Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux...
authorOlof Johansson <olof@lixom.net>
Thu, 29 Mar 2012 19:25:23 +0000 (12:25 -0700)
committerOlof Johansson <olof@lixom.net>
Thu, 29 Mar 2012 19:25:23 +0000 (12:25 -0700)
From Tony Lindgren:
"This contains the updated gpio_to_irq patches from Tarun, and a trivial
build fix from Govindraj to #include <asm/system_misc.h> in pm.c.
The DSI mux patch is the same."

* 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap:
  ARM: OMAP: pm: fix compilation break
  ARM: OMAP: Remove OMAP_GPIO_IRQ macro definition
  drivers: input: Fix OMAP_GPIO_IRQ with gpio_to_irq() in ams_delta_serio_exit()
  ARM: OMAP: boards: Fix OMAP_GPIO_IRQ usage with gpio_to_irq()
  ARM: OMAP2+: Remove __init from DSI mux functions

115 files changed:
Documentation/Makefile
Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt [new file with mode: 0644]
Documentation/vm/Makefile [deleted file]
Documentation/vm/hugepage-mmap.c [deleted file]
Documentation/vm/hugepage-shm.c [deleted file]
Documentation/vm/map_hugetlb.c [deleted file]
Documentation/vm/page-types.c [deleted file]
arch/arm/kernel/smp_tlb.c
arch/arm/mach-exynos/mach-nuri.c
arch/arm/mach-exynos/mach-universal_c210.c
arch/arm/mach-lpc32xx/clock.c
arch/arm/mach-omap2/hsmmc.c
arch/arm/mach-omap2/hsmmc.h
arch/arm/mach-tegra/board-dt-tegra20.c
arch/arm/mach-tegra/devices.c
arch/arm/mach-tegra/devices.h
arch/arm/plat-omap/include/plat/mmc.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/msi_ia64.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/smp.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/topology.c
arch/tile/include/asm/smp.h
arch/tile/kernel/smp.c
arch/x86/kernel/setup.c
drivers/block/nbd.c
drivers/char/ipmi/ipmi_kcs_sm.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ipmi/ipmi_watchdog.c
drivers/mmc/card/block.c
drivers/mmc/core/cd-gpio.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/host.h
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/dw_mmc-pci.c [new file with mode: 0644]
drivers/mmc/host/dw_mmc-pltfm.c [new file with mode: 0644]
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-spear.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_pio.c
drivers/video/backlight/tosa_lcd.c
fs/buffer.c
fs/exofs/super.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4proc.c
fs/proc/array.c
fs/proc/namespaces.c
fs/proc/task_mmu.c
fs/squashfs/block.c
fs/squashfs/dir.c
fs/squashfs/namei.c
fs/squashfs/squashfs_fs.h
fs/squashfs/super.c
include/linux/cpumask.h
include/linux/mfd/tmio.h
include/linux/mm.h
include/linux/mmc/card.h
include/linux/mmc/cd-gpio.h
include/linux/mmc/core.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/mmc/sdhci.h
include/linux/mmc/sh_mmcif.h
include/linux/mmc/sh_mobile_sdhi.h
include/linux/pid_namespace.h
include/linux/radix-tree.h
include/linux/smp.h
include/linux/swap.h
kernel/kexec.c
kernel/pid_namespace.c
kernel/smp.c
kernel/sys.c
kernel/sysctl.c
lib/Kconfig
lib/cpumask.c
lib/radix-tree.c
mm/filemap.c
mm/memcontrol.c
mm/page_alloc.c
mm/slub.c
mm/swapfile.c
mm/truncate.c
net/sunrpc/rpcb_clnt.c
tools/slub/slabinfo.c [deleted file]
tools/testing/selftests/Makefile
tools/testing/selftests/breakpoints/Makefile
tools/testing/selftests/run_tests [deleted file]
tools/testing/selftests/vm/Makefile [new file with mode: 0644]
tools/testing/selftests/vm/hugepage-mmap.c [new file with mode: 0644]
tools/testing/selftests/vm/hugepage-shm.c [new file with mode: 0644]
tools/testing/selftests/vm/map_hugetlb.c [new file with mode: 0644]
tools/testing/selftests/vm/run_vmtests [new file with mode: 0644]
tools/vm/Makefile [new file with mode: 0644]
tools/vm/page-types.c [new file with mode: 0644]
tools/vm/slabinfo.c [new file with mode: 0644]

index 9b4bc5c76f335341d568062d1f4034ec530458a7..30b656ece7aaed21076daa92d865ad472f607e22 100644 (file)
@@ -1,3 +1,3 @@
 obj-m := DocBook/ accounting/ auxdisplay/ connector/ \
        filesystems/ filesystems/configfs/ ia64/ laptops/ networking/ \
-       pcmcia/ spi/ timers/ vm/ watchdog/src/
+       pcmcia/ spi/ timers/ watchdog/src/
diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
new file mode 100644 (file)
index 0000000..dbd4368
--- /dev/null
@@ -0,0 +1,33 @@
+* TI Highspeed MMC host controller for OMAP
+
+The Highspeed MMC Host Controller on TI OMAP family
+provides an interface for MMC, SD, and SDIO types of memory cards.
+
+Required properties:
+- compatible:
+ Should be "ti,omap2-hsmmc", for OMAP2 controllers
+ Should be "ti,omap3-hsmmc", for OMAP3 controllers
+ Should be "ti,omap4-hsmmc", for OMAP4 controllers
+- ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
+- reg : should contain hsmmc registers location and length
+
+Optional properties:
+ti,dual-volt: boolean, supports dual voltage cards
+<supply-name>-supply: phandle to the regulator device tree node
+"supply-name" examples are "vmmc", "vmmc_aux" etc
+ti,bus-width: Number of data lines, default assumed is 1 if the property is missing.
+cd-gpios: GPIOs for card detection
+wp-gpios: GPIOs for write protection
+ti,non-removable: non-removable slot (like eMMC)
+ti,needs-special-reset: Requires a special softreset sequence
+
+Example:
+       mmc1: mmc@0x4809c000 {
+               compatible = "ti,omap4-hsmmc";
+               reg = <0x4809c000 0x400>;
+               ti,hwmods = "mmc1";
+               ti,dual-volt;
+               ti,bus-width = <4>;
+               vmmc-supply = <&vmmc>; /* phandle to regulator node */
+               ti,non-removable;
+       };
diff --git a/Documentation/vm/Makefile b/Documentation/vm/Makefile
deleted file mode 100644 (file)
index 3fa4d06..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# kbuild trick to avoid linker error. Can be omitted if a module is built.
-obj- := dummy.o
-
-# List of programs to build
-hostprogs-y := page-types hugepage-mmap hugepage-shm map_hugetlb
-
-# Tell kbuild to always build the programs
-always := $(hostprogs-y)
diff --git a/Documentation/vm/hugepage-mmap.c b/Documentation/vm/hugepage-mmap.c
deleted file mode 100644 (file)
index db0dd9a..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * hugepage-mmap:
- *
- * Example of using huge page memory in a user application using the mmap
- * system call.  Before running this application, make sure that the
- * administrator has mounted the hugetlbfs filesystem (on some directory
- * like /mnt) using the command mount -t hugetlbfs nodev /mnt. In this
- * example, the app is requesting memory of size 256MB that is backed by
- * huge pages.
- *
- * For the ia64 architecture, the Linux kernel reserves Region number 4 for
- * huge pages.  That means that if one requires a fixed address, a huge page
- * aligned address starting with 0x800000... will be required.  If a fixed
- * address is not required, the kernel will select an address in the proper
- * range.
- * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-
-#define FILE_NAME "/mnt/hugepagefile"
-#define LENGTH (256UL*1024*1024)
-#define PROTECTION (PROT_READ | PROT_WRITE)
-
-/* Only ia64 requires this */
-#ifdef __ia64__
-#define ADDR (void *)(0x8000000000000000UL)
-#define FLAGS (MAP_SHARED | MAP_FIXED)
-#else
-#define ADDR (void *)(0x0UL)
-#define FLAGS (MAP_SHARED)
-#endif
-
-static void check_bytes(char *addr)
-{
-       printf("First hex is %x\n", *((unsigned int *)addr));
-}
-
-static void write_bytes(char *addr)
-{
-       unsigned long i;
-
-       for (i = 0; i < LENGTH; i++)
-               *(addr + i) = (char)i;
-}
-
-static void read_bytes(char *addr)
-{
-       unsigned long i;
-
-       check_bytes(addr);
-       for (i = 0; i < LENGTH; i++)
-               if (*(addr + i) != (char)i) {
-                       printf("Mismatch at %lu\n", i);
-                       break;
-               }
-}
-
-int main(void)
-{
-       void *addr;
-       int fd;
-
-       fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
-       if (fd < 0) {
-               perror("Open failed");
-               exit(1);
-       }
-
-       addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, fd, 0);
-       if (addr == MAP_FAILED) {
-               perror("mmap");
-               unlink(FILE_NAME);
-               exit(1);
-       }
-
-       printf("Returned address is %p\n", addr);
-       check_bytes(addr);
-       write_bytes(addr);
-       read_bytes(addr);
-
-       munmap(addr, LENGTH);
-       close(fd);
-       unlink(FILE_NAME);
-
-       return 0;
-}
diff --git a/Documentation/vm/hugepage-shm.c b/Documentation/vm/hugepage-shm.c
deleted file mode 100644 (file)
index 07956d8..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * hugepage-shm:
- *
- * Example of using huge page memory in a user application using Sys V shared
- * memory system calls.  In this example the app is requesting 256MB of
- * memory that is backed by huge pages.  The application uses the flag
- * SHM_HUGETLB in the shmget system call to inform the kernel that it is
- * requesting huge pages.
- *
- * For the ia64 architecture, the Linux kernel reserves Region number 4 for
- * huge pages.  That means that if one requires a fixed address, a huge page
- * aligned address starting with 0x800000... will be required.  If a fixed
- * address is not required, the kernel will select an address in the proper
- * range.
- * Other architectures, such as ppc64, i386 or x86_64 are not so constrained.
- *
- * Note: The default shared memory limit is quite low on many kernels,
- * you may need to increase it via:
- *
- * echo 268435456 > /proc/sys/kernel/shmmax
- *
- * This will increase the maximum size per shared memory segment to 256MB.
- * The other limit that you will hit eventually is shmall which is the
- * total amount of shared memory in pages. To set it to 16GB on a system
- * with a 4kB pagesize do:
- *
- * echo 4194304 > /proc/sys/kernel/shmall
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/mman.h>
-
-#ifndef SHM_HUGETLB
-#define SHM_HUGETLB 04000
-#endif
-
-#define LENGTH (256UL*1024*1024)
-
-#define dprintf(x)  printf(x)
-
-/* Only ia64 requires this */
-#ifdef __ia64__
-#define ADDR (void *)(0x8000000000000000UL)
-#define SHMAT_FLAGS (SHM_RND)
-#else
-#define ADDR (void *)(0x0UL)
-#define SHMAT_FLAGS (0)
-#endif
-
-int main(void)
-{
-       int shmid;
-       unsigned long i;
-       char *shmaddr;
-
-       if ((shmid = shmget(2, LENGTH,
-                           SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W)) < 0) {
-               perror("shmget");
-               exit(1);
-       }
-       printf("shmid: 0x%x\n", shmid);
-
-       shmaddr = shmat(shmid, ADDR, SHMAT_FLAGS);
-       if (shmaddr == (char *)-1) {
-               perror("Shared memory attach failure");
-               shmctl(shmid, IPC_RMID, NULL);
-               exit(2);
-       }
-       printf("shmaddr: %p\n", shmaddr);
-
-       dprintf("Starting the writes:\n");
-       for (i = 0; i < LENGTH; i++) {
-               shmaddr[i] = (char)(i);
-               if (!(i % (1024 * 1024)))
-                       dprintf(".");
-       }
-       dprintf("\n");
-
-       dprintf("Starting the Check...");
-       for (i = 0; i < LENGTH; i++)
-               if (shmaddr[i] != (char)i)
-                       printf("\nIndex %lu mismatched\n", i);
-       dprintf("Done.\n");
-
-       if (shmdt((const void *)shmaddr) != 0) {
-               perror("Detach failure");
-               shmctl(shmid, IPC_RMID, NULL);
-               exit(3);
-       }
-
-       shmctl(shmid, IPC_RMID, NULL);
-
-       return 0;
-}
diff --git a/Documentation/vm/map_hugetlb.c b/Documentation/vm/map_hugetlb.c
deleted file mode 100644 (file)
index eda1a6d..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Example of using hugepage memory in a user application using the mmap
- * system call with MAP_HUGETLB flag.  Before running this program make
- * sure the administrator has allocated enough default sized huge pages
- * to cover the 256 MB allocation.
- *
- * For ia64 architecture, Linux kernel reserves Region number 4 for hugepages.
- * That means the addresses starting with 0x800000... will need to be
- * specified.  Specifying a fixed address is not required on ppc64, i386
- * or x86_64.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-
-#define LENGTH (256UL*1024*1024)
-#define PROTECTION (PROT_READ | PROT_WRITE)
-
-#ifndef MAP_HUGETLB
-#define MAP_HUGETLB 0x40000 /* arch specific */
-#endif
-
-/* Only ia64 requires this */
-#ifdef __ia64__
-#define ADDR (void *)(0x8000000000000000UL)
-#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED)
-#else
-#define ADDR (void *)(0x0UL)
-#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
-#endif
-
-static void check_bytes(char *addr)
-{
-       printf("First hex is %x\n", *((unsigned int *)addr));
-}
-
-static void write_bytes(char *addr)
-{
-       unsigned long i;
-
-       for (i = 0; i < LENGTH; i++)
-               *(addr + i) = (char)i;
-}
-
-static void read_bytes(char *addr)
-{
-       unsigned long i;
-
-       check_bytes(addr);
-       for (i = 0; i < LENGTH; i++)
-               if (*(addr + i) != (char)i) {
-                       printf("Mismatch at %lu\n", i);
-                       break;
-               }
-}
-
-int main(void)
-{
-       void *addr;
-
-       addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);
-       if (addr == MAP_FAILED) {
-               perror("mmap");
-               exit(1);
-       }
-
-       printf("Returned address is %p\n", addr);
-       check_bytes(addr);
-       write_bytes(addr);
-       read_bytes(addr);
-
-       munmap(addr, LENGTH);
-
-       return 0;
-}
diff --git a/Documentation/vm/page-types.c b/Documentation/vm/page-types.c
deleted file mode 100644 (file)
index 0b13f02..0000000
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*
- * page-types: Tool for querying page flags
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; version 2.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should find a copy of v2 of the GNU General Public License somewhere on
- * your Linux system; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * Copyright (C) 2009 Intel corporation
- *
- * Authors: Wu Fengguang <fengguang.wu@intel.com>
- */
-
-#define _LARGEFILE64_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <string.h>
-#include <getopt.h>
-#include <limits.h>
-#include <assert.h>
-#include <sys/types.h>
-#include <sys/errno.h>
-#include <sys/fcntl.h>
-#include <sys/mount.h>
-#include <sys/statfs.h>
-#include "../../include/linux/magic.h"
-
-
-#ifndef MAX_PATH
-# define MAX_PATH 256
-#endif
-
-#ifndef STR
-# define _STR(x) #x
-# define STR(x) _STR(x)
-#endif
-
-/*
- * pagemap kernel ABI bits
- */
-
-#define PM_ENTRY_BYTES      sizeof(uint64_t)
-#define PM_STATUS_BITS      3
-#define PM_STATUS_OFFSET    (64 - PM_STATUS_BITS)
-#define PM_STATUS_MASK      (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET)
-#define PM_STATUS(nr)       (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK)
-#define PM_PSHIFT_BITS      6
-#define PM_PSHIFT_OFFSET    (PM_STATUS_OFFSET - PM_PSHIFT_BITS)
-#define PM_PSHIFT_MASK      (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET)
-#define PM_PSHIFT(x)        (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK)
-#define PM_PFRAME_MASK      ((1LL << PM_PSHIFT_OFFSET) - 1)
-#define PM_PFRAME(x)        ((x) & PM_PFRAME_MASK)
-
-#define PM_PRESENT          PM_STATUS(4LL)
-#define PM_SWAP             PM_STATUS(2LL)
-
-
-/*
- * kernel page flags
- */
-
-#define KPF_BYTES              8
-#define PROC_KPAGEFLAGS                "/proc/kpageflags"
-
-/* copied from kpageflags_read() */
-#define KPF_LOCKED             0
-#define KPF_ERROR              1
-#define KPF_REFERENCED         2
-#define KPF_UPTODATE           3
-#define KPF_DIRTY              4
-#define KPF_LRU                        5
-#define KPF_ACTIVE             6
-#define KPF_SLAB               7
-#define KPF_WRITEBACK          8
-#define KPF_RECLAIM            9
-#define KPF_BUDDY              10
-
-/* [11-20] new additions in 2.6.31 */
-#define KPF_MMAP               11
-#define KPF_ANON               12
-#define KPF_SWAPCACHE          13
-#define KPF_SWAPBACKED         14
-#define KPF_COMPOUND_HEAD      15
-#define KPF_COMPOUND_TAIL      16
-#define KPF_HUGE               17
-#define KPF_UNEVICTABLE                18
-#define KPF_HWPOISON           19
-#define KPF_NOPAGE             20
-#define KPF_KSM                        21
-#define KPF_THP                        22
-
-/* [32-] kernel hacking assistances */
-#define KPF_RESERVED           32
-#define KPF_MLOCKED            33
-#define KPF_MAPPEDTODISK       34
-#define KPF_PRIVATE            35
-#define KPF_PRIVATE_2          36
-#define KPF_OWNER_PRIVATE      37
-#define KPF_ARCH               38
-#define KPF_UNCACHED           39
-
-/* [48-] take some arbitrary free slots for expanding overloaded flags
- * not part of kernel API
- */
-#define KPF_READAHEAD          48
-#define KPF_SLOB_FREE          49
-#define KPF_SLUB_FROZEN                50
-#define KPF_SLUB_DEBUG         51
-
-#define KPF_ALL_BITS           ((uint64_t)~0ULL)
-#define KPF_HACKERS_BITS       (0xffffULL << 32)
-#define KPF_OVERLOADED_BITS    (0xffffULL << 48)
-#define BIT(name)              (1ULL << KPF_##name)
-#define BITS_COMPOUND          (BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL))
-
-static const char *page_flag_names[] = {
-       [KPF_LOCKED]            = "L:locked",
-       [KPF_ERROR]             = "E:error",
-       [KPF_REFERENCED]        = "R:referenced",
-       [KPF_UPTODATE]          = "U:uptodate",
-       [KPF_DIRTY]             = "D:dirty",
-       [KPF_LRU]               = "l:lru",
-       [KPF_ACTIVE]            = "A:active",
-       [KPF_SLAB]              = "S:slab",
-       [KPF_WRITEBACK]         = "W:writeback",
-       [KPF_RECLAIM]           = "I:reclaim",
-       [KPF_BUDDY]             = "B:buddy",
-
-       [KPF_MMAP]              = "M:mmap",
-       [KPF_ANON]              = "a:anonymous",
-       [KPF_SWAPCACHE]         = "s:swapcache",
-       [KPF_SWAPBACKED]        = "b:swapbacked",
-       [KPF_COMPOUND_HEAD]     = "H:compound_head",
-       [KPF_COMPOUND_TAIL]     = "T:compound_tail",
-       [KPF_HUGE]              = "G:huge",
-       [KPF_UNEVICTABLE]       = "u:unevictable",
-       [KPF_HWPOISON]          = "X:hwpoison",
-       [KPF_NOPAGE]            = "n:nopage",
-       [KPF_KSM]               = "x:ksm",
-       [KPF_THP]               = "t:thp",
-
-       [KPF_RESERVED]          = "r:reserved",
-       [KPF_MLOCKED]           = "m:mlocked",
-       [KPF_MAPPEDTODISK]      = "d:mappedtodisk",
-       [KPF_PRIVATE]           = "P:private",
-       [KPF_PRIVATE_2]         = "p:private_2",
-       [KPF_OWNER_PRIVATE]     = "O:owner_private",
-       [KPF_ARCH]              = "h:arch",
-       [KPF_UNCACHED]          = "c:uncached",
-
-       [KPF_READAHEAD]         = "I:readahead",
-       [KPF_SLOB_FREE]         = "P:slob_free",
-       [KPF_SLUB_FROZEN]       = "A:slub_frozen",
-       [KPF_SLUB_DEBUG]        = "E:slub_debug",
-};
-
-
-static const char *debugfs_known_mountpoints[] = {
-       "/sys/kernel/debug",
-       "/debug",
-       0,
-};
-
-/*
- * data structures
- */
-
-static int             opt_raw;        /* for kernel developers */
-static int             opt_list;       /* list pages (in ranges) */
-static int             opt_no_summary; /* don't show summary */
-static pid_t           opt_pid;        /* process to walk */
-
-#define MAX_ADDR_RANGES        1024
-static int             nr_addr_ranges;
-static unsigned long   opt_offset[MAX_ADDR_RANGES];
-static unsigned long   opt_size[MAX_ADDR_RANGES];
-
-#define MAX_VMAS       10240
-static int             nr_vmas;
-static unsigned long   pg_start[MAX_VMAS];
-static unsigned long   pg_end[MAX_VMAS];
-
-#define MAX_BIT_FILTERS        64
-static int             nr_bit_filters;
-static uint64_t                opt_mask[MAX_BIT_FILTERS];
-static uint64_t                opt_bits[MAX_BIT_FILTERS];
-
-static int             page_size;
-
-static int             pagemap_fd;
-static int             kpageflags_fd;
-
-static int             opt_hwpoison;
-static int             opt_unpoison;
-
-static char            hwpoison_debug_fs[MAX_PATH+1];
-static int             hwpoison_inject_fd;
-static int             hwpoison_forget_fd;
-
-#define HASH_SHIFT     13
-#define HASH_SIZE      (1 << HASH_SHIFT)
-#define HASH_MASK      (HASH_SIZE - 1)
-#define HASH_KEY(flags)        (flags & HASH_MASK)
-
-static unsigned long   total_pages;
-static unsigned long   nr_pages[HASH_SIZE];
-static uint64_t        page_flags[HASH_SIZE];
-
-
-/*
- * helper functions
- */
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-#define min_t(type, x, y) ({                   \
-       type __min1 = (x);                      \
-       type __min2 = (y);                      \
-       __min1 < __min2 ? __min1 : __min2; })
-
-#define max_t(type, x, y) ({                   \
-       type __max1 = (x);                      \
-       type __max2 = (y);                      \
-       __max1 > __max2 ? __max1 : __max2; })
-
-static unsigned long pages2mb(unsigned long pages)
-{
-       return (pages * page_size) >> 20;
-}
-
-static void fatal(const char *x, ...)
-{
-       va_list ap;
-
-       va_start(ap, x);
-       vfprintf(stderr, x, ap);
-       va_end(ap);
-       exit(EXIT_FAILURE);
-}
-
-static int checked_open(const char *pathname, int flags)
-{
-       int fd = open(pathname, flags);
-
-       if (fd < 0) {
-               perror(pathname);
-               exit(EXIT_FAILURE);
-       }
-
-       return fd;
-}
-
-/*
- * pagemap/kpageflags routines
- */
-
-static unsigned long do_u64_read(int fd, char *name,
-                                uint64_t *buf,
-                                unsigned long index,
-                                unsigned long count)
-{
-       long bytes;
-
-       if (index > ULONG_MAX / 8)
-               fatal("index overflow: %lu\n", index);
-
-       if (lseek(fd, index * 8, SEEK_SET) < 0) {
-               perror(name);
-               exit(EXIT_FAILURE);
-       }
-
-       bytes = read(fd, buf, count * 8);
-       if (bytes < 0) {
-               perror(name);
-               exit(EXIT_FAILURE);
-       }
-       if (bytes % 8)
-               fatal("partial read: %lu bytes\n", bytes);
-
-       return bytes / 8;
-}
-
-static unsigned long kpageflags_read(uint64_t *buf,
-                                    unsigned long index,
-                                    unsigned long pages)
-{
-       return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages);
-}
-
-static unsigned long pagemap_read(uint64_t *buf,
-                                 unsigned long index,
-                                 unsigned long pages)
-{
-       return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages);
-}
-
-static unsigned long pagemap_pfn(uint64_t val)
-{
-       unsigned long pfn;
-
-       if (val & PM_PRESENT)
-               pfn = PM_PFRAME(val);
-       else
-               pfn = 0;
-
-       return pfn;
-}
-
-
-/*
- * page flag names
- */
-
-static char *page_flag_name(uint64_t flags)
-{
-       static char buf[65];
-       int present;
-       int i, j;
-
-       for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
-               present = (flags >> i) & 1;
-               if (!page_flag_names[i]) {
-                       if (present)
-                               fatal("unknown flag bit %d\n", i);
-                       continue;
-               }
-               buf[j++] = present ? page_flag_names[i][0] : '_';
-       }
-
-       return buf;
-}
-
-static char *page_flag_longname(uint64_t flags)
-{
-       static char buf[1024];
-       int i, n;
-
-       for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) {
-               if (!page_flag_names[i])
-                       continue;
-               if ((flags >> i) & 1)
-                       n += snprintf(buf + n, sizeof(buf) - n, "%s,",
-                                       page_flag_names[i] + 2);
-       }
-       if (n)
-               n--;
-       buf[n] = '\0';
-
-       return buf;
-}
-
-
-/*
- * page list and summary
- */
-
-static void show_page_range(unsigned long voffset,
-                           unsigned long offset, uint64_t flags)
-{
-       static uint64_t      flags0;
-       static unsigned long voff;
-       static unsigned long index;
-       static unsigned long count;
-
-       if (flags == flags0 && offset == index + count &&
-           (!opt_pid || voffset == voff + count)) {
-               count++;
-               return;
-       }
-
-       if (count) {
-               if (opt_pid)
-                       printf("%lx\t", voff);
-               printf("%lx\t%lx\t%s\n",
-                               index, count, page_flag_name(flags0));
-       }
-
-       flags0 = flags;
-       index  = offset;
-       voff   = voffset;
-       count  = 1;
-}
-
-static void show_page(unsigned long voffset,
-                     unsigned long offset, uint64_t flags)
-{
-       if (opt_pid)
-               printf("%lx\t", voffset);
-       printf("%lx\t%s\n", offset, page_flag_name(flags));
-}
-
-static void show_summary(void)
-{
-       int i;
-
-       printf("             flags\tpage-count       MB"
-               "  symbolic-flags\t\t\tlong-symbolic-flags\n");
-
-       for (i = 0; i < ARRAY_SIZE(nr_pages); i++) {
-               if (nr_pages[i])
-                       printf("0x%016llx\t%10lu %8lu  %s\t%s\n",
-                               (unsigned long long)page_flags[i],
-                               nr_pages[i],
-                               pages2mb(nr_pages[i]),
-                               page_flag_name(page_flags[i]),
-                               page_flag_longname(page_flags[i]));
-       }
-
-       printf("             total\t%10lu %8lu\n",
-                       total_pages, pages2mb(total_pages));
-}
-
-
-/*
- * page flag filters
- */
-
-static int bit_mask_ok(uint64_t flags)
-{
-       int i;
-
-       for (i = 0; i < nr_bit_filters; i++) {
-               if (opt_bits[i] == KPF_ALL_BITS) {
-                       if ((flags & opt_mask[i]) == 0)
-                               return 0;
-               } else {
-                       if ((flags & opt_mask[i]) != opt_bits[i])
-                               return 0;
-               }
-       }
-
-       return 1;
-}
-
-static uint64_t expand_overloaded_flags(uint64_t flags)
-{
-       /* SLOB/SLUB overload several page flags */
-       if (flags & BIT(SLAB)) {
-               if (flags & BIT(PRIVATE))
-                       flags ^= BIT(PRIVATE) | BIT(SLOB_FREE);
-               if (flags & BIT(ACTIVE))
-                       flags ^= BIT(ACTIVE) | BIT(SLUB_FROZEN);
-               if (flags & BIT(ERROR))
-                       flags ^= BIT(ERROR) | BIT(SLUB_DEBUG);
-       }
-
-       /* PG_reclaim is overloaded as PG_readahead in the read path */
-       if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM))
-               flags ^= BIT(RECLAIM) | BIT(READAHEAD);
-
-       return flags;
-}
-
-static uint64_t well_known_flags(uint64_t flags)
-{
-       /* hide flags intended only for kernel hacker */
-       flags &= ~KPF_HACKERS_BITS;
-
-       /* hide non-hugeTLB compound pages */
-       if ((flags & BITS_COMPOUND) && !(flags & BIT(HUGE)))
-               flags &= ~BITS_COMPOUND;
-
-       return flags;
-}
-
-static uint64_t kpageflags_flags(uint64_t flags)
-{
-       flags = expand_overloaded_flags(flags);
-
-       if (!opt_raw)
-               flags = well_known_flags(flags);
-
-       return flags;
-}
-
-/* verify that a mountpoint is actually a debugfs instance */
-static int debugfs_valid_mountpoint(const char *debugfs)
-{
-       struct statfs st_fs;
-
-       if (statfs(debugfs, &st_fs) < 0)
-               return -ENOENT;
-       else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
-               return -ENOENT;
-
-       return 0;
-}
-
-/* find the path to the mounted debugfs */
-static const char *debugfs_find_mountpoint(void)
-{
-       const char **ptr;
-       char type[100];
-       FILE *fp;
-
-       ptr = debugfs_known_mountpoints;
-       while (*ptr) {
-               if (debugfs_valid_mountpoint(*ptr) == 0) {
-                       strcpy(hwpoison_debug_fs, *ptr);
-                       return hwpoison_debug_fs;
-               }
-               ptr++;
-       }
-
-       /* give up and parse /proc/mounts */
-       fp = fopen("/proc/mounts", "r");
-       if (fp == NULL)
-               perror("Can't open /proc/mounts for read");
-
-       while (fscanf(fp, "%*s %"
-                     STR(MAX_PATH)
-                     "s %99s %*s %*d %*d\n",
-                     hwpoison_debug_fs, type) == 2) {
-               if (strcmp(type, "debugfs") == 0)
-                       break;
-       }
-       fclose(fp);
-
-       if (strcmp(type, "debugfs") != 0)
-               return NULL;
-
-       return hwpoison_debug_fs;
-}
-
-/* mount the debugfs somewhere if it's not mounted */
-
-static void debugfs_mount(void)
-{
-       const char **ptr;
-
-       /* see if it's already mounted */
-       if (debugfs_find_mountpoint())
-               return;
-
-       ptr = debugfs_known_mountpoints;
-       while (*ptr) {
-               if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) {
-                       /* save the mountpoint */
-                       strcpy(hwpoison_debug_fs, *ptr);
-                       break;
-               }
-               ptr++;
-       }
-
-       if (*ptr == NULL) {
-               perror("mount debugfs");
-               exit(EXIT_FAILURE);
-       }
-}
-
-/*
- * page actions
- */
-
-static void prepare_hwpoison_fd(void)
-{
-       char buf[MAX_PATH + 1];
-
-       debugfs_mount();
-
-       if (opt_hwpoison && !hwpoison_inject_fd) {
-               snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn",
-                       hwpoison_debug_fs);
-               hwpoison_inject_fd = checked_open(buf, O_WRONLY);
-       }
-
-       if (opt_unpoison && !hwpoison_forget_fd) {
-               snprintf(buf, MAX_PATH, "%s/hwpoison/unpoison-pfn",
-                       hwpoison_debug_fs);
-               hwpoison_forget_fd = checked_open(buf, O_WRONLY);
-       }
-}
-
-static int hwpoison_page(unsigned long offset)
-{
-       char buf[100];
-       int len;
-
-       len = sprintf(buf, "0x%lx\n", offset);
-       len = write(hwpoison_inject_fd, buf, len);
-       if (len < 0) {
-               perror("hwpoison inject");
-               return len;
-       }
-       return 0;
-}
-
-static int unpoison_page(unsigned long offset)
-{
-       char buf[100];
-       int len;
-
-       len = sprintf(buf, "0x%lx\n", offset);
-       len = write(hwpoison_forget_fd, buf, len);
-       if (len < 0) {
-               perror("hwpoison forget");
-               return len;
-       }
-       return 0;
-}
-
-/*
- * page frame walker
- */
-
-static int hash_slot(uint64_t flags)
-{
-       int k = HASH_KEY(flags);
-       int i;
-
-       /* Explicitly reserve slot 0 for flags 0: the following logic
-        * cannot distinguish an unoccupied slot from slot (flags==0).
-        */
-       if (flags == 0)
-               return 0;
-
-       /* search through the remaining (HASH_SIZE-1) slots */
-       for (i = 1; i < ARRAY_SIZE(page_flags); i++, k++) {
-               if (!k || k >= ARRAY_SIZE(page_flags))
-                       k = 1;
-               if (page_flags[k] == 0) {
-                       page_flags[k] = flags;
-                       return k;
-               }
-               if (page_flags[k] == flags)
-                       return k;
-       }
-
-       fatal("hash table full: bump up HASH_SHIFT?\n");
-       exit(EXIT_FAILURE);
-}
-
-static void add_page(unsigned long voffset,
-                    unsigned long offset, uint64_t flags)
-{
-       flags = kpageflags_flags(flags);
-
-       if (!bit_mask_ok(flags))
-               return;
-
-       if (opt_hwpoison)
-               hwpoison_page(offset);
-       if (opt_unpoison)
-               unpoison_page(offset);
-
-       if (opt_list == 1)
-               show_page_range(voffset, offset, flags);
-       else if (opt_list == 2)
-               show_page(voffset, offset, flags);
-
-       nr_pages[hash_slot(flags)]++;
-       total_pages++;
-}
-
-#define KPAGEFLAGS_BATCH       (64 << 10)      /* 64k pages */
-static void walk_pfn(unsigned long voffset,
-                    unsigned long index,
-                    unsigned long count)
-{
-       uint64_t buf[KPAGEFLAGS_BATCH];
-       unsigned long batch;
-       long pages;
-       unsigned long i;
-
-       while (count) {
-               batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH);
-               pages = kpageflags_read(buf, index, batch);
-               if (pages == 0)
-                       break;
-
-               for (i = 0; i < pages; i++)
-                       add_page(voffset + i, index + i, buf[i]);
-
-               index += pages;
-               count -= pages;
-       }
-}
-
-#define PAGEMAP_BATCH  (64 << 10)
-static void walk_vma(unsigned long index, unsigned long count)
-{
-       uint64_t buf[PAGEMAP_BATCH];
-       unsigned long batch;
-       unsigned long pages;
-       unsigned long pfn;
-       unsigned long i;
-
-       while (count) {
-               batch = min_t(unsigned long, count, PAGEMAP_BATCH);
-               pages = pagemap_read(buf, index, batch);
-               if (pages == 0)
-                       break;
-
-               for (i = 0; i < pages; i++) {
-                       pfn = pagemap_pfn(buf[i]);
-                       if (pfn)
-                               walk_pfn(index + i, pfn, 1);
-               }
-
-               index += pages;
-               count -= pages;
-       }
-}
-
-static void walk_task(unsigned long index, unsigned long count)
-{
-       const unsigned long end = index + count;
-       unsigned long start;
-       int i = 0;
-
-       while (index < end) {
-
-               while (pg_end[i] <= index)
-                       if (++i >= nr_vmas)
-                               return;
-               if (pg_start[i] >= end)
-                       return;
-
-               start = max_t(unsigned long, pg_start[i], index);
-               index = min_t(unsigned long, pg_end[i], end);
-
-               assert(start < index);
-               walk_vma(start, index - start);
-       }
-}
-
-static void add_addr_range(unsigned long offset, unsigned long size)
-{
-       if (nr_addr_ranges >= MAX_ADDR_RANGES)
-               fatal("too many addr ranges\n");
-
-       opt_offset[nr_addr_ranges] = offset;
-       opt_size[nr_addr_ranges] = min_t(unsigned long, size, ULONG_MAX-offset);
-       nr_addr_ranges++;
-}
-
-static void walk_addr_ranges(void)
-{
-       int i;
-
-       kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY);
-
-       if (!nr_addr_ranges)
-               add_addr_range(0, ULONG_MAX);
-
-       for (i = 0; i < nr_addr_ranges; i++)
-               if (!opt_pid)
-                       walk_pfn(0, opt_offset[i], opt_size[i]);
-               else
-                       walk_task(opt_offset[i], opt_size[i]);
-
-       close(kpageflags_fd);
-}
-
-
-/*
- * user interface
- */
-
-static const char *page_flag_type(uint64_t flag)
-{
-       if (flag & KPF_HACKERS_BITS)
-               return "(r)";
-       if (flag & KPF_OVERLOADED_BITS)
-               return "(o)";
-       return "   ";
-}
-
-static void usage(void)
-{
-       int i, j;
-
-       printf(
-"page-types [options]\n"
-"            -r|--raw                   Raw mode, for kernel developers\n"
-"            -d|--describe flags        Describe flags\n"
-"            -a|--addr    addr-spec     Walk a range of pages\n"
-"            -b|--bits    bits-spec     Walk pages with specified bits\n"
-"            -p|--pid     pid           Walk process address space\n"
-#if 0 /* planned features */
-"            -f|--file    filename      Walk file address space\n"
-#endif
-"            -l|--list                  Show page details in ranges\n"
-"            -L|--list-each             Show page details one by one\n"
-"            -N|--no-summary            Don't show summary info\n"
-"            -X|--hwpoison              hwpoison pages\n"
-"            -x|--unpoison              unpoison pages\n"
-"            -h|--help                  Show this usage message\n"
-"flags:\n"
-"            0x10                       bitfield format, e.g.\n"
-"            anon                       bit-name, e.g.\n"
-"            0x10,anon                  comma-separated list, e.g.\n"
-"addr-spec:\n"
-"            N                          one page at offset N (unit: pages)\n"
-"            N+M                        pages range from N to N+M-1\n"
-"            N,M                        pages range from N to M-1\n"
-"            N,                         pages range from N to end\n"
-"            ,M                         pages range from 0 to M-1\n"
-"bits-spec:\n"
-"            bit1,bit2                  (flags & (bit1|bit2)) != 0\n"
-"            bit1,bit2=bit1             (flags & (bit1|bit2)) == bit1\n"
-"            bit1,~bit2                 (flags & (bit1|bit2)) == bit1\n"
-"            =bit1,bit2                 flags == (bit1|bit2)\n"
-"bit-names:\n"
-       );
-
-       for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
-               if (!page_flag_names[i])
-                       continue;
-               printf("%16s%s", page_flag_names[i] + 2,
-                                page_flag_type(1ULL << i));
-               if (++j > 3) {
-                       j = 0;
-                       putchar('\n');
-               }
-       }
-       printf("\n                                   "
-               "(r) raw mode bits  (o) overloaded bits\n");
-}
-
-static unsigned long long parse_number(const char *str)
-{
-       unsigned long long n;
-
-       n = strtoll(str, NULL, 0);
-
-       if (n == 0 && str[0] != '0')
-               fatal("invalid name or number: %s\n", str);
-
-       return n;
-}
-
-static void parse_pid(const char *str)
-{
-       FILE *file;
-       char buf[5000];
-
-       opt_pid = parse_number(str);
-
-       sprintf(buf, "/proc/%d/pagemap", opt_pid);
-       pagemap_fd = checked_open(buf, O_RDONLY);
-
-       sprintf(buf, "/proc/%d/maps", opt_pid);
-       file = fopen(buf, "r");
-       if (!file) {
-               perror(buf);
-               exit(EXIT_FAILURE);
-       }
-
-       while (fgets(buf, sizeof(buf), file) != NULL) {
-               unsigned long vm_start;
-               unsigned long vm_end;
-               unsigned long long pgoff;
-               int major, minor;
-               char r, w, x, s;
-               unsigned long ino;
-               int n;
-
-               n = sscanf(buf, "%lx-%lx %c%c%c%c %llx %x:%x %lu",
-                          &vm_start,
-                          &vm_end,
-                          &r, &w, &x, &s,
-                          &pgoff,
-                          &major, &minor,
-                          &ino);
-               if (n < 10) {
-                       fprintf(stderr, "unexpected line: %s\n", buf);
-                       continue;
-               }
-               pg_start[nr_vmas] = vm_start / page_size;
-               pg_end[nr_vmas] = vm_end / page_size;
-               if (++nr_vmas >= MAX_VMAS) {
-                       fprintf(stderr, "too many VMAs\n");
-                       break;
-               }
-       }
-       fclose(file);
-}
-
-static void parse_file(const char *name)
-{
-}
-
-static void parse_addr_range(const char *optarg)
-{
-       unsigned long offset;
-       unsigned long size;
-       char *p;
-
-       p = strchr(optarg, ',');
-       if (!p)
-               p = strchr(optarg, '+');
-
-       if (p == optarg) {
-               offset = 0;
-               size   = parse_number(p + 1);
-       } else if (p) {
-               offset = parse_number(optarg);
-               if (p[1] == '\0')
-                       size = ULONG_MAX;
-               else {
-                       size = parse_number(p + 1);
-                       if (*p == ',') {
-                               if (size < offset)
-                                       fatal("invalid range: %lu,%lu\n",
-                                                       offset, size);
-                               size -= offset;
-                       }
-               }
-       } else {
-               offset = parse_number(optarg);
-               size   = 1;
-       }
-
-       add_addr_range(offset, size);
-}
-
-static void add_bits_filter(uint64_t mask, uint64_t bits)
-{
-       if (nr_bit_filters >= MAX_BIT_FILTERS)
-               fatal("too much bit filters\n");
-
-       opt_mask[nr_bit_filters] = mask;
-       opt_bits[nr_bit_filters] = bits;
-       nr_bit_filters++;
-}
-
-static uint64_t parse_flag_name(const char *str, int len)
-{
-       int i;
-
-       if (!*str || !len)
-               return 0;
-
-       if (len <= 8 && !strncmp(str, "compound", len))
-               return BITS_COMPOUND;
-
-       for (i = 0; i < ARRAY_SIZE(page_flag_names); i++) {
-               if (!page_flag_names[i])
-                       continue;
-               if (!strncmp(str, page_flag_names[i] + 2, len))
-                       return 1ULL << i;
-       }
-
-       return parse_number(str);
-}
-
-static uint64_t parse_flag_names(const char *str, int all)
-{
-       const char *p    = str;
-       uint64_t   flags = 0;
-
-       while (1) {
-               if (*p == ',' || *p == '=' || *p == '\0') {
-                       if ((*str != '~') || (*str == '~' && all && *++str))
-                               flags |= parse_flag_name(str, p - str);
-                       if (*p != ',')
-                               break;
-                       str = p + 1;
-               }
-               p++;
-       }
-
-       return flags;
-}
-
-static void parse_bits_mask(const char *optarg)
-{
-       uint64_t mask;
-       uint64_t bits;
-       const char *p;
-
-       p = strchr(optarg, '=');
-       if (p == optarg) {
-               mask = KPF_ALL_BITS;
-               bits = parse_flag_names(p + 1, 0);
-       } else if (p) {
-               mask = parse_flag_names(optarg, 0);
-               bits = parse_flag_names(p + 1, 0);
-       } else if (strchr(optarg, '~')) {
-               mask = parse_flag_names(optarg, 1);
-               bits = parse_flag_names(optarg, 0);
-       } else {
-               mask = parse_flag_names(optarg, 0);
-               bits = KPF_ALL_BITS;
-       }
-
-       add_bits_filter(mask, bits);
-}
-
-static void describe_flags(const char *optarg)
-{
-       uint64_t flags = parse_flag_names(optarg, 0);
-
-       printf("0x%016llx\t%s\t%s\n",
-               (unsigned long long)flags,
-               page_flag_name(flags),
-               page_flag_longname(flags));
-}
-
-static const struct option opts[] = {
-       { "raw"       , 0, NULL, 'r' },
-       { "pid"       , 1, NULL, 'p' },
-       { "file"      , 1, NULL, 'f' },
-       { "addr"      , 1, NULL, 'a' },
-       { "bits"      , 1, NULL, 'b' },
-       { "describe"  , 1, NULL, 'd' },
-       { "list"      , 0, NULL, 'l' },
-       { "list-each" , 0, NULL, 'L' },
-       { "no-summary", 0, NULL, 'N' },
-       { "hwpoison"  , 0, NULL, 'X' },
-       { "unpoison"  , 0, NULL, 'x' },
-       { "help"      , 0, NULL, 'h' },
-       { NULL        , 0, NULL, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       int c;
-
-       page_size = getpagesize();
-
-       while ((c = getopt_long(argc, argv,
-                               "rp:f:a:b:d:lLNXxh", opts, NULL)) != -1) {
-               switch (c) {
-               case 'r':
-                       opt_raw = 1;
-                       break;
-               case 'p':
-                       parse_pid(optarg);
-                       break;
-               case 'f':
-                       parse_file(optarg);
-                       break;
-               case 'a':
-                       parse_addr_range(optarg);
-                       break;
-               case 'b':
-                       parse_bits_mask(optarg);
-                       break;
-               case 'd':
-                       describe_flags(optarg);
-                       exit(0);
-               case 'l':
-                       opt_list = 1;
-                       break;
-               case 'L':
-                       opt_list = 2;
-                       break;
-               case 'N':
-                       opt_no_summary = 1;
-                       break;
-               case 'X':
-                       opt_hwpoison = 1;
-                       prepare_hwpoison_fd();
-                       break;
-               case 'x':
-                       opt_unpoison = 1;
-                       prepare_hwpoison_fd();
-                       break;
-               case 'h':
-                       usage();
-                       exit(0);
-               default:
-                       usage();
-                       exit(1);
-               }
-       }
-
-       if (opt_list && opt_pid)
-               printf("voffset\t");
-       if (opt_list == 1)
-               printf("offset\tlen\tflags\n");
-       if (opt_list == 2)
-               printf("offset\tflags\n");
-
-       walk_addr_ranges();
-
-       if (opt_list == 1)
-               show_page_range(0, 0, 0);  /* drain the buffer */
-
-       if (opt_no_summary)
-               return 0;
-
-       if (opt_list)
-               printf("\n\n");
-
-       show_summary();
-
-       return 0;
-}
index 7dcb35285be7bd0d805c303f3dfc64d2ef74ebfb..02c5d2ce23bf121f17479bba2b52460419481930 100644 (file)
 #include <asm/smp_plat.h>
 #include <asm/tlbflush.h>
 
-static void on_each_cpu_mask(void (*func)(void *), void *info, int wait,
-       const struct cpumask *mask)
-{
-       preempt_disable();
-
-       smp_call_function_many(mask, func, info, wait);
-       if (cpumask_test_cpu(smp_processor_id(), mask))
-               func(info);
-
-       preempt_enable();
-}
-
 /**********************************************************************/
 
 /*
@@ -87,7 +75,7 @@ void flush_tlb_all(void)
 void flush_tlb_mm(struct mm_struct *mm)
 {
        if (tlb_ops_need_broadcast())
-               on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, mm_cpumask(mm));
+               on_each_cpu_mask(mm_cpumask(mm), ipi_flush_tlb_mm, mm, 1);
        else
                local_flush_tlb_mm(mm);
 }
@@ -98,7 +86,8 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
                struct tlb_args ta;
                ta.ta_vma = vma;
                ta.ta_start = uaddr;
-               on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, mm_cpumask(vma->vm_mm));
+               on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_page,
+                                       &ta, 1);
        } else
                local_flush_tlb_page(vma, uaddr);
 }
@@ -121,7 +110,8 @@ void flush_tlb_range(struct vm_area_struct *vma,
                ta.ta_vma = vma;
                ta.ta_start = start;
                ta.ta_end = end;
-               on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, mm_cpumask(vma->vm_mm));
+               on_each_cpu_mask(mm_cpumask(vma->vm_mm), ipi_flush_tlb_range,
+                                       &ta, 1);
        } else
                local_flush_tlb_range(vma, start, end);
 }
index 82ea6fccfb3450e54487b24ead9e12c2af589e9b..b3982c867c9c5e9243c505d41b9914b69c130b30 100644 (file)
@@ -111,7 +111,7 @@ static struct s3c_sdhci_platdata nuri_hsmmc0_data __initdata = {
        .max_width              = 8,
        .host_caps              = (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA |
                                MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-                               MMC_CAP_DISABLE | MMC_CAP_ERASE),
+                               MMC_CAP_ERASE),
        .cd_type                = S3C_SDHCI_CD_PERMANENT,
        .clk_type               = S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
@@ -150,8 +150,7 @@ static struct platform_device emmc_fixed_voltage = {
 static struct s3c_sdhci_platdata nuri_hsmmc2_data __initdata = {
        .max_width              = 4,
        .host_caps              = MMC_CAP_4_BIT_DATA |
-                               MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-                               MMC_CAP_DISABLE,
+                               MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
        .ext_cd_gpio            = EXYNOS4_GPX3(3),      /* XEINT_27 */
        .ext_cd_gpio_invert     = 1,
        .cd_type                = S3C_SDHCI_CD_GPIO,
index 28658da9f4230e8d17c000e4fec5ca696fb39373..6bb9dbdd73fdde842bcad0cb75f4713316c4a760 100644 (file)
@@ -745,8 +745,7 @@ static struct platform_device universal_gpio_keys = {
 static struct s3c_sdhci_platdata universal_hsmmc0_data __initdata = {
        .max_width              = 8,
        .host_caps              = (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA |
-                               MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-                               MMC_CAP_DISABLE),
+                               MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
        .cd_type                = S3C_SDHCI_CD_PERMANENT,
        .clk_type               = S3C_SDHCI_CLK_DIV_EXTERNAL,
 };
@@ -784,8 +783,7 @@ static struct platform_device mmc0_fixed_voltage = {
 static struct s3c_sdhci_platdata universal_hsmmc2_data __initdata = {
        .max_width              = 4,
        .host_caps              = MMC_CAP_4_BIT_DATA |
-                               MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-                               MMC_CAP_DISABLE,
+                               MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
        .ext_cd_gpio            = EXYNOS4_GPX3(4),      /* XEINT_28 */
        .ext_cd_gpio_invert     = 1,
        .cd_type                = S3C_SDHCI_CD_GPIO,
@@ -796,8 +794,7 @@ static struct s3c_sdhci_platdata universal_hsmmc2_data __initdata = {
 static struct s3c_sdhci_platdata universal_hsmmc3_data __initdata = {
        .max_width              = 4,
        .host_caps              = MMC_CAP_4_BIT_DATA |
-                               MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-                               MMC_CAP_DISABLE,
+                               MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
        .cd_type                = S3C_SDHCI_CD_EXTERNAL,
 };
 
index b7ef51119d37580839f9773431f69c4282bdbae0..2fc24ca12054dae290b8c3b34077699225883370 100644 (file)
@@ -1134,7 +1134,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "i2s1_ck", clk_i2s1)
        _REGISTER_CLOCK("ts-lpc32xx", NULL, clk_tsc)
        _REGISTER_CLOCK("dev:mmc0", NULL, clk_mmc)
-       _REGISTER_CLOCK("lpc-net.0", NULL, clk_net)
+       _REGISTER_CLOCK("lpc-eth.0", NULL, clk_net)
        _REGISTER_CLOCK("dev:clcd", NULL, clk_lcd)
        _REGISTER_CLOCK("lpc32xx_udc", "ck_usbd", clk_usbd)
        _REGISTER_CLOCK("lpc32xx_rtc", NULL, clk_rtc)
index 8121720e942ffdb10d14cd6fdde29aa691f7446e..100db6217f39984428ba49df988df65c2307f936 100644 (file)
@@ -316,6 +316,7 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
        mmc->slots[0].pm_caps = c->pm_caps;
        mmc->slots[0].internal_clock = !c->ext_clock;
        mmc->dma_mask = 0xffffffff;
+       mmc->max_freq = c->max_freq;
        if (cpu_is_omap44xx())
                mmc->reg_offset = OMAP4_MMC_REG_OFFSET;
        else
index 07831cc3c171d39bcc96b1f3fa8e20615ac804ba..7f2e790e0929a9a23a13015c32cc119b81593c2d 100644 (file)
@@ -27,6 +27,8 @@ struct omap2_hsmmc_info {
        char    *name;          /* or NULL for default */
        struct platform_device *pdev;   /* mmc controller instance */
        int     ocr_mask;       /* temporary HACK */
+       int     max_freq;       /* maximum clock, if constrained by external
+                                * circuitry, or 0 for default */
        /* Remux (pad configuration) when powering on/off */
        void (*remux)(struct device *dev, int slot, int power_on);
        /* init some special card */
index e20b419d598342f55453f3526969e34120728517..0952494f481aa4a7c5dd4f7f6e615b9148f218c1 100644 (file)
@@ -68,11 +68,11 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra-i2s.1", NULL),
        OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra-das", NULL),
        OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0",
-                      &tegra_ehci1_device.dev.platform_data),
+                      &tegra_ehci1_pdata),
        OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1",
-                      &tegra_ehci2_device.dev.platform_data),
+                      &tegra_ehci2_pdata),
        OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB3_BASE, "tegra-ehci.2",
-                      &tegra_ehci3_device.dev.platform_data),
+                      &tegra_ehci3_pdata),
        {}
 };
 
index 7a2a02dbd632f3134ca98730497368b0d555fc9d..5f6b867e20b49c77c2635017e44b6dc0d8eeafe1 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/fsl_devices.h>
 #include <linux/serial_8250.h>
 #include <linux/i2c-tegra.h>
-#include <linux/platform_data/tegra_usb.h>
 #include <asm/pmu.h>
 #include <mach/irqs.h>
 #include <mach/iomap.h>
@@ -446,18 +445,18 @@ static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = {
        .clk = "cdev2",
 };
 
-static struct tegra_ehci_platform_data tegra_ehci1_pdata = {
+struct tegra_ehci_platform_data tegra_ehci1_pdata = {
        .operating_mode = TEGRA_USB_OTG,
        .power_down_on_bus_suspend = 1,
 };
 
-static struct tegra_ehci_platform_data tegra_ehci2_pdata = {
+struct tegra_ehci_platform_data tegra_ehci2_pdata = {
        .phy_config = &tegra_ehci2_ulpi_phy_config,
        .operating_mode = TEGRA_USB_HOST,
        .power_down_on_bus_suspend = 1,
 };
 
-static struct tegra_ehci_platform_data tegra_ehci3_pdata = {
+struct tegra_ehci_platform_data tegra_ehci3_pdata = {
        .operating_mode = TEGRA_USB_HOST,
        .power_down_on_bus_suspend = 1,
 };
index 873ecb2f8ae6af0fb40111457e2c1ae7c1a06ed6..ec455679b219a987dcade1063f7770559746e9f4 100644 (file)
 #define __MACH_TEGRA_DEVICES_H
 
 #include <linux/platform_device.h>
+#include <linux/platform_data/tegra_usb.h>
+
+extern struct tegra_ehci_platform_data tegra_ehci1_pdata;
+extern struct tegra_ehci_platform_data tegra_ehci2_pdata;
+extern struct tegra_ehci_platform_data tegra_ehci3_pdata;
 
 extern struct platform_device tegra_gpio_device;
 extern struct platform_device tegra_pinmux_device;
index f75946c3293d2bd26b0de35b8f253c0ed832eb3d..7a38750c0079088dafc76dd64f7d8135d1369d39 100644 (file)
@@ -137,8 +137,6 @@ struct omap_mmc_platform_data {
                int (*set_power)(struct device *dev, int slot,
                                 int power_on, int vdd);
                int (*get_ro)(struct device *dev, int slot);
-               int (*set_sleep)(struct device *dev, int slot, int sleep,
-                                int vdd, int cardsleep);
                void (*remux)(struct device *dev, int slot, int power_on);
                /* Call back before enabling / disabling regulators */
                void (*before_set_reg)(struct device *dev, int slot,
index d1cc81e63ba63a08602fc58f4c1e3e63db1a065c..ac795d311f4411cef9cd8c76b1e91cc6b7d5988c 100644 (file)
@@ -843,7 +843,7 @@ early_param("additional_cpus", setup_additional_cpus);
  * are onlined, or offlined. The reason is per-cpu data-structures
  * are allocated by some modules at init time, and dont expect to
  * do this dynamically on cpu arrival/departure.
- * cpu_present_map on the other hand can change dynamically.
+ * cpu_present_mask on the other hand can change dynamically.
  * In case when cpu_hotplug is not compiled, then we resort to current
  * behaviour, which is cpu_possible == cpu_present.
  * - Ashok Raj
@@ -921,7 +921,7 @@ static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
 
        acpi_map_cpu2node(handle, cpu, physid);
 
-       cpu_set(cpu, cpu_present_map);
+       set_cpu_present(cpu, true);
        ia64_cpu_to_sapicid[cpu] = physid;
 
        acpi_processor_set_pdc(handle);
@@ -940,7 +940,7 @@ EXPORT_SYMBOL(acpi_map_lsapic);
 int acpi_unmap_lsapic(int cpu)
 {
        ia64_cpu_to_sapicid[cpu] = -1;
-       cpu_clear(cpu, cpu_present_map);
+       set_cpu_present(cpu, false);
 
 #ifdef CONFIG_ACPI_NUMA
        /* NUMA specific cleanup's */
index 08113b1d30f714a25e903875d3dc1f6e9c85dbc5..5c3e0888265a80a2fe75d48f6ed8177aeb3aad7f 100644 (file)
@@ -117,7 +117,7 @@ static inline int find_unassigned_vector(cpumask_t domain)
        cpumask_t mask;
        int pos, vector;
 
-       cpus_and(mask, domain, cpu_online_map);
+       cpumask_and(&mask, &domain, cpu_online_mask);
        if (cpus_empty(mask))
                return -EINVAL;
 
@@ -140,7 +140,7 @@ static int __bind_irq_vector(int irq, int vector, cpumask_t domain)
        BUG_ON((unsigned)irq >= NR_IRQS);
        BUG_ON((unsigned)vector >= IA64_NUM_VECTORS);
 
-       cpus_and(mask, domain, cpu_online_map);
+       cpumask_and(&mask, &domain, cpu_online_mask);
        if (cpus_empty(mask))
                return -EINVAL;
        if ((cfg->vector == vector) && cpus_equal(cfg->domain, domain))
@@ -178,7 +178,7 @@ static void __clear_irq_vector(int irq)
        BUG_ON(cfg->vector == IRQ_VECTOR_UNASSIGNED);
        vector = cfg->vector;
        domain = cfg->domain;
-       cpus_and(mask, cfg->domain, cpu_online_map);
+       cpumask_and(&mask, &cfg->domain, cpu_online_mask);
        for_each_cpu_mask(cpu, mask)
                per_cpu(vector_irq, cpu)[vector] = -1;
        cfg->vector = IRQ_VECTOR_UNASSIGNED;
@@ -321,7 +321,7 @@ void irq_complete_move(unsigned irq)
        if (unlikely(cpu_isset(smp_processor_id(), cfg->old_domain)))
                return;
 
-       cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
+       cpumask_and(&cleanup_mask, &cfg->old_domain, cpu_online_mask);
        cfg->move_cleanup_count = cpus_weight(cleanup_mask);
        for_each_cpu_mask(i, cleanup_mask)
                platform_send_ipi(i, IA64_IRQ_MOVE_VECTOR, IA64_IPI_DM_INT, 0);
index a39fe098a7322e15a480add1176d8154e55c949a..65bf9cd390443c3574e8d4da5a175c566928b535 100644 (file)
@@ -1514,7 +1514,8 @@ static void
 ia64_mca_cmc_poll (unsigned long dummy)
 {
        /* Trigger a CMC interrupt cascade  */
-       platform_send_ipi(first_cpu(cpu_online_map), IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0);
+       platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CMCP_VECTOR,
+                                                       IA64_IPI_DM_INT, 0);
 }
 
 /*
@@ -1590,7 +1591,8 @@ static void
 ia64_mca_cpe_poll (unsigned long dummy)
 {
        /* Trigger a CPE interrupt cascade  */
-       platform_send_ipi(first_cpu(cpu_online_map), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0);
+       platform_send_ipi(cpumask_first(cpu_online_mask), IA64_CPEP_VECTOR,
+                                                       IA64_IPI_DM_INT, 0);
 }
 
 #endif /* CONFIG_ACPI */
index 94e0db72d4a68591370de63af9db07baaae203ab..fb2f1e622877e202f8bdb6be4d6922fa6431986f 100644 (file)
@@ -57,7 +57,7 @@ int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
                return irq;
 
        irq_set_msi_desc(irq, desc);
-       cpus_and(mask, irq_to_domain(irq), cpu_online_map);
+       cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
        dest_phys_id = cpu_physical_id(first_cpu(mask));
        vector = irq_to_vector(irq);
 
@@ -179,7 +179,7 @@ msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
        unsigned dest;
        cpumask_t mask;
 
-       cpus_and(mask, irq_to_domain(irq), cpu_online_map);
+       cpumask_and(&mask, &(irq_to_domain(irq)), cpu_online_mask);
        dest = cpu_physical_id(first_cpu(mask));
 
        msg->address_hi = 0;
index c45e6ddb4ddb0ffc50c48d5936ea25379211eb3b..aaefd9b94f2fc6f57865b5d500bceaf50fdc84b3 100644 (file)
@@ -485,7 +485,7 @@ mark_bsp_online (void)
 {
 #ifdef CONFIG_SMP
        /* If we register an early console, allow CPU 0 to printk */
-       cpu_set(smp_processor_id(), cpu_online_map);
+       set_cpu_online(smp_processor_id(), true);
 #endif
 }
 
index e27f925032aeb73529196fcd41c9b550bda5c8ed..9fcd4e63048f65f5ae638833c7a51b756883acbb 100644 (file)
@@ -76,7 +76,7 @@ stop_this_cpu(void)
        /*
         * Remove this CPU:
         */
-       cpu_clear(smp_processor_id(), cpu_online_map);
+       set_cpu_online(smp_processor_id(), false);
        max_xtp();
        local_irq_disable();
        cpu_halt();
index fb7927be75c4a4aedf774801b39e3d7ab1df32b7..796f6a5b966a742d46a4f63417939e0a737a0732 100644 (file)
@@ -400,7 +400,7 @@ smp_callin (void)
        /* Setup the per cpu irq handling data structures */
        __setup_vector_irq(cpuid);
        notify_cpu_starting(cpuid);
-       cpu_set(cpuid, cpu_online_map);
+       set_cpu_online(cpuid, true);
        per_cpu(cpu_state, cpuid) = CPU_ONLINE;
        spin_unlock(&vector_lock);
        ipi_call_unlock_irq();
@@ -547,7 +547,7 @@ do_rest:
        if (!cpu_isset(cpu, cpu_callin_map)) {
                printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid);
                ia64_cpu_to_sapicid[cpu] = -1;
-               cpu_clear(cpu, cpu_online_map);  /* was set in smp_callin() */
+               set_cpu_online(cpu, false);  /* was set in smp_callin() */
                return -EINVAL;
        }
        return 0;
@@ -577,8 +577,7 @@ smp_build_cpu_map (void)
        }
 
        ia64_cpu_to_sapicid[0] = boot_cpu_id;
-       cpus_clear(cpu_present_map);
-       set_cpu_present(0, true);
+       init_cpu_present(cpumask_of(0));
        set_cpu_possible(0, true);
        for (cpu = 1, i = 0; i < smp_boot_data.cpu_count; i++) {
                sapicid = smp_boot_data.cpu_phys_id[i];
@@ -605,10 +604,6 @@ smp_prepare_cpus (unsigned int max_cpus)
 
        smp_setup_percpu_timer();
 
-       /*
-        * We have the boot CPU online for sure.
-        */
-       cpu_set(0, cpu_online_map);
        cpu_set(0, cpu_callin_map);
 
        local_cpu_data->loops_per_jiffy = loops_per_jiffy;
@@ -632,7 +627,7 @@ smp_prepare_cpus (unsigned int max_cpus)
 
 void __devinit smp_prepare_boot_cpu(void)
 {
-       cpu_set(smp_processor_id(), cpu_online_map);
+       set_cpu_online(smp_processor_id(), true);
        cpu_set(smp_processor_id(), cpu_callin_map);
        set_numa_node(cpu_to_node_map[smp_processor_id()]);
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
@@ -689,7 +684,7 @@ int migrate_platform_irqs(unsigned int cpu)
                        /*
                         * Now re-target the CPEI to a different processor
                         */
-                       new_cpei_cpu = any_online_cpu(cpu_online_map);
+                       new_cpei_cpu = cpumask_any(cpu_online_mask);
                        mask = cpumask_of(new_cpei_cpu);
                        set_cpei_target_cpu(new_cpei_cpu);
                        data = irq_get_irq_data(ia64_cpe_irq);
@@ -731,10 +726,10 @@ int __cpu_disable(void)
                        return -EBUSY;
        }
 
-       cpu_clear(cpu, cpu_online_map);
+       set_cpu_online(cpu, false);
 
        if (migrate_platform_irqs(cpu)) {
-               cpu_set(cpu, cpu_online_map);
+               set_cpu_online(cpu, true);
                return -EBUSY;
        }
 
index 9deb21dbf62965740f2b6c34c1630dbf80d1f4aa..c64460b9c704d56e7cb5efd9fb750e251a9f707f 100644 (file)
@@ -220,7 +220,8 @@ static ssize_t show_shared_cpu_map(struct cache_info *this_leaf, char *buf)
        ssize_t len;
        cpumask_t shared_cpu_map;
 
-       cpus_and(shared_cpu_map, this_leaf->shared_cpu_map, cpu_online_map);
+       cpumask_and(&shared_cpu_map,
+                               &this_leaf->shared_cpu_map, cpu_online_mask);
        len = cpumask_scnprintf(buf, NR_CPUS+1, &shared_cpu_map);
        len += sprintf(buf+len, "\n");
        return len;
index 532124ae4b128f896335b0629af9043fc5277aaa..1aa759aeb5b3f0db2842a22c99b2f493dca10cf7 100644 (file)
@@ -43,10 +43,6 @@ void evaluate_message(int tag);
 /* Boot a secondary cpu */
 void online_secondary(void);
 
-/* Call a function on a specified set of CPUs (may include this one). */
-extern void on_each_cpu_mask(const struct cpumask *mask,
-                            void (*func)(void *), void *info, bool wait);
-
 /* Topology of the supervisor tile grid, and coordinates of boot processor */
 extern HV_Topology smp_topology;
 
@@ -91,9 +87,6 @@ void print_disabled_cpus(void);
 
 #else /* !CONFIG_SMP */
 
-#define on_each_cpu_mask(mask, func, info, wait)               \
-  do { if (cpumask_test_cpu(0, (mask))) func(info); } while (0)
-
 #define smp_master_cpu         0
 #define smp_height             1
 #define smp_width              1
index c52224d5ed45f06a38f4461e19f485a2bb4cadb3..a44e103c5a636670bdbd358f5143419c24d19d7a 100644 (file)
@@ -87,25 +87,6 @@ void send_IPI_allbutself(int tag)
        send_IPI_many(&mask, tag);
 }
 
-
-/*
- * Provide smp_call_function_mask, but also run function locally
- * if specified in the mask.
- */
-void on_each_cpu_mask(const struct cpumask *mask, void (*func)(void *),
-                     void *info, bool wait)
-{
-       int cpu = get_cpu();
-       smp_call_function_many(mask, func, info, wait);
-       if (cpumask_test_cpu(cpu, mask)) {
-               local_irq_disable();
-               func(info);
-               local_irq_enable();
-       }
-       put_cpu();
-}
-
-
 /*
  * Functions related to starting/stopping cpus.
  */
index 8cbeb7209c3e2a24af1e8b681a12494e4b00ee1c..1a2901562059a48a4ec863c64e4150b881ed9271 100644 (file)
@@ -508,15 +508,6 @@ static void __init memblock_x86_reserve_range_setup_data(void)
 
 #ifdef CONFIG_KEXEC
 
-static inline unsigned long long get_total_mem(void)
-{
-       unsigned long long total;
-
-       total = max_pfn - min_low_pfn;
-
-       return total << PAGE_SHIFT;
-}
-
 /*
  * Keep the crash kernel below this limit.  On 32 bits earlier kernels
  * would limit the kernel to the low 512 MiB due to mapping restrictions.
@@ -535,7 +526,7 @@ static void __init reserve_crashkernel(void)
        unsigned long long crash_size, crash_base;
        int ret;
 
-       total_mem = get_total_mem();
+       total_mem = memblock_phys_mem_size();
 
        ret = parse_crashkernel(boot_command_line, total_mem,
                        &crash_size, &crash_base);
index c7ba11f9b203a4e83a66307b299bc67a513f4365..061427a75d375a5ed0655bdac8422e668a252a5e 100644 (file)
@@ -38,7 +38,7 @@
 
 #include <linux/nbd.h>
 
-#define LO_MAGIC 0x68797548
+#define NBD_MAGIC 0x68797548
 
 #ifdef NDEBUG
 #define dprintk(flags, fmt...)
@@ -115,7 +115,7 @@ static void nbd_end_request(struct request *req)
        spin_unlock_irqrestore(q->queue_lock, flags);
 }
 
-static void sock_shutdown(struct nbd_device *lo, int lock)
+static void sock_shutdown(struct nbd_device *nbd, int lock)
 {
        /* Forcibly shutdown the socket causing all listeners
         * to error
@@ -124,14 +124,14 @@ static void sock_shutdown(struct nbd_device *lo, int lock)
         * there should be a more generic interface rather than
         * calling socket ops directly here */
        if (lock)
-               mutex_lock(&lo->tx_lock);
-       if (lo->sock) {
-               dev_warn(disk_to_dev(lo->disk), "shutting down socket\n");
-               kernel_sock_shutdown(lo->sock, SHUT_RDWR);
-               lo->sock = NULL;
+               mutex_lock(&nbd->tx_lock);
+       if (nbd->sock) {
+               dev_warn(disk_to_dev(nbd->disk), "shutting down socket\n");
+               kernel_sock_shutdown(nbd->sock, SHUT_RDWR);
+               nbd->sock = NULL;
        }
        if (lock)
-               mutex_unlock(&lo->tx_lock);
+               mutex_unlock(&nbd->tx_lock);
 }
 
 static void nbd_xmit_timeout(unsigned long arg)
@@ -146,17 +146,17 @@ static void nbd_xmit_timeout(unsigned long arg)
 /*
  *  Send or receive packet.
  */
-static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
+static int sock_xmit(struct nbd_device *nbd, int send, void *buf, int size,
                int msg_flags)
 {
-       struct socket *sock = lo->sock;
+       struct socket *sock = nbd->sock;
        int result;
        struct msghdr msg;
        struct kvec iov;
        sigset_t blocked, oldset;
 
        if (unlikely(!sock)) {
-               dev_err(disk_to_dev(lo->disk),
+               dev_err(disk_to_dev(nbd->disk),
                        "Attempted %s on closed socket in sock_xmit\n",
                        (send ? "send" : "recv"));
                return -EINVAL;
@@ -180,15 +180,15 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
                if (send) {
                        struct timer_list ti;
 
-                       if (lo->xmit_timeout) {
+                       if (nbd->xmit_timeout) {
                                init_timer(&ti);
                                ti.function = nbd_xmit_timeout;
                                ti.data = (unsigned long)current;
-                               ti.expires = jiffies + lo->xmit_timeout;
+                               ti.expires = jiffies + nbd->xmit_timeout;
                                add_timer(&ti);
                        }
                        result = kernel_sendmsg(sock, &msg, &iov, 1, size);
-                       if (lo->xmit_timeout)
+                       if (nbd->xmit_timeout)
                                del_timer_sync(&ti);
                } else
                        result = kernel_recvmsg(sock, &msg, &iov, 1, size,
@@ -200,7 +200,7 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
                                task_pid_nr(current), current->comm,
                                dequeue_signal_lock(current, &current->blocked, &info));
                        result = -EINTR;
-                       sock_shutdown(lo, !send);
+                       sock_shutdown(nbd, !send);
                        break;
                }
 
@@ -218,18 +218,19 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
        return result;
 }
 
-static inline int sock_send_bvec(struct nbd_device *lo, struct bio_vec *bvec,
+static inline int sock_send_bvec(struct nbd_device *nbd, struct bio_vec *bvec,
                int flags)
 {
        int result;
        void *kaddr = kmap(bvec->bv_page);
-       result = sock_xmit(lo, 1, kaddr + bvec->bv_offset, bvec->bv_len, flags);
+       result = sock_xmit(nbd, 1, kaddr + bvec->bv_offset,
+                          bvec->bv_len, flags);
        kunmap(bvec->bv_page);
        return result;
 }
 
 /* always call with the tx_lock held */
-static int nbd_send_req(struct nbd_device *lo, struct request *req)
+static int nbd_send_req(struct nbd_device *nbd, struct request *req)
 {
        int result, flags;
        struct nbd_request request;
@@ -242,14 +243,14 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
        memcpy(request.handle, &req, sizeof(req));
 
        dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%uB)\n",
-                       lo->disk->disk_name, req,
+                       nbd->disk->disk_name, req,
                        nbdcmd_to_ascii(nbd_cmd(req)),
                        (unsigned long long)blk_rq_pos(req) << 9,
                        blk_rq_bytes(req));
-       result = sock_xmit(lo, 1, &request, sizeof(request),
+       result = sock_xmit(nbd, 1, &request, sizeof(request),
                        (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0);
        if (result <= 0) {
-               dev_err(disk_to_dev(lo->disk),
+               dev_err(disk_to_dev(nbd->disk),
                        "Send control failed (result %d)\n", result);
                goto error_out;
        }
@@ -266,10 +267,10 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
                        if (!rq_iter_last(req, iter))
                                flags = MSG_MORE;
                        dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
-                                       lo->disk->disk_name, req, bvec->bv_len);
-                       result = sock_send_bvec(lo, bvec, flags);
+                                       nbd->disk->disk_name, req, bvec->bv_len);
+                       result = sock_send_bvec(nbd, bvec, flags);
                        if (result <= 0) {
-                               dev_err(disk_to_dev(lo->disk),
+                               dev_err(disk_to_dev(nbd->disk),
                                        "Send data failed (result %d)\n",
                                        result);
                                goto error_out;
@@ -282,25 +283,25 @@ error_out:
        return -EIO;
 }
 
-static struct request *nbd_find_request(struct nbd_device *lo,
+static struct request *nbd_find_request(struct nbd_device *nbd,
                                        struct request *xreq)
 {
        struct request *req, *tmp;
        int err;
 
-       err = wait_event_interruptible(lo->active_wq, lo->active_req != xreq);
+       err = wait_event_interruptible(nbd->active_wq, nbd->active_req != xreq);
        if (unlikely(err))
                goto out;
 
-       spin_lock(&lo->queue_lock);
-       list_for_each_entry_safe(req, tmp, &lo->queue_head, queuelist) {
+       spin_lock(&nbd->queue_lock);
+       list_for_each_entry_safe(req, tmp, &nbd->queue_head, queuelist) {
                if (req != xreq)
                        continue;
                list_del_init(&req->queuelist);
-               spin_unlock(&lo->queue_lock);
+               spin_unlock(&nbd->queue_lock);
                return req;
        }
-       spin_unlock(&lo->queue_lock);
+       spin_unlock(&nbd->queue_lock);
 
        err = -ENOENT;
 
@@ -308,78 +309,78 @@ out:
        return ERR_PTR(err);
 }
 
-static inline int sock_recv_bvec(struct nbd_device *lo, struct bio_vec *bvec)
+static inline int sock_recv_bvec(struct nbd_device *nbd, struct bio_vec *bvec)
 {
        int result;
        void *kaddr = kmap(bvec->bv_page);
-       result = sock_xmit(lo, 0, kaddr + bvec->bv_offset, bvec->bv_len,
+       result = sock_xmit(nbd, 0, kaddr + bvec->bv_offset, bvec->bv_len,
                        MSG_WAITALL);
        kunmap(bvec->bv_page);
        return result;
 }
 
 /* NULL returned = something went wrong, inform userspace */
-static struct request *nbd_read_stat(struct nbd_device *lo)
+static struct request *nbd_read_stat(struct nbd_device *nbd)
 {
        int result;
        struct nbd_reply reply;
        struct request *req;
 
        reply.magic = 0;
-       result = sock_xmit(lo, 0, &reply, sizeof(reply), MSG_WAITALL);
+       result = sock_xmit(nbd, 0, &reply, sizeof(reply), MSG_WAITALL);
        if (result <= 0) {
-               dev_err(disk_to_dev(lo->disk),
+               dev_err(disk_to_dev(nbd->disk),
                        "Receive control failed (result %d)\n", result);
                goto harderror;
        }
 
        if (ntohl(reply.magic) != NBD_REPLY_MAGIC) {
-               dev_err(disk_to_dev(lo->disk), "Wrong magic (0x%lx)\n",
+               dev_err(disk_to_dev(nbd->disk), "Wrong magic (0x%lx)\n",
                                (unsigned long)ntohl(reply.magic));
                result = -EPROTO;
                goto harderror;
        }
 
-       req = nbd_find_request(lo, *(struct request **)reply.handle);
+       req = nbd_find_request(nbd, *(struct request **)reply.handle);
        if (IS_ERR(req)) {
                result = PTR_ERR(req);
                if (result != -ENOENT)
                        goto harderror;
 
-               dev_err(disk_to_dev(lo->disk), "Unexpected reply (%p)\n",
+               dev_err(disk_to_dev(nbd->disk), "Unexpected reply (%p)\n",
                        reply.handle);
                result = -EBADR;
                goto harderror;
        }
 
        if (ntohl(reply.error)) {
-               dev_err(disk_to_dev(lo->disk), "Other side returned error (%d)\n",
+               dev_err(disk_to_dev(nbd->disk), "Other side returned error (%d)\n",
                        ntohl(reply.error));
                req->errors++;
                return req;
        }
 
        dprintk(DBG_RX, "%s: request %p: got reply\n",
-                       lo->disk->disk_name, req);
+                       nbd->disk->disk_name, req);
        if (nbd_cmd(req) == NBD_CMD_READ) {
                struct req_iterator iter;
                struct bio_vec *bvec;
 
                rq_for_each_segment(bvec, req, iter) {
-                       result = sock_recv_bvec(lo, bvec);
+                       result = sock_recv_bvec(nbd, bvec);
                        if (result <= 0) {
-                               dev_err(disk_to_dev(lo->disk), "Receive data failed (result %d)\n",
+                               dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n",
                                        result);
                                req->errors++;
                                return req;
                        }
                        dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
-                               lo->disk->disk_name, req, bvec->bv_len);
+                               nbd->disk->disk_name, req, bvec->bv_len);
                }
        }
        return req;
 harderror:
-       lo->harderror = result;
+       nbd->harderror = result;
        return NULL;
 }
 
@@ -397,48 +398,48 @@ static struct device_attribute pid_attr = {
        .show = pid_show,
 };
 
-static int nbd_do_it(struct nbd_device *lo)
+static int nbd_do_it(struct nbd_device *nbd)
 {
        struct request *req;
        int ret;
 
-       BUG_ON(lo->magic != LO_MAGIC);
+       BUG_ON(nbd->magic != NBD_MAGIC);
 
-       lo->pid = task_pid_nr(current);
-       ret = device_create_file(disk_to_dev(lo->disk), &pid_attr);
+       nbd->pid = task_pid_nr(current);
+       ret = device_create_file(disk_to_dev(nbd->disk), &pid_attr);
        if (ret) {
-               dev_err(disk_to_dev(lo->disk), "device_create_file failed!\n");
-               lo->pid = 0;
+               dev_err(disk_to_dev(nbd->disk), "device_create_file failed!\n");
+               nbd->pid = 0;
                return ret;
        }
 
-       while ((req = nbd_read_stat(lo)) != NULL)
+       while ((req = nbd_read_stat(nbd)) != NULL)
                nbd_end_request(req);
 
-       device_remove_file(disk_to_dev(lo->disk), &pid_attr);
-       lo->pid = 0;
+       device_remove_file(disk_to_dev(nbd->disk), &pid_attr);
+       nbd->pid = 0;
        return 0;
 }
 
-static void nbd_clear_que(struct nbd_device *lo)
+static void nbd_clear_que(struct nbd_device *nbd)
 {
        struct request *req;
 
-       BUG_ON(lo->magic != LO_MAGIC);
+       BUG_ON(nbd->magic != NBD_MAGIC);
 
        /*
-        * Because we have set lo->sock to NULL under the tx_lock, all
+        * Because we have set nbd->sock to NULL under the tx_lock, all
         * modifications to the list must have completed by now.  For
         * the same reason, the active_req must be NULL.
         *
         * As a consequence, we don't need to take the spin lock while
         * purging the list here.
         */
-       BUG_ON(lo->sock);
-       BUG_ON(lo->active_req);
+       BUG_ON(nbd->sock);
+       BUG_ON(nbd->active_req);
 
-       while (!list_empty(&lo->queue_head)) {
-               req = list_entry(lo->queue_head.next, struct request,
+       while (!list_empty(&nbd->queue_head)) {
+               req = list_entry(nbd->queue_head.next, struct request,
                                 queuelist);
                list_del_init(&req->queuelist);
                req->errors++;
@@ -447,7 +448,7 @@ static void nbd_clear_que(struct nbd_device *lo)
 }
 
 
-static void nbd_handle_req(struct nbd_device *lo, struct request *req)
+static void nbd_handle_req(struct nbd_device *nbd, struct request *req)
 {
        if (req->cmd_type != REQ_TYPE_FS)
                goto error_out;
@@ -455,8 +456,8 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req)
        nbd_cmd(req) = NBD_CMD_READ;
        if (rq_data_dir(req) == WRITE) {
                nbd_cmd(req) = NBD_CMD_WRITE;
-               if (lo->flags & NBD_READ_ONLY) {
-                       dev_err(disk_to_dev(lo->disk),
+               if (nbd->flags & NBD_READ_ONLY) {
+                       dev_err(disk_to_dev(nbd->disk),
                                "Write on read-only\n");
                        goto error_out;
                }
@@ -464,29 +465,29 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req)
 
        req->errors = 0;
 
-       mutex_lock(&lo->tx_lock);
-       if (unlikely(!lo->sock)) {
-               mutex_unlock(&lo->tx_lock);
-               dev_err(disk_to_dev(lo->disk),
+       mutex_lock(&nbd->tx_lock);
+       if (unlikely(!nbd->sock)) {
+               mutex_unlock(&nbd->tx_lock);
+               dev_err(disk_to_dev(nbd->disk),
                        "Attempted send on closed socket\n");
                goto error_out;
        }
 
-       lo->active_req = req;
+       nbd->active_req = req;
 
-       if (nbd_send_req(lo, req) != 0) {
-               dev_err(disk_to_dev(lo->disk), "Request send failed\n");
+       if (nbd_send_req(nbd, req) != 0) {
+               dev_err(disk_to_dev(nbd->disk), "Request send failed\n");
                req->errors++;
                nbd_end_request(req);
        } else {
-               spin_lock(&lo->queue_lock);
-               list_add(&req->queuelist, &lo->queue_head);
-               spin_unlock(&lo->queue_lock);
+               spin_lock(&nbd->queue_lock);
+               list_add(&req->queuelist, &nbd->queue_head);
+               spin_unlock(&nbd->queue_lock);
        }
 
-       lo->active_req = NULL;
-       mutex_unlock(&lo->tx_lock);
-       wake_up_all(&lo->active_wq);
+       nbd->active_req = NULL;
+       mutex_unlock(&nbd->tx_lock);
+       wake_up_all(&nbd->active_wq);
 
        return;
 
@@ -497,28 +498,28 @@ error_out:
 
 static int nbd_thread(void *data)
 {
-       struct nbd_device *lo = data;
+       struct nbd_device *nbd = data;
        struct request *req;
 
        set_user_nice(current, -20);
-       while (!kthread_should_stop() || !list_empty(&lo->waiting_queue)) {
+       while (!kthread_should_stop() || !list_empty(&nbd->waiting_queue)) {
                /* wait for something to do */
-               wait_event_interruptible(lo->waiting_wq,
+               wait_event_interruptible(nbd->waiting_wq,
                                         kthread_should_stop() ||
-                                        !list_empty(&lo->waiting_queue));
+                                        !list_empty(&nbd->waiting_queue));
 
                /* extract request */
-               if (list_empty(&lo->waiting_queue))
+               if (list_empty(&nbd->waiting_queue))
                        continue;
 
-               spin_lock_irq(&lo->queue_lock);
-               req = list_entry(lo->waiting_queue.next, struct request,
+               spin_lock_irq(&nbd->queue_lock);
+               req = list_entry(nbd->waiting_queue.next, struct request,
                                 queuelist);
                list_del_init(&req->queuelist);
-               spin_unlock_irq(&lo->queue_lock);
+               spin_unlock_irq(&nbd->queue_lock);
 
                /* handle request */
-               nbd_handle_req(lo, req);
+               nbd_handle_req(nbd, req);
        }
        return 0;
 }
@@ -526,7 +527,7 @@ static int nbd_thread(void *data)
 /*
  * We always wait for result of write, for now. It would be nice to make it optional
  * in future
- * if ((rq_data_dir(req) == WRITE) && (lo->flags & NBD_WRITE_NOCHK))
+ * if ((rq_data_dir(req) == WRITE) && (nbd->flags & NBD_WRITE_NOCHK))
  *   { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
  */
 
@@ -535,19 +536,19 @@ static void do_nbd_request(struct request_queue *q)
        struct request *req;
        
        while ((req = blk_fetch_request(q)) != NULL) {
-               struct nbd_device *lo;
+               struct nbd_device *nbd;
 
                spin_unlock_irq(q->queue_lock);
 
                dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n",
                                req->rq_disk->disk_name, req, req->cmd_type);
 
-               lo = req->rq_disk->private_data;
+               nbd = req->rq_disk->private_data;
 
-               BUG_ON(lo->magic != LO_MAGIC);
+               BUG_ON(nbd->magic != NBD_MAGIC);
 
-               if (unlikely(!lo->sock)) {
-                       dev_err(disk_to_dev(lo->disk),
+               if (unlikely(!nbd->sock)) {
+                       dev_err(disk_to_dev(nbd->disk),
                                "Attempted send on closed socket\n");
                        req->errors++;
                        nbd_end_request(req);
@@ -555,11 +556,11 @@ static void do_nbd_request(struct request_queue *q)
                        continue;
                }
 
-               spin_lock_irq(&lo->queue_lock);
-               list_add_tail(&req->queuelist, &lo->waiting_queue);
-               spin_unlock_irq(&lo->queue_lock);
+               spin_lock_irq(&nbd->queue_lock);
+               list_add_tail(&req->queuelist, &nbd->waiting_queue);
+               spin_unlock_irq(&nbd->queue_lock);
 
-               wake_up(&lo->waiting_wq);
+               wake_up(&nbd->waiting_wq);
 
                spin_lock_irq(q->queue_lock);
        }
@@ -567,32 +568,32 @@ static void do_nbd_request(struct request_queue *q)
 
 /* Must be called with tx_lock held */
 
-static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
+static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
                       unsigned int cmd, unsigned long arg)
 {
        switch (cmd) {
        case NBD_DISCONNECT: {
                struct request sreq;
 
-               dev_info(disk_to_dev(lo->disk), "NBD_DISCONNECT\n");
+               dev_info(disk_to_dev(nbd->disk), "NBD_DISCONNECT\n");
 
                blk_rq_init(NULL, &sreq);
                sreq.cmd_type = REQ_TYPE_SPECIAL;
                nbd_cmd(&sreq) = NBD_CMD_DISC;
-               if (!lo->sock)
+               if (!nbd->sock)
                        return -EINVAL;
-               nbd_send_req(lo, &sreq);
+               nbd_send_req(nbd, &sreq);
                 return 0;
        }
  
        case NBD_CLEAR_SOCK: {
                struct file *file;
 
-               lo->sock = NULL;
-               file = lo->file;
-               lo->file = NULL;
-               nbd_clear_que(lo);
-               BUG_ON(!list_empty(&lo->queue_head));
+               nbd->sock = NULL;
+               file = nbd->file;
+               nbd->file = NULL;
+               nbd_clear_que(nbd);
+               BUG_ON(!list_empty(&nbd->queue_head));
                if (file)
                        fput(file);
                return 0;
@@ -600,14 +601,14 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
 
        case NBD_SET_SOCK: {
                struct file *file;
-               if (lo->file)
+               if (nbd->file)
                        return -EBUSY;
                file = fget(arg);
                if (file) {
                        struct inode *inode = file->f_path.dentry->d_inode;
                        if (S_ISSOCK(inode->i_mode)) {
-                               lo->file = file;
-                               lo->sock = SOCKET_I(inode);
+                               nbd->file = file;
+                               nbd->sock = SOCKET_I(inode);
                                if (max_part > 0)
                                        bdev->bd_invalidated = 1;
                                return 0;
@@ -619,29 +620,29 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
        }
 
        case NBD_SET_BLKSIZE:
-               lo->blksize = arg;
-               lo->bytesize &= ~(lo->blksize-1);
-               bdev->bd_inode->i_size = lo->bytesize;
-               set_blocksize(bdev, lo->blksize);
-               set_capacity(lo->disk, lo->bytesize >> 9);
+               nbd->blksize = arg;
+               nbd->bytesize &= ~(nbd->blksize-1);
+               bdev->bd_inode->i_size = nbd->bytesize;
+               set_blocksize(bdev, nbd->blksize);
+               set_capacity(nbd->disk, nbd->bytesize >> 9);
                return 0;
 
        case NBD_SET_SIZE:
-               lo->bytesize = arg & ~(lo->blksize-1);
-               bdev->bd_inode->i_size = lo->bytesize;
-               set_blocksize(bdev, lo->blksize);
-               set_capacity(lo->disk, lo->bytesize >> 9);
+               nbd->bytesize = arg & ~(nbd->blksize-1);
+               bdev->bd_inode->i_size = nbd->bytesize;
+               set_blocksize(bdev, nbd->blksize);
+               set_capacity(nbd->disk, nbd->bytesize >> 9);
                return 0;
 
        case NBD_SET_TIMEOUT:
-               lo->xmit_timeout = arg * HZ;
+               nbd->xmit_timeout = arg * HZ;
                return 0;
 
        case NBD_SET_SIZE_BLOCKS:
-               lo->bytesize = ((u64) arg) * lo->blksize;
-               bdev->bd_inode->i_size = lo->bytesize;
-               set_blocksize(bdev, lo->blksize);
-               set_capacity(lo->disk, lo->bytesize >> 9);
+               nbd->bytesize = ((u64) arg) * nbd->blksize;
+               bdev->bd_inode->i_size = nbd->bytesize;
+               set_blocksize(bdev, nbd->blksize);
+               set_capacity(nbd->disk, nbd->bytesize >> 9);
                return 0;
 
        case NBD_DO_IT: {
@@ -649,38 +650,38 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
                struct file *file;
                int error;
 
-               if (lo->pid)
+               if (nbd->pid)
                        return -EBUSY;
-               if (!lo->file)
+               if (!nbd->file)
                        return -EINVAL;
 
-               mutex_unlock(&lo->tx_lock);
+               mutex_unlock(&nbd->tx_lock);
 
-               thread = kthread_create(nbd_thread, lo, lo->disk->disk_name);
+               thread = kthread_create(nbd_thread, nbd, nbd->disk->disk_name);
                if (IS_ERR(thread)) {
-                       mutex_lock(&lo->tx_lock);
+                       mutex_lock(&nbd->tx_lock);
                        return PTR_ERR(thread);
                }
                wake_up_process(thread);
-               error = nbd_do_it(lo);
+               error = nbd_do_it(nbd);
                kthread_stop(thread);
 
-               mutex_lock(&lo->tx_lock);
+               mutex_lock(&nbd->tx_lock);
                if (error)
                        return error;
-               sock_shutdown(lo, 0);
-               file = lo->file;
-               lo->file = NULL;
-               nbd_clear_que(lo);
-               dev_warn(disk_to_dev(lo->disk), "queue cleared\n");
+               sock_shutdown(nbd, 0);
+               file = nbd->file;
+               nbd->file = NULL;
+               nbd_clear_que(nbd);
+               dev_warn(disk_to_dev(nbd->disk), "queue cleared\n");
                if (file)
                        fput(file);
-               lo->bytesize = 0;
+               nbd->bytesize = 0;
                bdev->bd_inode->i_size = 0;
-               set_capacity(lo->disk, 0);
+               set_capacity(nbd->disk, 0);
                if (max_part > 0)
                        ioctl_by_bdev(bdev, BLKRRPART, 0);
-               return lo->harderror;
+               return nbd->harderror;
        }
 
        case NBD_CLEAR_QUE:
@@ -688,14 +689,14 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
                 * This is for compatibility only.  The queue is always cleared
                 * by NBD_DO_IT or NBD_CLEAR_SOCK.
                 */
-               BUG_ON(!lo->sock && !list_empty(&lo->queue_head));
+               BUG_ON(!nbd->sock && !list_empty(&nbd->queue_head));
                return 0;
 
        case NBD_PRINT_DEBUG:
-               dev_info(disk_to_dev(lo->disk),
+               dev_info(disk_to_dev(nbd->disk),
                        "next = %p, prev = %p, head = %p\n",
-                       lo->queue_head.next, lo->queue_head.prev,
-                       &lo->queue_head);
+                       nbd->queue_head.next, nbd->queue_head.prev,
+                       &nbd->queue_head);
                return 0;
        }
        return -ENOTTY;
@@ -704,21 +705,21 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
 static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
                     unsigned int cmd, unsigned long arg)
 {
-       struct nbd_device *lo = bdev->bd_disk->private_data;
+       struct nbd_device *nbd = bdev->bd_disk->private_data;
        int error;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       BUG_ON(lo->magic != LO_MAGIC);
+       BUG_ON(nbd->magic != NBD_MAGIC);
 
        /* Anyone capable of this syscall can do *real bad* things */
        dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",
-                       lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
+               nbd->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);
 
-       mutex_lock(&lo->tx_lock);
-       error = __nbd_ioctl(bdev, lo, cmd, arg);
-       mutex_unlock(&lo->tx_lock);
+       mutex_lock(&nbd->tx_lock);
+       error = __nbd_ioctl(bdev, nbd, cmd, arg);
+       mutex_unlock(&nbd->tx_lock);
 
        return error;
 }
@@ -804,7 +805,7 @@ static int __init nbd_init(void)
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = nbd_dev[i].disk;
                nbd_dev[i].file = NULL;
-               nbd_dev[i].magic = LO_MAGIC;
+               nbd_dev[i].magic = NBD_MAGIC;
                nbd_dev[i].flags = 0;
                INIT_LIST_HEAD(&nbd_dev[i].waiting_queue);
                spin_lock_init(&nbd_dev[i].queue_lock);
index cf82fedae09975272fd6517b1fa5346eff95a814..e53fc24c6af3e1b97ea95052dd383efc26138eb3 100644 (file)
@@ -118,8 +118,8 @@ enum kcs_states {
 #define MAX_KCS_WRITE_SIZE IPMI_MAX_MSG_LENGTH
 
 /* Timeouts in microseconds. */
-#define IBF_RETRY_TIMEOUT 1000000
-#define OBF_RETRY_TIMEOUT 1000000
+#define IBF_RETRY_TIMEOUT 5000000
+#define OBF_RETRY_TIMEOUT 5000000
 #define MAX_ERROR_RETRIES 10
 #define ERROR0_OBF_WAIT_JIFFIES (2*HZ)
 
index c90e9390b78c15d517e9431601c755541344bcce..2c29942b132654747af55e6b70ea4857dc9e0de4 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/rcupdate.h>
+#include <linux/interrupt.h>
 
 #define PFX "IPMI message handler: "
 
@@ -52,6 +53,8 @@
 
 static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
 static int ipmi_init_msghandler(void);
+static void smi_recv_tasklet(unsigned long);
+static void handle_new_recv_msgs(ipmi_smi_t intf);
 
 static int initialized;
 
@@ -354,12 +357,15 @@ struct ipmi_smi {
        int curr_seq;
 
        /*
-        * Messages that were delayed for some reason (out of memory,
-        * for instance), will go in here to be processed later in a
-        * periodic timer interrupt.
+        * Messages queued for delivery.  If delivery fails (out of memory
+        * for instance), They will stay in here to be processed later in a
+        * periodic timer interrupt.  The tasklet is for handling received
+        * messages directly from the handler.
         */
        spinlock_t       waiting_msgs_lock;
        struct list_head waiting_msgs;
+       atomic_t         watchdog_pretimeouts_to_deliver;
+       struct tasklet_struct recv_tasklet;
 
        /*
         * The list of command receivers that are registered for commands
@@ -492,6 +498,8 @@ static void clean_up_interface_data(ipmi_smi_t intf)
        struct cmd_rcvr  *rcvr, *rcvr2;
        struct list_head list;
 
+       tasklet_kill(&intf->recv_tasklet);
+
        free_smi_msg_list(&intf->waiting_msgs);
        free_recv_msg_list(&intf->waiting_events);
 
@@ -2785,12 +2793,17 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
        return;
 }
 
-void ipmi_poll_interface(ipmi_user_t user)
+static void ipmi_poll(ipmi_smi_t intf)
 {
-       ipmi_smi_t intf = user->intf;
-
        if (intf->handlers->poll)
                intf->handlers->poll(intf->send_info);
+       /* In case something came in */
+       handle_new_recv_msgs(intf);
+}
+
+void ipmi_poll_interface(ipmi_user_t user)
+{
+       ipmi_poll(user->intf);
 }
 EXPORT_SYMBOL(ipmi_poll_interface);
 
@@ -2859,6 +2872,10 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
 #endif
        spin_lock_init(&intf->waiting_msgs_lock);
        INIT_LIST_HEAD(&intf->waiting_msgs);
+       tasklet_init(&intf->recv_tasklet,
+                    smi_recv_tasklet,
+                    (unsigned long) intf);
+       atomic_set(&intf->watchdog_pretimeouts_to_deliver, 0);
        spin_lock_init(&intf->events_lock);
        INIT_LIST_HEAD(&intf->waiting_events);
        intf->waiting_events_count = 0;
@@ -3621,11 +3638,11 @@ static int handle_bmc_rsp(ipmi_smi_t          intf,
 }
 
 /*
- * Handle a new message.  Return 1 if the message should be requeued,
+ * Handle a received message.  Return 1 if the message should be requeued,
  * 0 if the message should be freed, or -1 if the message should not
  * be freed or requeued.
  */
-static int handle_new_recv_msg(ipmi_smi_t          intf,
+static int handle_one_recv_msg(ipmi_smi_t          intf,
                               struct ipmi_smi_msg *msg)
 {
        int requeue;
@@ -3783,12 +3800,72 @@ static int handle_new_recv_msg(ipmi_smi_t          intf,
        return requeue;
 }
 
+/*
+ * If there are messages in the queue or pretimeouts, handle them.
+ */
+static void handle_new_recv_msgs(ipmi_smi_t intf)
+{
+       struct ipmi_smi_msg  *smi_msg;
+       unsigned long        flags = 0;
+       int                  rv;
+       int                  run_to_completion = intf->run_to_completion;
+
+       /* See if any waiting messages need to be processed. */
+       if (!run_to_completion)
+               spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
+       while (!list_empty(&intf->waiting_msgs)) {
+               smi_msg = list_entry(intf->waiting_msgs.next,
+                                    struct ipmi_smi_msg, link);
+               list_del(&smi_msg->link);
+               if (!run_to_completion)
+                       spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+               rv = handle_one_recv_msg(intf, smi_msg);
+               if (!run_to_completion)
+                       spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
+               if (rv == 0) {
+                       /* Message handled */
+                       ipmi_free_smi_msg(smi_msg);
+               } else if (rv < 0) {
+                       /* Fatal error on the message, del but don't free. */
+               } else {
+                       /*
+                        * To preserve message order, quit if we
+                        * can't handle a message.
+                        */
+                       list_add(&smi_msg->link, &intf->waiting_msgs);
+                       break;
+               }
+       }
+       if (!run_to_completion)
+               spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+
+       /*
+        * If the pretimout count is non-zero, decrement one from it and
+        * deliver pretimeouts to all the users.
+        */
+       if (atomic_add_unless(&intf->watchdog_pretimeouts_to_deliver, -1, 0)) {
+               ipmi_user_t user;
+
+               rcu_read_lock();
+               list_for_each_entry_rcu(user, &intf->users, link) {
+                       if (user->handler->ipmi_watchdog_pretimeout)
+                               user->handler->ipmi_watchdog_pretimeout(
+                                       user->handler_data);
+               }
+               rcu_read_unlock();
+       }
+}
+
+static void smi_recv_tasklet(unsigned long val)
+{
+       handle_new_recv_msgs((ipmi_smi_t) val);
+}
+
 /* Handle a new message from the lower layer. */
 void ipmi_smi_msg_received(ipmi_smi_t          intf,
                           struct ipmi_smi_msg *msg)
 {
        unsigned long flags = 0; /* keep us warning-free. */
-       int           rv;
        int           run_to_completion;
 
 
@@ -3842,31 +3919,11 @@ void ipmi_smi_msg_received(ipmi_smi_t          intf,
        run_to_completion = intf->run_to_completion;
        if (!run_to_completion)
                spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
-       if (!list_empty(&intf->waiting_msgs)) {
-               list_add_tail(&msg->link, &intf->waiting_msgs);
-               if (!run_to_completion)
-                       spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
-               goto out;
-       }
+       list_add_tail(&msg->link, &intf->waiting_msgs);
        if (!run_to_completion)
                spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
 
-       rv = handle_new_recv_msg(intf, msg);
-       if (rv > 0) {
-               /*
-                * Could not handle the message now, just add it to a
-                * list to handle later.
-                */
-               run_to_completion = intf->run_to_completion;
-               if (!run_to_completion)
-                       spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
-               list_add_tail(&msg->link, &intf->waiting_msgs);
-               if (!run_to_completion)
-                       spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
-       } else if (rv == 0) {
-               ipmi_free_smi_msg(msg);
-       }
-
+       tasklet_schedule(&intf->recv_tasklet);
  out:
        return;
 }
@@ -3874,16 +3931,8 @@ EXPORT_SYMBOL(ipmi_smi_msg_received);
 
 void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
 {
-       ipmi_user_t user;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(user, &intf->users, link) {
-               if (!user->handler->ipmi_watchdog_pretimeout)
-                       continue;
-
-               user->handler->ipmi_watchdog_pretimeout(user->handler_data);
-       }
-       rcu_read_unlock();
+       atomic_set(&intf->watchdog_pretimeouts_to_deliver, 1);
+       tasklet_schedule(&intf->recv_tasklet);
 }
 EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
 
@@ -3997,28 +4046,12 @@ static void ipmi_timeout_handler(long timeout_period)
        ipmi_smi_t           intf;
        struct list_head     timeouts;
        struct ipmi_recv_msg *msg, *msg2;
-       struct ipmi_smi_msg  *smi_msg, *smi_msg2;
        unsigned long        flags;
        int                  i;
 
        rcu_read_lock();
        list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
-               /* See if any waiting messages need to be processed. */
-               spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
-               list_for_each_entry_safe(smi_msg, smi_msg2,
-                                        &intf->waiting_msgs, link) {
-                       if (!handle_new_recv_msg(intf, smi_msg)) {
-                               list_del(&smi_msg->link);
-                               ipmi_free_smi_msg(smi_msg);
-                       } else {
-                               /*
-                                * To preserve message order, quit if we
-                                * can't handle a message.
-                                */
-                               break;
-                       }
-               }
-               spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+               tasklet_schedule(&intf->recv_tasklet);
 
                /*
                 * Go through the seq table and find any messages that
@@ -4172,12 +4205,48 @@ EXPORT_SYMBOL(ipmi_free_recv_msg);
 
 #ifdef CONFIG_IPMI_PANIC_EVENT
 
+static atomic_t panic_done_count = ATOMIC_INIT(0);
+
 static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
 {
+       atomic_dec(&panic_done_count);
 }
 
 static void dummy_recv_done_handler(struct ipmi_recv_msg *msg)
 {
+       atomic_dec(&panic_done_count);
+}
+
+/*
+ * Inside a panic, send a message and wait for a response.
+ */
+static void ipmi_panic_request_and_wait(ipmi_smi_t           intf,
+                                       struct ipmi_addr     *addr,
+                                       struct kernel_ipmi_msg *msg)
+{
+       struct ipmi_smi_msg  smi_msg;
+       struct ipmi_recv_msg recv_msg;
+       int rv;
+
+       smi_msg.done = dummy_smi_done_handler;
+       recv_msg.done = dummy_recv_done_handler;
+       atomic_add(2, &panic_done_count);
+       rv = i_ipmi_request(NULL,
+                           intf,
+                           addr,
+                           0,
+                           msg,
+                           intf,
+                           &smi_msg,
+                           &recv_msg,
+                           0,
+                           intf->channels[0].address,
+                           intf->channels[0].lun,
+                           0, 1); /* Don't retry, and don't wait. */
+       if (rv)
+               atomic_sub(2, &panic_done_count);
+       while (atomic_read(&panic_done_count) != 0)
+               ipmi_poll(intf);
 }
 
 #ifdef CONFIG_IPMI_PANIC_STRING
@@ -4216,8 +4285,6 @@ static void send_panic_events(char *str)
        unsigned char                     data[16];
        struct ipmi_system_interface_addr *si;
        struct ipmi_addr                  addr;
-       struct ipmi_smi_msg               smi_msg;
-       struct ipmi_recv_msg              recv_msg;
 
        si = (struct ipmi_system_interface_addr *) &addr;
        si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
@@ -4245,9 +4312,6 @@ static void send_panic_events(char *str)
                data[7] = str[2];
        }
 
-       smi_msg.done = dummy_smi_done_handler;
-       recv_msg.done = dummy_recv_done_handler;
-
        /* For every registered interface, send the event. */
        list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
                if (!intf->handlers)
@@ -4257,18 +4321,7 @@ static void send_panic_events(char *str)
                intf->run_to_completion = 1;
                /* Send the event announcing the panic. */
                intf->handlers->set_run_to_completion(intf->send_info, 1);
-               i_ipmi_request(NULL,
-                              intf,
-                              &addr,
-                              0,
-                              &msg,
-                              intf,
-                              &smi_msg,
-                              &recv_msg,
-                              0,
-                              intf->channels[0].address,
-                              intf->channels[0].lun,
-                              0, 1); /* Don't retry, and don't wait. */
+               ipmi_panic_request_and_wait(intf, &addr, &msg);
        }
 
 #ifdef CONFIG_IPMI_PANIC_STRING
@@ -4316,18 +4369,7 @@ static void send_panic_events(char *str)
                msg.data = NULL;
                msg.data_len = 0;
                intf->null_user_handler = device_id_fetcher;
-               i_ipmi_request(NULL,
-                              intf,
-                              &addr,
-                              0,
-                              &msg,
-                              intf,
-                              &smi_msg,
-                              &recv_msg,
-                              0,
-                              intf->channels[0].address,
-                              intf->channels[0].lun,
-                              0, 1); /* Don't retry, and don't wait. */
+               ipmi_panic_request_and_wait(intf, &addr, &msg);
 
                if (intf->local_event_generator) {
                        /* Request the event receiver from the local MC. */
@@ -4336,18 +4378,7 @@ static void send_panic_events(char *str)
                        msg.data = NULL;
                        msg.data_len = 0;
                        intf->null_user_handler = event_receiver_fetcher;
-                       i_ipmi_request(NULL,
-                                      intf,
-                                      &addr,
-                                      0,
-                                      &msg,
-                                      intf,
-                                      &smi_msg,
-                                      &recv_msg,
-                                      0,
-                                      intf->channels[0].address,
-                                      intf->channels[0].lun,
-                                      0, 1); /* no retry, and no wait. */
+                       ipmi_panic_request_and_wait(intf, &addr, &msg);
                }
                intf->null_user_handler = NULL;
 
@@ -4404,18 +4435,7 @@ static void send_panic_events(char *str)
                        strncpy(data+5, p, 11);
                        p += size;
 
-                       i_ipmi_request(NULL,
-                                      intf,
-                                      &addr,
-                                      0,
-                                      &msg,
-                                      intf,
-                                      &smi_msg,
-                                      &recv_msg,
-                                      0,
-                                      intf->channels[0].address,
-                                      intf->channels[0].lun,
-                                      0, 1); /* no retry, and no wait. */
+                       ipmi_panic_request_and_wait(intf, &addr, &msg);
                }
        }
 #endif /* CONFIG_IPMI_PANIC_STRING */
index f9fdc114b31dfbdba423491afe58004178693767..1e638fff40ea2cb01d99d33745ae5f6526787237 100644 (file)
@@ -170,7 +170,6 @@ struct smi_info {
        struct si_sm_handlers  *handlers;
        enum si_type           si_type;
        spinlock_t             si_lock;
-       spinlock_t             msg_lock;
        struct list_head       xmit_msgs;
        struct list_head       hp_xmit_msgs;
        struct ipmi_smi_msg    *curr_msg;
@@ -319,16 +318,8 @@ static int register_xaction_notifier(struct notifier_block *nb)
 static void deliver_recv_msg(struct smi_info *smi_info,
                             struct ipmi_smi_msg *msg)
 {
-       /* Deliver the message to the upper layer with the lock
-          released. */
-
-       if (smi_info->run_to_completion) {
-               ipmi_smi_msg_received(smi_info->intf, msg);
-       } else {
-               spin_unlock(&(smi_info->si_lock));
-               ipmi_smi_msg_received(smi_info->intf, msg);
-               spin_lock(&(smi_info->si_lock));
-       }
+       /* Deliver the message to the upper layer. */
+       ipmi_smi_msg_received(smi_info->intf, msg);
 }
 
 static void return_hosed_msg(struct smi_info *smi_info, int cCode)
@@ -357,13 +348,6 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
        struct timeval t;
 #endif
 
-       /*
-        * No need to save flags, we aleady have interrupts off and we
-        * already hold the SMI lock.
-        */
-       if (!smi_info->run_to_completion)
-               spin_lock(&(smi_info->msg_lock));
-
        /* Pick the high priority queue first. */
        if (!list_empty(&(smi_info->hp_xmit_msgs))) {
                entry = smi_info->hp_xmit_msgs.next;
@@ -401,9 +385,6 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
                rv = SI_SM_CALL_WITHOUT_DELAY;
        }
  out:
-       if (!smi_info->run_to_completion)
-               spin_unlock(&(smi_info->msg_lock));
-
        return rv;
 }
 
@@ -480,9 +461,7 @@ static void handle_flags(struct smi_info *smi_info)
 
                start_clear_flags(smi_info);
                smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
-               spin_unlock(&(smi_info->si_lock));
                ipmi_smi_watchdog_pretimeout(smi_info->intf);
-               spin_lock(&(smi_info->si_lock));
        } else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
                /* Messages available. */
                smi_info->curr_msg = ipmi_alloc_smi_msg();
@@ -888,19 +867,6 @@ static void sender(void                *send_info,
        printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
 #endif
 
-       /*
-        * last_timeout_jiffies is updated here to avoid
-        * smi_timeout() handler passing very large time_diff
-        * value to smi_event_handler() that causes
-        * the send command to abort.
-        */
-       smi_info->last_timeout_jiffies = jiffies;
-
-       mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
-
-       if (smi_info->thread)
-               wake_up_process(smi_info->thread);
-
        if (smi_info->run_to_completion) {
                /*
                 * If we are running to completion, then throw it in
@@ -923,16 +889,29 @@ static void sender(void                *send_info,
                return;
        }
 
-       spin_lock_irqsave(&smi_info->msg_lock, flags);
+       spin_lock_irqsave(&smi_info->si_lock, flags);
        if (priority > 0)
                list_add_tail(&msg->link, &smi_info->hp_xmit_msgs);
        else
                list_add_tail(&msg->link, &smi_info->xmit_msgs);
-       spin_unlock_irqrestore(&smi_info->msg_lock, flags);
 
-       spin_lock_irqsave(&smi_info->si_lock, flags);
-       if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL)
+       if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) {
+               /*
+                * last_timeout_jiffies is updated here to avoid
+                * smi_timeout() handler passing very large time_diff
+                * value to smi_event_handler() that causes
+                * the send command to abort.
+                */
+               smi_info->last_timeout_jiffies = jiffies;
+
+               mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
+
+               if (smi_info->thread)
+                       wake_up_process(smi_info->thread);
+
                start_next_msg(smi_info);
+               smi_event_handler(smi_info, 0);
+       }
        spin_unlock_irqrestore(&smi_info->si_lock, flags);
 }
 
@@ -1033,16 +1012,19 @@ static int ipmi_thread(void *data)
 static void poll(void *send_info)
 {
        struct smi_info *smi_info = send_info;
-       unsigned long flags;
+       unsigned long flags = 0;
+       int run_to_completion = smi_info->run_to_completion;
 
        /*
         * Make sure there is some delay in the poll loop so we can
         * drive time forward and timeout things.
         */
        udelay(10);
-       spin_lock_irqsave(&smi_info->si_lock, flags);
+       if (!run_to_completion)
+               spin_lock_irqsave(&smi_info->si_lock, flags);
        smi_event_handler(smi_info, 10);
-       spin_unlock_irqrestore(&smi_info->si_lock, flags);
+       if (!run_to_completion)
+               spin_unlock_irqrestore(&smi_info->si_lock, flags);
 }
 
 static void request_events(void *send_info)
@@ -1679,10 +1661,8 @@ static struct smi_info *smi_info_alloc(void)
 {
        struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
 
-       if (info) {
+       if (info)
                spin_lock_init(&info->si_lock);
-               spin_lock_init(&info->msg_lock);
-       }
        return info;
 }
 
index 020a6aec2d86d70f15b9f27443f39af30f0bf914..7ed356e520351741173757d81270334e10ec4585 100644 (file)
@@ -520,6 +520,7 @@ static void panic_halt_ipmi_heartbeat(void)
        msg.cmd = IPMI_WDOG_RESET_TIMER;
        msg.data = NULL;
        msg.data_len = 0;
+       atomic_add(2, &panic_done_count);
        rv = ipmi_request_supply_msgs(watchdog_user,
                                      (struct ipmi_addr *) &addr,
                                      0,
@@ -528,8 +529,8 @@ static void panic_halt_ipmi_heartbeat(void)
                                      &panic_halt_heartbeat_smi_msg,
                                      &panic_halt_heartbeat_recv_msg,
                                      1);
-       if (!rv)
-               atomic_add(2, &panic_done_count);
+       if (rv)
+               atomic_sub(2, &panic_done_count);
 }
 
 static struct ipmi_smi_msg panic_halt_smi_msg = {
@@ -553,16 +554,18 @@ static void panic_halt_ipmi_set_timeout(void)
        /* Wait for the messages to be free. */
        while (atomic_read(&panic_done_count) != 0)
                ipmi_poll_interface(watchdog_user);
+       atomic_add(2, &panic_done_count);
        rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
                                &panic_halt_recv_msg,
                                &send_heartbeat_now);
-       if (!rv) {
-               atomic_add(2, &panic_done_count);
-               if (send_heartbeat_now)
-                       panic_halt_ipmi_heartbeat();
-       } else
+       if (rv) {
+               atomic_sub(2, &panic_done_count);
                printk(KERN_WARNING PFX
                       "Unable to extend the watchdog timeout.");
+       } else {
+               if (send_heartbeat_now)
+                       panic_halt_ipmi_heartbeat();
+       }
        while (atomic_read(&panic_done_count) != 0)
                ipmi_poll_interface(watchdog_user);
 }
@@ -1164,7 +1167,7 @@ static int wdog_reboot_handler(struct notifier_block *this,
                if (code == SYS_POWER_OFF || code == SYS_HALT) {
                        /* Disable the WDT if we are shutting down. */
                        ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
-                       panic_halt_ipmi_set_timeout();
+                       ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
                } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
                        /* Set a long timer to let the reboot happens, but
                           reboot if it hangs, but only if the watchdog
@@ -1172,7 +1175,7 @@ static int wdog_reboot_handler(struct notifier_block *this,
                        timeout = 120;
                        pretimeout = 0;
                        ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
-                       panic_halt_ipmi_set_timeout();
+                       ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
                }
        }
        return NOTIFY_OK;
index 4c3b2847e47c2a4be430928a63ec88529bbddf77..eed213a5c8cba8f53ae8bdba6e2f6525eedc9657 100644 (file)
@@ -1079,6 +1079,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
        struct mmc_blk_request *brq = &mqrq->brq;
        struct request *req = mqrq->req;
        struct mmc_blk_data *md = mq->data;
+       bool do_data_tag;
 
        /*
         * Reliable writes are used to implement Forced Unit Access and
@@ -1154,6 +1155,16 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
        if (do_rel_wr)
                mmc_apply_rel_rw(brq, card, req);
 
+       /*
+        * Data tag is used only during writing meta data to speed
+        * up write and any subsequent read of this meta data
+        */
+       do_data_tag = (card->ext_csd.data_tag_unit_size) &&
+               (req->cmd_flags & REQ_META) &&
+               (rq_data_dir(req) == WRITE) &&
+               ((brq->data.blocks * brq->data.blksz) >=
+                card->ext_csd.data_tag_unit_size);
+
        /*
         * Pre-defined multi-block transfers are preferable to
         * open ended-ones (and necessary for reliable writes).
@@ -1172,13 +1183,13 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
         * We'll avoid using CMD23-bounded multiblock writes for
         * these, while retaining features like reliable writes.
         */
-
-       if ((md->flags & MMC_BLK_CMD23) &&
-           mmc_op_multi(brq->cmd.opcode) &&
-           (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
+       if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) &&
+           (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) ||
+            do_data_tag)) {
                brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
                brq->sbc.arg = brq->data.blocks |
-                       (do_rel_wr ? (1 << 31) : 0);
+                       (do_rel_wr ? (1 << 31) : 0) |
+                       (do_data_tag ? (1 << 29) : 0);
                brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
                brq->mrq.sbc = &brq->sbc;
        }
index 082202ae4a03cbc9fb5a4a32f3276e27bec98508..29de31e260dda56da18d0345f15a3886c6c1063a 100644 (file)
@@ -28,13 +28,17 @@ static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio,
-                       unsigned int irq, unsigned long flags)
+int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio)
 {
        size_t len = strlen(dev_name(host->parent)) + 4;
-       struct mmc_cd_gpio *cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
+       struct mmc_cd_gpio *cd;
+       int irq = gpio_to_irq(gpio);
        int ret;
 
+       if (irq < 0)
+               return irq;
+
+       cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
        if (!cd)
                return -ENOMEM;
 
@@ -45,7 +49,8 @@ int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio,
                goto egpioreq;
 
        ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt,
-                                  flags, cd->label, host);
+                                  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                                  cd->label, host);
        if (ret < 0)
                goto eirqreq;
 
index 132378b89d76a0072fe31b7f436975525d04e353..14f262e9246d7a853ad2e1d78ce561e1c51d58c2 100644 (file)
@@ -188,6 +188,12 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
        struct scatterlist *sg;
 #endif
 
+       if (mrq->sbc) {
+               pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
+                        mmc_hostname(host), mrq->sbc->opcode,
+                        mrq->sbc->arg, mrq->sbc->flags);
+       }
+
        pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
                 mmc_hostname(host), mrq->cmd->opcode,
                 mrq->cmd->arg, mrq->cmd->flags);
@@ -243,16 +249,17 @@ static void mmc_wait_done(struct mmc_request *mrq)
        complete(&mrq->completion);
 }
 
-static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
+static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
 {
        init_completion(&mrq->completion);
        mrq->done = mmc_wait_done;
        if (mmc_card_removed(host->card)) {
                mrq->cmd->error = -ENOMEDIUM;
                complete(&mrq->completion);
-               return;
+               return -ENOMEDIUM;
        }
        mmc_start_request(host, mrq);
+       return 0;
 }
 
 static void mmc_wait_for_req_done(struct mmc_host *host,
@@ -336,6 +343,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
                                    struct mmc_async_req *areq, int *error)
 {
        int err = 0;
+       int start_err = 0;
        struct mmc_async_req *data = host->areq;
 
        /* Prepare a new request */
@@ -345,30 +353,23 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
        if (host->areq) {
                mmc_wait_for_req_done(host, host->areq->mrq);
                err = host->areq->err_check(host->card, host->areq);
-               if (err) {
-                       /* post process the completed failed request */
-                       mmc_post_req(host, host->areq->mrq, 0);
-                       if (areq)
-                               /*
-                                * Cancel the new prepared request, because
-                                * it can't run until the failed
-                                * request has been properly handled.
-                                */
-                               mmc_post_req(host, areq->mrq, -EINVAL);
-
-                       host->areq = NULL;
-                       goto out;
-               }
        }
 
-       if (areq)
-               __mmc_start_req(host, areq->mrq);
+       if (!err && areq)
+               start_err = __mmc_start_req(host, areq->mrq);
 
        if (host->areq)
                mmc_post_req(host, host->areq->mrq, 0);
 
-       host->areq = areq;
- out:
+        /* Cancel a prepared request if it was not started. */
+       if ((err || start_err) && areq)
+                       mmc_post_req(host, areq->mrq, -EINVAL);
+
+       if (err)
+               host->areq = NULL;
+       else
+               host->areq = areq;
+
        if (error)
                *error = err;
        return data;
@@ -598,105 +599,6 @@ unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
 }
 EXPORT_SYMBOL(mmc_align_data_size);
 
-/**
- *     mmc_host_enable - enable a host.
- *     @host: mmc host to enable
- *
- *     Hosts that support power saving can use the 'enable' and 'disable'
- *     methods to exit and enter power saving states. For more information
- *     see comments for struct mmc_host_ops.
- */
-int mmc_host_enable(struct mmc_host *host)
-{
-       if (!(host->caps & MMC_CAP_DISABLE))
-               return 0;
-
-       if (host->en_dis_recurs)
-               return 0;
-
-       if (host->nesting_cnt++)
-               return 0;
-
-       cancel_delayed_work_sync(&host->disable);
-
-       if (host->enabled)
-               return 0;
-
-       if (host->ops->enable) {
-               int err;
-
-               host->en_dis_recurs = 1;
-               mmc_host_clk_hold(host);
-               err = host->ops->enable(host);
-               mmc_host_clk_release(host);
-               host->en_dis_recurs = 0;
-
-               if (err) {
-                       pr_debug("%s: enable error %d\n",
-                                mmc_hostname(host), err);
-                       return err;
-               }
-       }
-       host->enabled = 1;
-       return 0;
-}
-EXPORT_SYMBOL(mmc_host_enable);
-
-static int mmc_host_do_disable(struct mmc_host *host, int lazy)
-{
-       if (host->ops->disable) {
-               int err;
-
-               host->en_dis_recurs = 1;
-               mmc_host_clk_hold(host);
-               err = host->ops->disable(host, lazy);
-               mmc_host_clk_release(host);
-               host->en_dis_recurs = 0;
-
-               if (err < 0) {
-                       pr_debug("%s: disable error %d\n",
-                                mmc_hostname(host), err);
-                       return err;
-               }
-               if (err > 0) {
-                       unsigned long delay = msecs_to_jiffies(err);
-
-                       mmc_schedule_delayed_work(&host->disable, delay);
-               }
-       }
-       host->enabled = 0;
-       return 0;
-}
-
-/**
- *     mmc_host_disable - disable a host.
- *     @host: mmc host to disable
- *
- *     Hosts that support power saving can use the 'enable' and 'disable'
- *     methods to exit and enter power saving states. For more information
- *     see comments for struct mmc_host_ops.
- */
-int mmc_host_disable(struct mmc_host *host)
-{
-       int err;
-
-       if (!(host->caps & MMC_CAP_DISABLE))
-               return 0;
-
-       if (host->en_dis_recurs)
-               return 0;
-
-       if (--host->nesting_cnt)
-               return 0;
-
-       if (!host->enabled)
-               return 0;
-
-       err = mmc_host_do_disable(host, 0);
-       return err;
-}
-EXPORT_SYMBOL(mmc_host_disable);
-
 /**
  *     __mmc_claim_host - exclusively claim a host
  *     @host: mmc host to claim
@@ -735,8 +637,8 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
                wake_up(&host->wq);
        spin_unlock_irqrestore(&host->lock, flags);
        remove_wait_queue(&host->wq, &wait);
-       if (!stop)
-               mmc_host_enable(host);
+       if (host->ops->enable && !stop && host->claim_cnt == 1)
+               host->ops->enable(host);
        return stop;
 }
 
@@ -761,21 +663,28 @@ int mmc_try_claim_host(struct mmc_host *host)
                claimed_host = 1;
        }
        spin_unlock_irqrestore(&host->lock, flags);
+       if (host->ops->enable && claimed_host && host->claim_cnt == 1)
+               host->ops->enable(host);
        return claimed_host;
 }
 EXPORT_SYMBOL(mmc_try_claim_host);
 
 /**
- *     mmc_do_release_host - release a claimed host
+ *     mmc_release_host - release a host
  *     @host: mmc host to release
  *
- *     If you successfully claimed a host, this function will
- *     release it again.
+ *     Release a MMC host, allowing others to claim the host
+ *     for their operations.
  */
-void mmc_do_release_host(struct mmc_host *host)
+void mmc_release_host(struct mmc_host *host)
 {
        unsigned long flags;
 
+       WARN_ON(!host->claimed);
+
+       if (host->ops->disable && host->claim_cnt == 1)
+               host->ops->disable(host);
+
        spin_lock_irqsave(&host->lock, flags);
        if (--host->claim_cnt) {
                /* Release for nested claim */
@@ -787,67 +696,6 @@ void mmc_do_release_host(struct mmc_host *host)
                wake_up(&host->wq);
        }
 }
-EXPORT_SYMBOL(mmc_do_release_host);
-
-void mmc_host_deeper_disable(struct work_struct *work)
-{
-       struct mmc_host *host =
-               container_of(work, struct mmc_host, disable.work);
-
-       /* If the host is claimed then we do not want to disable it anymore */
-       if (!mmc_try_claim_host(host))
-               return;
-       mmc_host_do_disable(host, 1);
-       mmc_do_release_host(host);
-}
-
-/**
- *     mmc_host_lazy_disable - lazily disable a host.
- *     @host: mmc host to disable
- *
- *     Hosts that support power saving can use the 'enable' and 'disable'
- *     methods to exit and enter power saving states. For more information
- *     see comments for struct mmc_host_ops.
- */
-int mmc_host_lazy_disable(struct mmc_host *host)
-{
-       if (!(host->caps & MMC_CAP_DISABLE))
-               return 0;
-
-       if (host->en_dis_recurs)
-               return 0;
-
-       if (--host->nesting_cnt)
-               return 0;
-
-       if (!host->enabled)
-               return 0;
-
-       if (host->disable_delay) {
-               mmc_schedule_delayed_work(&host->disable,
-                               msecs_to_jiffies(host->disable_delay));
-               return 0;
-       } else
-               return mmc_host_do_disable(host, 1);
-}
-EXPORT_SYMBOL(mmc_host_lazy_disable);
-
-/**
- *     mmc_release_host - release a host
- *     @host: mmc host to release
- *
- *     Release a MMC host, allowing others to claim the host
- *     for their operations.
- */
-void mmc_release_host(struct mmc_host *host)
-{
-       WARN_ON(!host->claimed);
-
-       mmc_host_lazy_disable(host);
-
-       mmc_do_release_host(host);
-}
-
 EXPORT_SYMBOL(mmc_release_host);
 
 /*
@@ -2115,18 +1963,36 @@ int _mmc_detect_card_removed(struct mmc_host *host)
 int mmc_detect_card_removed(struct mmc_host *host)
 {
        struct mmc_card *card = host->card;
+       int ret;
 
        WARN_ON(!host->claimed);
+
+       if (!card)
+               return 1;
+
+       ret = mmc_card_removed(card);
        /*
         * The card will be considered unchanged unless we have been asked to
         * detect a change or host requires polling to provide card detection.
         */
-       if (card && !host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
-               return mmc_card_removed(card);
+       if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) &&
+           !(host->caps2 & MMC_CAP2_DETECT_ON_ERR))
+               return ret;
 
        host->detect_change = 0;
+       if (!ret) {
+               ret = _mmc_detect_card_removed(host);
+               if (ret && (host->caps2 & MMC_CAP2_DETECT_ON_ERR)) {
+                       /*
+                        * Schedule a detect work as soon as possible to let a
+                        * rescan handle the card removal.
+                        */
+                       cancel_delayed_work(&host->detect);
+                       mmc_detect_change(host, 0);
+               }
+       }
 
-       return _mmc_detect_card_removed(host);
+       return ret;
 }
 EXPORT_SYMBOL(mmc_detect_card_removed);
 
@@ -2203,8 +2069,6 @@ void mmc_stop_host(struct mmc_host *host)
        spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
-       if (host->caps & MMC_CAP_DISABLE)
-               cancel_delayed_work(&host->disable);
        cancel_delayed_work_sync(&host->detect);
        mmc_flush_scheduled_work();
 
@@ -2399,13 +2263,11 @@ int mmc_suspend_host(struct mmc_host *host)
 {
        int err = 0;
 
-       if (host->caps & MMC_CAP_DISABLE)
-               cancel_delayed_work(&host->disable);
        cancel_delayed_work(&host->detect);
        mmc_flush_scheduled_work();
        if (mmc_try_claim_host(host)) {
                err = mmc_cache_ctrl(host, 0);
-               mmc_do_release_host(host);
+               mmc_release_host(host);
        } else {
                err = -EBUSY;
        }
@@ -2426,7 +2288,7 @@ int mmc_suspend_host(struct mmc_host *host)
                        if (host->bus_ops->suspend) {
                                err = host->bus_ops->suspend(host);
                        }
-                       mmc_do_release_host(host);
+                       mmc_release_host(host);
 
                        if (err == -ENOSYS || !host->bus_ops->resume) {
                                /*
index c3704e293a7b30d52c9cc1893da88a0e4844131b..91c84c7a1829e8693c4e9dc652758512df22b4d6 100644 (file)
@@ -330,7 +330,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
        spin_lock_init(&host->lock);
        init_waitqueue_head(&host->wq);
        INIT_DELAYED_WORK(&host->detect, mmc_rescan);
-       INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
 #ifdef CONFIG_PM
        host->pm_notify.notifier_call = mmc_pm_notify;
 #endif
index 08a7852ade448a126d56d0034ba9b0965206b7a5..f2ab9e5781265c29e1e62c6eaafb4618019532b9 100644 (file)
@@ -14,7 +14,6 @@
 
 int mmc_register_host_class(void);
 void mmc_unregister_host_class(void);
-void mmc_host_deeper_disable(struct work_struct *work);
 
 #endif
 
index 2b9ed1401dc439bf1dd29e4aa751f74e0175bc93..02914d609a91ab3d28577aed913702e119a695f6 100644 (file)
@@ -519,6 +519,20 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                        ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
                        ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
                        ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
+
+               if (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 1)
+                       card->ext_csd.data_sector_size = 4096;
+               else
+                       card->ext_csd.data_sector_size = 512;
+
+               if ((ext_csd[EXT_CSD_DATA_TAG_SUPPORT] & 1) &&
+                   (ext_csd[EXT_CSD_TAG_UNIT_SIZE] <= 8)) {
+                       card->ext_csd.data_tag_unit_size =
+                       ((unsigned int) 1 << ext_csd[EXT_CSD_TAG_UNIT_SIZE]) *
+                       (card->ext_csd.data_sector_size);
+               } else {
+                       card->ext_csd.data_tag_unit_size = 0;
+               }
        }
 
 out:
@@ -938,7 +952,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF
         * bit.  This bit will be lost every time after a reset or power off.
         */
-       if (card->ext_csd.enhanced_area_en) {
+       if (card->ext_csd.enhanced_area_en ||
+           (card->ext_csd.rev >= 3 && (host->caps2 & MMC_CAP2_HC_ERASE_SZ))) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                 EXT_CSD_ERASE_GROUP_DEF, 1,
                                 card->ext_csd.generic_cmd6_time);
@@ -1032,22 +1047,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
        }
 
-       /*
-        * Enable HPI feature (if supported)
-        */
-       if (card->ext_csd.hpi) {
-               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                       EXT_CSD_HPI_MGMT, 1, 0);
-               if (err && err != -EBADMSG)
-                       goto free_card;
-               if (err) {
-                       pr_warning("%s: Enabling HPI failed\n",
-                                  mmc_hostname(card->host));
-                       err = 0;
-               } else
-                       card->ext_csd.hpi_en = 1;
-       }
-
        /*
         * Compute bus speed.
         */
@@ -1097,9 +1096,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                 * 4. execute tuning for HS200
                 */
                if ((host->caps2 & MMC_CAP2_HS200) &&
-                   card->host->ops->execute_tuning)
+                   card->host->ops->execute_tuning) {
+                       mmc_host_clk_hold(card->host);
                        err = card->host->ops->execute_tuning(card->host,
                                MMC_SEND_TUNING_BLOCK_HS200);
+                       mmc_host_clk_release(card->host);
+               }
                if (err) {
                        pr_warning("%s: tuning execution failed\n",
                                   mmc_hostname(card->host));
@@ -1218,6 +1220,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
        }
 
+       /*
+        * Enable HPI feature (if supported)
+        */
+       if (card->ext_csd.hpi) {
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                               EXT_CSD_HPI_MGMT, 1,
+                               card->ext_csd.generic_cmd6_time);
+               if (err && err != -EBADMSG)
+                       goto free_card;
+               if (err) {
+                       pr_warning("%s: Enabling HPI failed\n",
+                                  mmc_hostname(card->host));
+                       err = 0;
+               } else
+                       card->ext_csd.hpi_en = 1;
+       }
+
        /*
         * If cache size is higher than 0, this indicates
         * the existence of cache and it can be turned on.
index 4d41fa984c9344d007a1df43898f25a18c0a4e91..69370f494e054f7951d287bba8b1d570510dc33d 100644 (file)
@@ -553,18 +553,22 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
 {
        struct mmc_command cmd = {0};
        unsigned int opcode;
-       unsigned int flags;
        int err;
 
+       if (!card->ext_csd.hpi) {
+               pr_warning("%s: Card didn't support HPI command\n",
+                          mmc_hostname(card->host));
+               return -EINVAL;
+       }
+
        opcode = card->ext_csd.hpi_cmd;
        if (opcode == MMC_STOP_TRANSMISSION)
-               flags = MMC_RSP_R1 | MMC_CMD_AC;
+               cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
        else if (opcode == MMC_SEND_STATUS)
-               flags = MMC_RSP_R1 | MMC_CMD_AC;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
        cmd.opcode = opcode;
        cmd.arg = card->rca << 16 | 1;
-       cmd.flags = flags;
        cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
 
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
index ecbee9bf87b2ef00cf18f54ff6968fe4f2616adf..2bc06e7344db5970c754ab6cbf0a849830d8339f 100644 (file)
@@ -533,6 +533,31 @@ config MMC_DW_IDMAC
          Designware Mobile Storage IP block. This disables the external DMA
          interface.
 
+config MMC_DW_PLTFM
+       tristate "Synopsys Designware MCI Support as platform device"
+       depends on MMC_DW
+       default y
+       help
+         This selects the common helper functions support for Host Controller
+         Interface based platform driver. Please select this option if the IP
+         is present as a platform device. This is the common interface for the
+         Synopsys Designware IP.
+
+         If you have a controller with this interface, say Y or M here.
+
+         If unsure, say Y.
+
+config MMC_DW_PCI
+       tristate "Synopsys Designware MCI support on PCI bus"
+       depends on MMC_DW && PCI
+       help
+         This selects the PCI bus for the Synopsys Designware Mobile Storage IP.
+         Select this option if the IP is present on PCI platform.
+
+         If you have a controller with this interface, say Y or M here.
+
+         If unsure, say N.
+
 config MMC_SH_MMCIF
        tristate "SuperH Internal MMCIF support"
        depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE)
index 745f8fce251986278b408951fd1d5b4a12015893..3e7e26d0807346a82353544a0623086ce4249409 100644 (file)
@@ -39,6 +39,8 @@ obj-$(CONFIG_MMC_CB710)               += cb710-mmc.o
 obj-$(CONFIG_MMC_VIA_SDMMC)    += via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)         += bfin_sdh.o
 obj-$(CONFIG_MMC_DW)           += dw_mmc.o
+obj-$(CONFIG_MMC_DW_PLTFM)     += dw_mmc-pltfm.o
+obj-$(CONFIG_MMC_DW_PCI)       += dw_mmc-pci.o
 obj-$(CONFIG_MMC_SH_MMCIF)     += sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)       += jz4740_mmc.o
 obj-$(CONFIG_MMC_VUB300)       += vub300.o
index e4449a54ae8f9fc68c3d9f719fe3a09e3e028adf..390863e7efbde4bb4ba37e210a1e694438b12cdd 100644 (file)
@@ -1975,7 +1975,7 @@ static bool atmci_configure_dma(struct atmel_mci *host)
                return false;
        } else {
                dev_info(&host->pdev->dev,
-                                       "Using %s for DMA transfers\n",
+                                       "using %s for DMA transfers\n",
                                        dma_chan_name(host->dma.chan));
                return true;
        }
index 64a8325a4a8af8f590204e1f38441128eab7e9bd..c1f3673ae1efa9df281bbb88687029af24309f29 100644 (file)
@@ -160,6 +160,16 @@ module_param(rw_threshold, uint, S_IRUGO);
 MODULE_PARM_DESC(rw_threshold,
                "Read/Write threshold. Default = 32");
 
+static unsigned poll_threshold = 128;
+module_param(poll_threshold, uint, S_IRUGO);
+MODULE_PARM_DESC(poll_threshold,
+                "Polling transaction size threshold. Default = 128");
+
+static unsigned poll_loopcount = 32;
+module_param(poll_loopcount, uint, S_IRUGO);
+MODULE_PARM_DESC(poll_loopcount,
+                "Maximum polling loop count. Default = 32");
+
 static unsigned __initdata use_dma = 1;
 module_param(use_dma, uint, 0);
 MODULE_PARM_DESC(use_dma, "Whether to use DMA or not. Default = 1");
@@ -193,6 +203,7 @@ struct mmc_davinci_host {
        bool use_dma;
        bool do_dma;
        bool sdio_int;
+       bool active_request;
 
        /* Scatterlist DMA uses one or more parameter RAM entries:
         * the main one (associated with rxdma or txdma) plus zero or
@@ -219,6 +230,7 @@ struct mmc_davinci_host {
 #endif
 };
 
+static irqreturn_t mmc_davinci_irq(int irq, void *dev_id);
 
 /* PIO only */
 static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
@@ -376,7 +388,20 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host,
 
        writel(cmd->arg, host->base + DAVINCI_MMCARGHL);
        writel(cmd_reg,  host->base + DAVINCI_MMCCMD);
-       writel(im_val, host->base + DAVINCI_MMCIM);
+
+       host->active_request = true;
+
+       if (!host->do_dma && host->bytes_left <= poll_threshold) {
+               u32 count = poll_loopcount;
+
+               while (host->active_request && count--) {
+                       mmc_davinci_irq(0, host);
+                       cpu_relax();
+               }
+       }
+
+       if (host->active_request)
+               writel(im_val, host->base + DAVINCI_MMCIM);
 }
 
 /*----------------------------------------------------------------------*/
@@ -915,6 +940,7 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
        if (!data->stop || (host->cmd && host->cmd->error)) {
                mmc_request_done(host->mmc, data->mrq);
                writel(0, host->base + DAVINCI_MMCIM);
+               host->active_request = false;
        } else
                mmc_davinci_start_command(host, data->stop);
 }
@@ -942,6 +968,7 @@ static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
                        cmd->mrq->cmd->retries = 0;
                mmc_request_done(host->mmc, cmd->mrq);
                writel(0, host->base + DAVINCI_MMCIM);
+               host->active_request = false;
        }
 }
 
@@ -1009,12 +1036,33 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
         * by read. So, it is not unbouned loop even in the case of
         * non-dma.
         */
-       while (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) {
-               davinci_fifo_data_trans(host, rw_threshold);
-               status = readl(host->base + DAVINCI_MMCST0);
-               if (!status)
-                       break;
-               qstatus |= status;
+       if (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) {
+               unsigned long im_val;
+
+               /*
+                * If interrupts fire during the following loop, they will be
+                * handled by the handler, but the PIC will still buffer these.
+                * As a result, the handler will be called again to serve these
+                * needlessly. In order to avoid these spurious interrupts,
+                * keep interrupts masked during the loop.
+                */
+               im_val = readl(host->base + DAVINCI_MMCIM);
+               writel(0, host->base + DAVINCI_MMCIM);
+
+               do {
+                       davinci_fifo_data_trans(host, rw_threshold);
+                       status = readl(host->base + DAVINCI_MMCST0);
+                       qstatus |= status;
+               } while (host->bytes_left &&
+                        (status & (MMCST0_DXRDY | MMCST0_DRRDY)));
+
+               /*
+                * If an interrupt is pending, it is assumed it will fire when
+                * it is unmasked. This assumption is also taken when the MMCIM
+                * is first set. Otherwise, writing to MMCIM after reading the
+                * status is race-prone.
+                */
+               writel(im_val, host->base + DAVINCI_MMCIM);
        }
 
        if (qstatus & MMCST0_DATDNE) {
@@ -1418,17 +1466,14 @@ static int davinci_mmcsd_suspend(struct device *dev)
        struct mmc_davinci_host *host = platform_get_drvdata(pdev);
        int ret;
 
-       mmc_host_enable(host->mmc);
        ret = mmc_suspend_host(host->mmc);
        if (!ret) {
                writel(0, host->base + DAVINCI_MMCIM);
                mmc_davinci_reset_ctrl(host, 1);
-               mmc_host_disable(host->mmc);
                clk_disable(host->clk);
                host->suspended = 1;
        } else {
                host->suspended = 0;
-               mmc_host_disable(host->mmc);
        }
 
        return ret;
@@ -1444,7 +1489,6 @@ static int davinci_mmcsd_resume(struct device *dev)
                return 0;
 
        clk_enable(host->clk);
-       mmc_host_enable(host->mmc);
 
        mmc_davinci_reset_ctrl(host, 0);
        ret = mmc_resume_host(host->mmc);
diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c
new file mode 100644 (file)
index 0000000..dc0d25a
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Synopsys DesignWare Multimedia Card PCI Interface driver
+ *
+ * Copyright (C) 2012 Vayavya Labs Pvt. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/dw_mmc.h>
+#include "dw_mmc.h"
+
+#define PCI_BAR_NO 2
+#define COMPLETE_BAR 0
+#define SYNOPSYS_DW_MCI_VENDOR_ID 0x700
+#define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107
+/* Defining the Capabilities */
+#define DW_MCI_CAPABILITIES (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |\
+                               MMC_CAP_SD_HIGHSPEED | MMC_CAP_8_BIT_DATA |\
+                               MMC_CAP_SDIO_IRQ)
+
+static struct dw_mci_board pci_board_data = {
+       .num_slots                      = 1,
+       .caps                           = DW_MCI_CAPABILITIES,
+       .bus_hz                         = 33 * 1000 * 1000,
+       .detect_delay_ms                = 200,
+       .fifo_depth                     = 32,
+};
+
+static int __devinit dw_mci_pci_probe(struct pci_dev *pdev,
+                                 const struct pci_device_id *entries)
+{
+       struct dw_mci *host;
+       int ret;
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
+       if (pci_request_regions(pdev, "dw_mmc_pci")) {
+               ret = -ENODEV;
+               goto err_disable_dev;
+       }
+
+       host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
+       if (!host) {
+               ret = -ENOMEM;
+               goto err_release;
+       }
+
+       host->irq = pdev->irq;
+       host->irq_flags = IRQF_SHARED;
+       host->dev = pdev->dev;
+       host->pdata = &pci_board_data;
+
+       host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR);
+       if (!host->regs) {
+               ret = -EIO;
+               goto err_unmap;
+       }
+
+       pci_set_drvdata(pdev, host);
+       ret = dw_mci_probe(host);
+       if (ret)
+               goto err_probe_failed;
+       return ret;
+
+err_probe_failed:
+       pci_iounmap(pdev, host->regs);
+err_unmap:
+       kfree(host);
+err_release:
+       pci_release_regions(pdev);
+err_disable_dev:
+       pci_disable_device(pdev);
+       return ret;
+}
+
+static void __devexit dw_mci_pci_remove(struct pci_dev *pdev)
+{
+       struct dw_mci *host = pci_get_drvdata(pdev);
+
+       dw_mci_remove(host);
+       pci_set_drvdata(pdev, NULL);
+       pci_release_regions(pdev);
+       pci_iounmap(pdev, host->regs);
+       kfree(host);
+       pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dw_mci_pci_suspend(struct device *dev)
+{
+       int ret;
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct dw_mci *host = pci_get_drvdata(pdev);
+
+       ret = dw_mci_suspend(host);
+       return ret;
+}
+
+static int dw_mci_pci_resume(struct device *dev)
+{
+       int ret;
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct dw_mci *host = pci_get_drvdata(pdev);
+
+       ret = dw_mci_resume(host);
+       return ret;
+}
+#else
+#define dw_mci_pci_suspend     NULL
+#define dw_mci_pci_resume      NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(dw_mci_pci_pmops, dw_mci_pci_suspend, dw_mci_pci_resume);
+
+static DEFINE_PCI_DEVICE_TABLE(dw_mci_pci_id) = {
+       { PCI_DEVICE(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) },
+       {}
+};
+MODULE_DEVICE_TABLE(pci, dw_mci_pci_id);
+
+static struct pci_driver dw_mci_pci_driver = {
+       .name           = "dw_mmc_pci",
+       .id_table       = dw_mci_pci_id,
+       .probe          = dw_mci_pci_probe,
+       .remove         = dw_mci_pci_remove,
+       .driver         =       {
+               .pm =   &dw_mci_pci_pmops
+       },
+};
+
+static int __init dw_mci_init(void)
+{
+       return pci_register_driver(&dw_mci_pci_driver);
+}
+
+static void __exit dw_mci_exit(void)
+{
+       pci_unregister_driver(&dw_mci_pci_driver);
+}
+
+module_init(dw_mci_init);
+module_exit(dw_mci_exit);
+
+MODULE_DESCRIPTION("DW Multimedia Card PCI Interface driver");
+MODULE_AUTHOR("Shashidhar Hiremath <shashidharh@vayavyalabs.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
new file mode 100644 (file)
index 0000000..92ec3eb
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Synopsys DesignWare Multimedia Card Interface driver
+ *
+ * Copyright (C) 2009 NXP Semiconductors
+ * Copyright (C) 2009, 2010 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/dw_mmc.h>
+#include "dw_mmc.h"
+
+static int dw_mci_pltfm_probe(struct platform_device *pdev)
+{
+       struct dw_mci *host;
+       struct resource *regs;
+       int ret;
+
+       host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
+       if (!host)
+               return -ENOMEM;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!regs) {
+               ret = -ENXIO;
+               goto err_free;
+       }
+
+       host->irq = platform_get_irq(pdev, 0);
+       if (host->irq < 0) {
+               ret = host->irq;
+               goto err_free;
+       }
+
+       host->dev = pdev->dev;
+       host->irq_flags = 0;
+       host->pdata = pdev->dev.platform_data;
+       ret = -ENOMEM;
+       host->regs = ioremap(regs->start, resource_size(regs));
+       if (!host->regs)
+               goto err_free;
+       platform_set_drvdata(pdev, host);
+       ret = dw_mci_probe(host);
+       if (ret)
+               goto err_out;
+       return ret;
+err_out:
+       iounmap(host->regs);
+err_free:
+       kfree(host);
+       return ret;
+}
+
+static int __exit dw_mci_pltfm_remove(struct platform_device *pdev)
+{
+       struct dw_mci *host = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       dw_mci_remove(host);
+       iounmap(host->regs);
+       kfree(host);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * TODO: we should probably disable the clock to the card in the suspend path.
+ */
+static int dw_mci_pltfm_suspend(struct device *dev)
+{
+       int ret;
+       struct dw_mci *host = dev_get_drvdata(dev);
+
+       ret = dw_mci_suspend(host);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int dw_mci_pltfm_resume(struct device *dev)
+{
+       int ret;
+       struct dw_mci *host = dev_get_drvdata(dev);
+
+       ret = dw_mci_resume(host);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+#else
+#define dw_mci_pltfm_suspend   NULL
+#define dw_mci_pltfm_resume    NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume);
+
+static struct platform_driver dw_mci_pltfm_driver = {
+       .remove         = __exit_p(dw_mci_pltfm_remove),
+       .driver         = {
+               .name           = "dw_mmc",
+               .pm             = &dw_mci_pltfm_pmops,
+       },
+};
+
+static int __init dw_mci_init(void)
+{
+       return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe);
+}
+
+static void __exit dw_mci_exit(void)
+{
+       platform_driver_unregister(&dw_mci_pltfm_driver);
+}
+
+module_init(dw_mci_init);
+module_exit(dw_mci_exit);
+
+MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
+MODULE_AUTHOR("NXP Semiconductor VietNam");
+MODULE_AUTHOR("Imagination Technologies Ltd");
+MODULE_LICENSE("GPL v2");
index 8bec1c36b159159593bcad0263f0bca2787d4b92..bf3c9b456aaf1080d6db5163eacefb3e7805787a 100644 (file)
@@ -268,7 +268,7 @@ static void dw_mci_start_command(struct dw_mci *host,
                                 struct mmc_command *cmd, u32 cmd_flags)
 {
        host->cmd = cmd;
-       dev_vdbg(&host->pdev->dev,
+       dev_vdbg(&host->dev,
                 "start command: ARGR=0x%08x CMDR=0x%08x\n",
                 cmd->arg, cmd_flags);
 
@@ -295,15 +295,25 @@ static void dw_mci_stop_dma(struct dw_mci *host)
        }
 }
 
+static int dw_mci_get_dma_dir(struct mmc_data *data)
+{
+       if (data->flags & MMC_DATA_WRITE)
+               return DMA_TO_DEVICE;
+       else
+               return DMA_FROM_DEVICE;
+}
+
 #ifdef CONFIG_MMC_DW_IDMAC
 static void dw_mci_dma_cleanup(struct dw_mci *host)
 {
        struct mmc_data *data = host->data;
 
        if (data)
-               dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
-                            ((data->flags & MMC_DATA_WRITE)
-                             ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+               if (!data->host_cookie)
+                       dma_unmap_sg(&host->dev,
+                                    data->sg,
+                                    data->sg_len,
+                                    dw_mci_get_dma_dir(data));
 }
 
 static void dw_mci_idmac_stop_dma(struct dw_mci *host)
@@ -326,7 +336,7 @@ static void dw_mci_idmac_complete_dma(struct dw_mci *host)
 {
        struct mmc_data *data = host->data;
 
-       dev_vdbg(&host->pdev->dev, "DMA complete\n");
+       dev_vdbg(&host->dev, "DMA complete\n");
 
        host->dma_ops->cleanup(host);
 
@@ -428,17 +438,15 @@ static struct dw_mci_dma_ops dw_mci_idmac_ops = {
 };
 #endif /* CONFIG_MMC_DW_IDMAC */
 
-static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
+static int dw_mci_pre_dma_transfer(struct dw_mci *host,
+                                  struct mmc_data *data,
+                                  bool next)
 {
        struct scatterlist *sg;
-       unsigned int i, direction, sg_len;
-       u32 temp;
+       unsigned int i, sg_len;
 
-       host->using_dma = 0;
-
-       /* If we don't have a channel, we can't do DMA */
-       if (!host->use_dma)
-               return -ENODEV;
+       if (!next && data->host_cookie)
+               return data->host_cookie;
 
        /*
         * We don't do DMA on "complex" transfers, i.e. with
@@ -447,6 +455,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
         */
        if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
                return -EINVAL;
+
        if (data->blksz & 3)
                return -EINVAL;
 
@@ -455,17 +464,74 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
                        return -EINVAL;
        }
 
-       host->using_dma = 1;
+       sg_len = dma_map_sg(&host->dev,
+                           data->sg,
+                           data->sg_len,
+                           dw_mci_get_dma_dir(data));
+       if (sg_len == 0)
+               return -EINVAL;
 
-       if (data->flags & MMC_DATA_READ)
-               direction = DMA_FROM_DEVICE;
-       else
-               direction = DMA_TO_DEVICE;
+       if (next)
+               data->host_cookie = sg_len;
 
-       sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
-                           direction);
+       return sg_len;
+}
 
-       dev_vdbg(&host->pdev->dev,
+static void dw_mci_pre_req(struct mmc_host *mmc,
+                          struct mmc_request *mrq,
+                          bool is_first_req)
+{
+       struct dw_mci_slot *slot = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+
+       if (!slot->host->use_dma || !data)
+               return;
+
+       if (data->host_cookie) {
+               data->host_cookie = 0;
+               return;
+       }
+
+       if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
+               data->host_cookie = 0;
+}
+
+static void dw_mci_post_req(struct mmc_host *mmc,
+                           struct mmc_request *mrq,
+                           int err)
+{
+       struct dw_mci_slot *slot = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+
+       if (!slot->host->use_dma || !data)
+               return;
+
+       if (data->host_cookie)
+               dma_unmap_sg(&slot->host->dev,
+                            data->sg,
+                            data->sg_len,
+                            dw_mci_get_dma_dir(data));
+       data->host_cookie = 0;
+}
+
+static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
+{
+       int sg_len;
+       u32 temp;
+
+       host->using_dma = 0;
+
+       /* If we don't have a channel, we can't do DMA */
+       if (!host->use_dma)
+               return -ENODEV;
+
+       sg_len = dw_mci_pre_dma_transfer(host, data, 0);
+       if (sg_len < 0)
+               return sg_len;
+
+       host->using_dma = 1;
+
+       dev_vdbg(&host->dev,
                 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
                 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
                 sg_len);
@@ -579,8 +645,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot)
                             SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
 
                /* enable clock */
-               mci_writel(host, CLKENA, SDMMC_CLKEN_ENABLE |
-                          SDMMC_CLKEN_LOW_PWR);
+               mci_writel(host, CLKENA, ((SDMMC_CLKEN_ENABLE |
+                          SDMMC_CLKEN_LOW_PWR) << slot->id));
 
                /* inform CIU */
                mci_send_cmd(slot,
@@ -800,6 +866,8 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
 
 static const struct mmc_host_ops dw_mci_ops = {
        .request                = dw_mci_request,
+       .pre_req                = dw_mci_pre_req,
+       .post_req               = dw_mci_post_req,
        .set_ios                = dw_mci_set_ios,
        .get_ro                 = dw_mci_get_ro,
        .get_cd                 = dw_mci_get_cd,
@@ -821,12 +889,12 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
                slot = list_entry(host->queue.next,
                                  struct dw_mci_slot, queue_node);
                list_del(&slot->queue_node);
-               dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
+               dev_vdbg(&host->dev, "list not empty: %s is next\n",
                         mmc_hostname(slot->mmc));
                host->state = STATE_SENDING_CMD;
                dw_mci_start_request(host, slot);
        } else {
-               dev_vdbg(&host->pdev->dev, "list empty\n");
+               dev_vdbg(&host->dev, "list empty\n");
                host->state = STATE_IDLE;
        }
 
@@ -965,7 +1033,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                        data->bytes_xfered = 0;
                                        data->error = -ETIMEDOUT;
                                } else {
-                                       dev_err(&host->pdev->dev,
+                                       dev_err(&host->dev,
                                                "data FIFO error "
                                                "(status=%08x)\n",
                                                status);
@@ -1682,7 +1750,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        struct mmc_host *mmc;
        struct dw_mci_slot *slot;
 
-       mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->pdev->dev);
+       mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->dev);
        if (!mmc)
                return -ENOMEM;
 
@@ -1720,13 +1788,11 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
                mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
-#ifdef CONFIG_MMC_DW_IDMAC
-       mmc->max_segs = host->ring_size;
-       mmc->max_blk_size = 65536;
-       mmc->max_blk_count = host->ring_size;
-       mmc->max_seg_size = 0x1000;
-       mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
-#else
+       if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
+               mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
+       else
+               mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
+
        if (host->pdata->blk_settings) {
                mmc->max_segs = host->pdata->blk_settings->max_segs;
                mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
@@ -1735,13 +1801,20 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
                mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
        } else {
                /* Useful defaults if platform data is unset. */
+#ifdef CONFIG_MMC_DW_IDMAC
+               mmc->max_segs = host->ring_size;
+               mmc->max_blk_size = 65536;
+               mmc->max_blk_count = host->ring_size;
+               mmc->max_seg_size = 0x1000;
+               mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
+#else
                mmc->max_segs = 64;
                mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
                mmc->max_blk_count = 512;
                mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
                mmc->max_seg_size = mmc->max_req_size;
-       }
 #endif /* CONFIG_MMC_DW_IDMAC */
+       }
 
        host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
        if (IS_ERR(host->vmmc)) {
@@ -1789,10 +1862,10 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
 static void dw_mci_init_dma(struct dw_mci *host)
 {
        /* Alloc memory for sg translation */
-       host->sg_cpu = dma_alloc_coherent(&host->pdev->dev, PAGE_SIZE,
+       host->sg_cpu = dma_alloc_coherent(&host->dev, PAGE_SIZE,
                                          &host->sg_dma, GFP_KERNEL);
        if (!host->sg_cpu) {
-               dev_err(&host->pdev->dev, "%s: could not alloc DMA memory\n",
+               dev_err(&host->dev, "%s: could not alloc DMA memory\n",
                        __func__);
                goto no_dma;
        }
@@ -1800,7 +1873,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
        /* Determine which DMA interface to use */
 #ifdef CONFIG_MMC_DW_IDMAC
        host->dma_ops = &dw_mci_idmac_ops;
-       dev_info(&host->pdev->dev, "Using internal DMA controller.\n");
+       dev_info(&host->dev, "Using internal DMA controller.\n");
 #endif
 
        if (!host->dma_ops)
@@ -1808,12 +1881,12 @@ static void dw_mci_init_dma(struct dw_mci *host)
 
        if (host->dma_ops->init) {
                if (host->dma_ops->init(host)) {
-                       dev_err(&host->pdev->dev, "%s: Unable to initialize "
+                       dev_err(&host->dev, "%s: Unable to initialize "
                                "DMA Controller.\n", __func__);
                        goto no_dma;
                }
        } else {
-               dev_err(&host->pdev->dev, "DMA initialization not found.\n");
+               dev_err(&host->dev, "DMA initialization not found.\n");
                goto no_dma;
        }
 
@@ -1821,7 +1894,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
        return;
 
 no_dma:
-       dev_info(&host->pdev->dev, "Using PIO mode.\n");
+       dev_info(&host->dev, "Using PIO mode.\n");
        host->use_dma = 0;
        return;
 }
@@ -1847,61 +1920,37 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
        return false;
 }
 
-static int dw_mci_probe(struct platform_device *pdev)
+int dw_mci_probe(struct dw_mci *host)
 {
-       struct dw_mci *host;
-       struct resource *regs;
-       struct dw_mci_board *pdata;
-       int irq, ret, i, width;
+       int width, i, ret = 0;
        u32 fifo_size;
 
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!regs)
-               return -ENXIO;
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
-
-       host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
-       if (!host)
-               return -ENOMEM;
-
-       host->pdev = pdev;
-       host->pdata = pdata = pdev->dev.platform_data;
-       if (!pdata || !pdata->init) {
-               dev_err(&pdev->dev,
+       if (!host->pdata || !host->pdata->init) {
+               dev_err(&host->dev,
                        "Platform data must supply init function\n");
-               ret = -ENODEV;
-               goto err_freehost;
+               return -ENODEV;
        }
 
-       if (!pdata->select_slot && pdata->num_slots > 1) {
-               dev_err(&pdev->dev,
+       if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
+               dev_err(&host->dev,
                        "Platform data must supply select_slot function\n");
-               ret = -ENODEV;
-               goto err_freehost;
+               return -ENODEV;
        }
 
-       if (!pdata->bus_hz) {
-               dev_err(&pdev->dev,
+       if (!host->pdata->bus_hz) {
+               dev_err(&host->dev,
                        "Platform data must supply bus speed\n");
-               ret = -ENODEV;
-               goto err_freehost;
+               return -ENODEV;
        }
 
-       host->bus_hz = pdata->bus_hz;
-       host->quirks = pdata->quirks;
+       host->bus_hz = host->pdata->bus_hz;
+       host->quirks = host->pdata->quirks;
 
        spin_lock_init(&host->lock);
        INIT_LIST_HEAD(&host->queue);
 
-       ret = -ENOMEM;
-       host->regs = ioremap(regs->start, resource_size(regs));
-       if (!host->regs)
-               goto err_freehost;
 
-       host->dma_ops = pdata->dma_ops;
+       host->dma_ops = host->pdata->dma_ops;
        dw_mci_init_dma(host);
 
        /*
@@ -1931,7 +1980,7 @@ static int dw_mci_probe(struct platform_device *pdev)
        }
 
        /* Reset all blocks */
-       if (!mci_wait_reset(&pdev->dev, host)) {
+       if (!mci_wait_reset(&host->dev, host)) {
                ret = -ENODEV;
                goto err_dmaunmap;
        }
@@ -1974,13 +2023,10 @@ static int dw_mci_probe(struct platform_device *pdev)
        if (!dw_mci_card_workqueue)
                goto err_dmaunmap;
        INIT_WORK(&host->card_work, dw_mci_work_routine_card);
-
-       ret = request_irq(irq, dw_mci_interrupt, 0, "dw-mci", host);
+       ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
        if (ret)
                goto err_workqueue;
 
-       platform_set_drvdata(pdev, host);
-
        if (host->pdata->num_slots)
                host->num_slots = host->pdata->num_slots;
        else
@@ -2000,7 +2046,7 @@ static int dw_mci_probe(struct platform_device *pdev)
         * Need to check the version-id and set data-offset for DATA register.
         */
        host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
-       dev_info(&pdev->dev, "Version ID is %04x\n", host->verid);
+       dev_info(&host->dev, "Version ID is %04x\n", host->verid);
 
        if (host->verid < DW_MMC_240A)
                host->data_offset = DATA_OFFSET;
@@ -2017,12 +2063,12 @@ static int dw_mci_probe(struct platform_device *pdev)
                   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
        mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
 
-       dev_info(&pdev->dev, "DW MMC controller at irq %d, "
+       dev_info(&host->dev, "DW MMC controller at irq %d, "
                 "%d bit host data width, "
                 "%u deep fifo\n",
-                irq, width, fifo_size);
+                host->irq, width, fifo_size);
        if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
-               dev_info(&pdev->dev, "Internal DMAC interrupt fix enabled.\n");
+               dev_info(&host->dev, "Internal DMAC interrupt fix enabled.\n");
 
        return 0;
 
@@ -2033,7 +2079,7 @@ err_init_slot:
                        dw_mci_cleanup_slot(host->slot[i], i);
                i--;
        }
-       free_irq(irq, host);
+       free_irq(host->irq, host);
 
 err_workqueue:
        destroy_workqueue(dw_mci_card_workqueue);
@@ -2041,33 +2087,26 @@ err_workqueue:
 err_dmaunmap:
        if (host->use_dma && host->dma_ops->exit)
                host->dma_ops->exit(host);
-       dma_free_coherent(&host->pdev->dev, PAGE_SIZE,
+       dma_free_coherent(&host->dev, PAGE_SIZE,
                          host->sg_cpu, host->sg_dma);
-       iounmap(host->regs);
 
        if (host->vmmc) {
                regulator_disable(host->vmmc);
                regulator_put(host->vmmc);
        }
-
-
-err_freehost:
-       kfree(host);
        return ret;
 }
+EXPORT_SYMBOL(dw_mci_probe);
 
-static int __exit dw_mci_remove(struct platform_device *pdev)
+void dw_mci_remove(struct dw_mci *host)
 {
-       struct dw_mci *host = platform_get_drvdata(pdev);
        int i;
 
        mci_writel(host, RINTSTS, 0xFFFFFFFF);
        mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
 
-       platform_set_drvdata(pdev, NULL);
-
        for (i = 0; i < host->num_slots; i++) {
-               dev_dbg(&pdev->dev, "remove slot %d\n", i);
+               dev_dbg(&host->dev, "remove slot %d\n", i);
                if (host->slot[i])
                        dw_mci_cleanup_slot(host->slot[i], i);
        }
@@ -2076,9 +2115,9 @@ static int __exit dw_mci_remove(struct platform_device *pdev)
        mci_writel(host, CLKENA, 0);
        mci_writel(host, CLKSRC, 0);
 
-       free_irq(platform_get_irq(pdev, 0), host);
+       free_irq(host->irq, host);
        destroy_workqueue(dw_mci_card_workqueue);
-       dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+       dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 
        if (host->use_dma && host->dma_ops->exit)
                host->dma_ops->exit(host);
@@ -2088,20 +2127,18 @@ static int __exit dw_mci_remove(struct platform_device *pdev)
                regulator_put(host->vmmc);
        }
 
-       iounmap(host->regs);
-
-       kfree(host);
-       return 0;
 }
+EXPORT_SYMBOL(dw_mci_remove);
+
+
 
 #ifdef CONFIG_PM_SLEEP
 /*
  * TODO: we should probably disable the clock to the card in the suspend path.
  */
-static int dw_mci_suspend(struct device *dev)
+int dw_mci_suspend(struct dw_mci *host)
 {
-       int i, ret;
-       struct dw_mci *host = dev_get_drvdata(dev);
+       int i, ret = 0;
 
        for (i = 0; i < host->num_slots; i++) {
                struct dw_mci_slot *slot = host->slot[i];
@@ -2123,11 +2160,11 @@ static int dw_mci_suspend(struct device *dev)
 
        return 0;
 }
+EXPORT_SYMBOL(dw_mci_suspend);
 
-static int dw_mci_resume(struct device *dev)
+int dw_mci_resume(struct dw_mci *host)
 {
        int i, ret;
-       struct dw_mci *host = dev_get_drvdata(dev);
 
        if (host->vmmc)
                regulator_enable(host->vmmc);
@@ -2135,7 +2172,7 @@ static int dw_mci_resume(struct device *dev)
        if (host->dma_ops->init)
                host->dma_ops->init(host);
 
-       if (!mci_wait_reset(dev, host)) {
+       if (!mci_wait_reset(&host->dev, host)) {
                ret = -ENODEV;
                return ret;
        }
@@ -2157,32 +2194,19 @@ static int dw_mci_resume(struct device *dev)
                if (ret < 0)
                        return ret;
        }
-
        return 0;
 }
-#else
-#define dw_mci_suspend NULL
-#define dw_mci_resume  NULL
+EXPORT_SYMBOL(dw_mci_resume);
 #endif /* CONFIG_PM_SLEEP */
 
-static SIMPLE_DEV_PM_OPS(dw_mci_pmops, dw_mci_suspend, dw_mci_resume);
-
-static struct platform_driver dw_mci_driver = {
-       .remove         = __exit_p(dw_mci_remove),
-       .driver         = {
-               .name           = "dw_mmc",
-               .pm             = &dw_mci_pmops,
-       },
-};
-
 static int __init dw_mci_init(void)
 {
-       return platform_driver_probe(&dw_mci_driver, dw_mci_probe);
+       printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver");
+       return 0;
 }
 
 static void __exit dw_mci_exit(void)
 {
-       platform_driver_unregister(&dw_mci_driver);
 }
 
 module_init(dw_mci_init);
index df392a1143f279d75e798a89e37c4e13356f8291..15c27e17c23fad303e83368a6d2f8fac93ae9fe2 100644 (file)
        (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value))
 #endif
 
+extern int dw_mci_probe(struct dw_mci *host);
+extern void dw_mci_remove(struct dw_mci *host);
+#ifdef CONFIG_PM
+extern int dw_mci_suspend(struct dw_mci *host);
+extern int dw_mci_resume(struct dw_mci *host);
+#endif
+
 #endif /* _DW_MMC_H_ */
index fd0c661bbad38a7152a37955146ff6068d4d7137..47adb161d3adfd98e4c14279d04f4015d7283d2a 100644 (file)
@@ -26,6 +26,9 @@
 #include <linux/platform_device.h>
 #include <linux/timer.h>
 #include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/core.h>
 #include <linux/mmc/mmc.h>
 #define SOFTRESET              (1 << 1)
 #define RESETDONE              (1 << 0)
 
-/*
- * FIXME: Most likely all the data using these _DEVID defines should come
- * from the platform_data, or implemented in controller and slot specific
- * functions.
- */
-#define OMAP_MMC1_DEVID                0
-#define OMAP_MMC2_DEVID                1
-#define OMAP_MMC3_DEVID                2
-#define OMAP_MMC4_DEVID                3
-#define OMAP_MMC5_DEVID                4
-
 #define MMC_AUTOSUSPEND_DELAY  100
 #define MMC_TIMEOUT_MS         20
 #define OMAP_MMC_MIN_CLOCK     400000
@@ -164,7 +156,6 @@ struct omap_hsmmc_host {
        void    __iomem         *base;
        resource_size_t         mapbase;
        spinlock_t              irq_lock; /* Prevent races with irq handler */
-       unsigned int            id;
        unsigned int            dma_len;
        unsigned int            dma_sg_idx;
        unsigned char           bus_mode;
@@ -179,7 +170,6 @@ struct omap_hsmmc_host {
        int                     got_dbclk;
        int                     response_busy;
        int                     context_loss;
-       int                     dpm_state;
        int                     vdd;
        int                     protect_card;
        int                     reqs_blocked;
@@ -241,28 +231,7 @@ static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
 
 #ifdef CONFIG_REGULATOR
 
-static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
-                                 int vdd)
-{
-       struct omap_hsmmc_host *host =
-               platform_get_drvdata(to_platform_device(dev));
-       int ret;
-
-       if (mmc_slot(host).before_set_reg)
-               mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
-
-       if (power_on)
-               ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
-       else
-               ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
-
-       if (mmc_slot(host).after_set_reg)
-               mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
-
-       return ret;
-}
-
-static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on,
+static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
                                   int vdd)
 {
        struct omap_hsmmc_host *host =
@@ -275,6 +244,13 @@ static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on,
         */
        if (!host->vcc)
                return 0;
+       /*
+        * With DT, never turn OFF the regulator. This is because
+        * the pbias cell programming support is still missing when
+        * booting with Device tree
+        */
+       if (of_have_populated_dt() && !vdd)
+               return 0;
 
        if (mmc_slot(host).before_set_reg)
                mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
@@ -318,106 +294,16 @@ static int omap_hsmmc_235_set_power(struct device *dev, int slot, int power_on,
        return ret;
 }
 
-static int omap_hsmmc_4_set_power(struct device *dev, int slot, int power_on,
-                                       int vdd)
-{
-       return 0;
-}
-
-static int omap_hsmmc_1_set_sleep(struct device *dev, int slot, int sleep,
-                                 int vdd, int cardsleep)
-{
-       struct omap_hsmmc_host *host =
-               platform_get_drvdata(to_platform_device(dev));
-       int mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
-
-       return regulator_set_mode(host->vcc, mode);
-}
-
-static int omap_hsmmc_235_set_sleep(struct device *dev, int slot, int sleep,
-                                  int vdd, int cardsleep)
-{
-       struct omap_hsmmc_host *host =
-               platform_get_drvdata(to_platform_device(dev));
-       int err, mode;
-
-       /*
-        * If we don't see a Vcc regulator, assume it's a fixed
-        * voltage always-on regulator.
-        */
-       if (!host->vcc)
-               return 0;
-
-       mode = sleep ? REGULATOR_MODE_STANDBY : REGULATOR_MODE_NORMAL;
-
-       if (!host->vcc_aux)
-               return regulator_set_mode(host->vcc, mode);
-
-       if (cardsleep) {
-               /* VCC can be turned off if card is asleep */
-               if (sleep)
-                       err = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
-               else
-                       err = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
-       } else
-               err = regulator_set_mode(host->vcc, mode);
-       if (err)
-               return err;
-
-       if (!mmc_slot(host).vcc_aux_disable_is_sleep)
-               return regulator_set_mode(host->vcc_aux, mode);
-
-       if (sleep)
-               return regulator_disable(host->vcc_aux);
-       else
-               return regulator_enable(host->vcc_aux);
-}
-
-static int omap_hsmmc_4_set_sleep(struct device *dev, int slot, int sleep,
-                                       int vdd, int cardsleep)
-{
-       return 0;
-}
-
 static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 {
        struct regulator *reg;
-       int ret = 0;
        int ocr_value = 0;
 
-       switch (host->id) {
-       case OMAP_MMC1_DEVID:
-               /* On-chip level shifting via PBIAS0/PBIAS1 */
-               mmc_slot(host).set_power = omap_hsmmc_1_set_power;
-               mmc_slot(host).set_sleep = omap_hsmmc_1_set_sleep;
-               break;
-       case OMAP_MMC2_DEVID:
-       case OMAP_MMC3_DEVID:
-       case OMAP_MMC5_DEVID:
-               /* Off-chip level shifting, or none */
-               mmc_slot(host).set_power = omap_hsmmc_235_set_power;
-               mmc_slot(host).set_sleep = omap_hsmmc_235_set_sleep;
-               break;
-       case OMAP_MMC4_DEVID:
-               mmc_slot(host).set_power = omap_hsmmc_4_set_power;
-               mmc_slot(host).set_sleep = omap_hsmmc_4_set_sleep;
-       default:
-               pr_err("MMC%d configuration not supported!\n", host->id);
-               return -EINVAL;
-       }
+       mmc_slot(host).set_power = omap_hsmmc_set_power;
 
        reg = regulator_get(host->dev, "vmmc");
        if (IS_ERR(reg)) {
                dev_dbg(host->dev, "vmmc regulator missing\n");
-               /*
-               * HACK: until fixed.c regulator is usable,
-               * we don't require a main regulator
-               * for MMC2 or MMC3
-               */
-               if (host->id == OMAP_MMC1_DEVID) {
-                       ret = PTR_ERR(reg);
-                       goto err;
-               }
        } else {
                host->vcc = reg;
                ocr_value = mmc_regulator_get_ocrmask(reg);
@@ -425,8 +311,8 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
                        mmc_slot(host).ocr_mask = ocr_value;
                } else {
                        if (!(mmc_slot(host).ocr_mask & ocr_value)) {
-                               pr_err("MMC%d ocrmask %x is not supported\n",
-                                       host->id, mmc_slot(host).ocr_mask);
+                               dev_err(host->dev, "ocrmask %x is not supported\n",
+                                       mmc_slot(host).ocr_mask);
                                mmc_slot(host).ocr_mask = 0;
                                return -EINVAL;
                        }
@@ -459,11 +345,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
        }
 
        return 0;
-
-err:
-       mmc_slot(host).set_power = NULL;
-       mmc_slot(host).set_sleep = NULL;
-       return ret;
 }
 
 static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
@@ -471,7 +352,6 @@ static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
        regulator_put(host->vcc);
        regulator_put(host->vcc_aux);
        mmc_slot(host).set_power = NULL;
-       mmc_slot(host).set_sleep = NULL;
 }
 
 static inline int omap_hsmmc_have_reg(void)
@@ -710,7 +590,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
        OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
                        OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
 
-       if (host->id == OMAP_MMC1_DEVID) {
+       if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
                if (host->power_mode != MMC_POWER_OFF &&
                    (1 << ios->vdd) <= MMC_VDD_23_24)
                        hctl = SDVS18;
@@ -1261,14 +1141,14 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
        host->reqs_blocked = 0;
        if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) {
                if (host->protect_card) {
-                       pr_info("%s: cover is closed, "
+                       dev_info(host->dev, "%s: cover is closed, "
                                         "card is now accessible\n",
                                         mmc_hostname(host->mmc));
                        host->protect_card = 0;
                }
        } else {
                if (!host->protect_card) {
-                       pr_info("%s: cover is open, "
+                       dev_info(host->dev, "%s: cover is open, "
                                         "card is now inaccessible\n",
                                         mmc_hostname(host->mmc));
                        host->protect_card = 1;
@@ -1405,7 +1285,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
 
        if (!next && data->host_cookie &&
            data->host_cookie != host->next_data.cookie) {
-               pr_warning("[%s] invalid cookie: data->host_cookie %d"
+               dev_warn(host->dev, "[%s] invalid cookie: data->host_cookie %d"
                       " host->next_data.cookie %d\n",
                       __func__, data->host_cookie, host->next_data.cookie);
                data->host_cookie = 0;
@@ -1663,7 +1543,13 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                 * of external transceiver; but they all handle 1.8V.
                 */
                if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
-                       (ios->vdd == DUAL_VOLT_OCR_BIT)) {
+                       (ios->vdd == DUAL_VOLT_OCR_BIT) &&
+                       /*
+                        * With pbias cell programming missing, this
+                        * can't be allowed when booting with device
+                        * tree.
+                        */
+                       (!of_have_populated_dt())) {
                                /*
                                 * The mmc_select_voltage fn of the core does
                                 * not seem to set the power_mode to
@@ -1748,7 +1634,7 @@ static int omap_hsmmc_enable_fclk(struct mmc_host *mmc)
        return 0;
 }
 
-static int omap_hsmmc_disable_fclk(struct mmc_host *mmc, int lazy)
+static int omap_hsmmc_disable_fclk(struct mmc_host *mmc)
 {
        struct omap_hsmmc_host *host = mmc_priv(mmc);
 
@@ -1782,15 +1668,8 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
        if (host->pdata->get_context_loss_count)
                context_loss = host->pdata->get_context_loss_count(host->dev);
 
-       seq_printf(s, "mmc%d:\n"
-                       " enabled:\t%d\n"
-                       " dpm_state:\t%d\n"
-                       " nesting_cnt:\t%d\n"
-                       " ctx_loss:\t%d:%d\n"
-                       "\nregs:\n",
-                       mmc->index, mmc->enabled ? 1 : 0,
-                       host->dpm_state, mmc->nesting_cnt,
-                       host->context_loss, context_loss);
+       seq_printf(s, "mmc%d:\n ctx_loss:\t%d:%d\n\nregs:\n",
+                       mmc->index, host->context_loss, context_loss);
 
        if (host->suspended) {
                seq_printf(s, "host suspended, can't read registers\n");
@@ -1847,6 +1726,65 @@ static void omap_hsmmc_debugfs(struct mmc_host *mmc)
 
 #endif
 
+#ifdef CONFIG_OF
+static u16 omap4_reg_offset = 0x100;
+
+static const struct of_device_id omap_mmc_of_match[] = {
+       {
+               .compatible = "ti,omap2-hsmmc",
+       },
+       {
+               .compatible = "ti,omap3-hsmmc",
+       },
+       {
+               .compatible = "ti,omap4-hsmmc",
+               .data = &omap4_reg_offset,
+       },
+       {},
+}
+MODULE_DEVICE_TABLE(of, omap_mmc_of_match);
+
+static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
+{
+       struct omap_mmc_platform_data *pdata;
+       struct device_node *np = dev->of_node;
+       u32 bus_width;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return NULL; /* out of memory */
+
+       if (of_find_property(np, "ti,dual-volt", NULL))
+               pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
+
+       /* This driver only supports 1 slot */
+       pdata->nr_slots = 1;
+       pdata->slots[0].switch_pin = of_get_named_gpio(np, "cd-gpios", 0);
+       pdata->slots[0].gpio_wp = of_get_named_gpio(np, "wp-gpios", 0);
+
+       if (of_find_property(np, "ti,non-removable", NULL)) {
+               pdata->slots[0].nonremovable = true;
+               pdata->slots[0].no_regulator_off_init = true;
+       }
+       of_property_read_u32(np, "ti,bus-width", &bus_width);
+       if (bus_width == 4)
+               pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA;
+       else if (bus_width == 8)
+               pdata->slots[0].caps |= MMC_CAP_8_BIT_DATA;
+
+       if (of_find_property(np, "ti,needs-special-reset", NULL))
+               pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+
+       return pdata;
+}
+#else
+static inline struct omap_mmc_platform_data
+                       *of_get_hsmmc_pdata(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
 static int __init omap_hsmmc_probe(struct platform_device *pdev)
 {
        struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
@@ -1854,6 +1792,16 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
        struct omap_hsmmc_host *host = NULL;
        struct resource *res;
        int ret, irq;
+       const struct of_device_id *match;
+
+       match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
+       if (match) {
+               pdata = of_get_hsmmc_pdata(&pdev->dev);
+               if (match->data) {
+                       u16 *offsetp = match->data;
+                       pdata->reg_offset = *offsetp;
+               }
+       }
 
        if (pdata == NULL) {
                dev_err(&pdev->dev, "Platform Data is missing\n");
@@ -1894,7 +1842,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
        host->dev->dma_mask = &pdata->dma_mask;
        host->dma_ch    = -1;
        host->irq       = irq;
-       host->id        = pdev->id;
        host->slot_id   = 0;
        host->mapbase   = res->start;
        host->base      = ioremap(host->mapbase, SZ_4K);
@@ -1912,8 +1859,12 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
        if (mmc_slot(host).vcc_aux_disable_is_sleep)
                mmc_slot(host).no_off = 1;
 
-       mmc->f_min      = OMAP_MMC_MIN_CLOCK;
-       mmc->f_max      = OMAP_MMC_MAX_CLOCK;
+       mmc->f_min = OMAP_MMC_MIN_CLOCK;
+
+       if (pdata->max_freq > 0)
+               mmc->f_max = pdata->max_freq;
+       else
+               mmc->f_max = OMAP_MMC_MAX_CLOCK;
 
        spin_lock_init(&host->irq_lock);
 
@@ -1926,7 +1877,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 
        omap_hsmmc_context_save(host);
 
-       mmc->caps |= MMC_CAP_DISABLE;
        if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) {
                dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n");
                mmc->caps2 |= MMC_CAP2_NO_MULTI_READ;
@@ -1977,32 +1927,19 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 
        omap_hsmmc_conf_bus_power(host);
 
-       /* Select DMA lines */
-       switch (host->id) {
-       case OMAP_MMC1_DEVID:
-               host->dma_line_tx = OMAP24XX_DMA_MMC1_TX;
-               host->dma_line_rx = OMAP24XX_DMA_MMC1_RX;
-               break;
-       case OMAP_MMC2_DEVID:
-               host->dma_line_tx = OMAP24XX_DMA_MMC2_TX;
-               host->dma_line_rx = OMAP24XX_DMA_MMC2_RX;
-               break;
-       case OMAP_MMC3_DEVID:
-               host->dma_line_tx = OMAP34XX_DMA_MMC3_TX;
-               host->dma_line_rx = OMAP34XX_DMA_MMC3_RX;
-               break;
-       case OMAP_MMC4_DEVID:
-               host->dma_line_tx = OMAP44XX_DMA_MMC4_TX;
-               host->dma_line_rx = OMAP44XX_DMA_MMC4_RX;
-               break;
-       case OMAP_MMC5_DEVID:
-               host->dma_line_tx = OMAP44XX_DMA_MMC5_TX;
-               host->dma_line_rx = OMAP44XX_DMA_MMC5_RX;
-               break;
-       default:
-               dev_err(mmc_dev(host->mmc), "Invalid MMC id\n");
+       res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+       if (!res) {
+               dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
+               goto err_irq;
+       }
+       host->dma_line_tx = res->start;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+       if (!res) {
+               dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
                goto err_irq;
        }
+       host->dma_line_rx = res->start;
 
        /* Request IRQ for MMC operations */
        ret = request_irq(host->irq, omap_hsmmc_irq, 0,
@@ -2083,6 +2020,7 @@ err_irq_cd_init:
 err_irq:
        pm_runtime_mark_last_busy(host->dev);
        pm_runtime_put_autosuspend(host->dev);
+       pm_runtime_disable(host->dev);
        clk_put(host->fclk);
        if (host->got_dbclk) {
                clk_disable(host->dbclk);
@@ -2269,6 +2207,7 @@ static struct platform_driver omap_hsmmc_driver = {
                .name = DRIVER_NAME,
                .owner = THIS_MODULE,
                .pm = &omap_hsmmc_dev_pm_ops,
+               .of_match_table = of_match_ptr(omap_mmc_of_match),
        },
 };
 
index 5d876ff86f377b5ec5b1a77a6cfcafc1ffca59e3..f8eb1fb0c9219283c9624f3f0a8adde251bcd5e9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Freescale eSDHC controller driver.
  *
- * Copyright (c) 2007, 2010 Freescale Semiconductor, Inc.
+ * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc.
  * Copyright (c) 2009 MontaVista Software, Inc.
  *
  * Authors: Xiaobo Xie <X.Xie@freescale.com>
@@ -14,6 +14,7 @@
  */
 
 #include <linux/io.h>
+#include <linux/of.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/mmc/host.h>
@@ -114,6 +115,34 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
        return pltfm_host->clock / 256 / 16;
 }
 
+static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+       /* Workaround to reduce the clock frequency for p1010 esdhc */
+       if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
+               if (clock > 20000000)
+                       clock -= 5000000;
+               if (clock > 40000000)
+                       clock -= 5000000;
+       }
+
+       /* Set the clock */
+       esdhc_set_clock(host, clock);
+}
+
+#ifdef CONFIG_PM
+static u32 esdhc_proctl;
+static void esdhc_of_suspend(struct sdhci_host *host)
+{
+       esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
+}
+
+static void esdhc_of_resume(struct sdhci_host *host)
+{
+       esdhc_of_enable_dma(host);
+       sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
+}
+#endif
+
 static struct sdhci_ops sdhci_esdhc_ops = {
        .read_l = sdhci_be32bs_readl,
        .read_w = esdhc_readw,
@@ -121,10 +150,14 @@ static struct sdhci_ops sdhci_esdhc_ops = {
        .write_l = sdhci_be32bs_writel,
        .write_w = esdhc_writew,
        .write_b = esdhc_writeb,
-       .set_clock = esdhc_set_clock,
+       .set_clock = esdhc_of_set_clock,
        .enable_dma = esdhc_of_enable_dma,
        .get_max_clock = esdhc_of_get_max_clock,
        .get_min_clock = esdhc_of_get_min_clock,
+#ifdef CONFIG_PM
+       .platform_suspend = esdhc_of_suspend,
+       .platform_resume = esdhc_of_resume,
+#endif
 };
 
 static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
index 6ebdc4010e7ccb46e6f1052357fcdaca5dc3ecc9..fbbebe251e016cf8b24906aa6a0b4ad31f64cd40 100644 (file)
 
 #include "sdhci.h"
 
+/*
+ * PCI device IDs
+ */
+#define PCI_DEVICE_ID_INTEL_PCH_SDIO0  0x8809
+#define PCI_DEVICE_ID_INTEL_PCH_SDIO1  0x880a
+
 /*
  * PCI registers
  */
@@ -47,6 +53,7 @@ struct sdhci_pci_slot;
 
 struct sdhci_pci_fixes {
        unsigned int            quirks;
+       unsigned int            quirks2;
        bool                    allow_runtime_pm;
 
        int                     (*probe) (struct sdhci_pci_chip *);
@@ -73,6 +80,7 @@ struct sdhci_pci_chip {
        struct pci_dev          *pdev;
 
        unsigned int            quirks;
+       unsigned int            quirks2;
        bool                    allow_runtime_pm;
        const struct sdhci_pci_fixes *fixes;
 
@@ -172,6 +180,12 @@ static int mrst_hc_probe(struct sdhci_pci_chip *chip)
        return 0;
 }
 
+static int pch_hc_probe_slot(struct sdhci_pci_slot *slot)
+{
+       slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+       return 0;
+}
+
 #ifdef CONFIG_PM_RUNTIME
 
 static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id)
@@ -244,7 +258,8 @@ static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
 static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
 {
        slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
-       slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC;
+       slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC |
+                                 MMC_CAP2_HC_ERASE_SZ;
        return 0;
 }
 
@@ -271,6 +286,7 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
 
 static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = {
        .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+       .quirks2        = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
        .allow_runtime_pm = true,
        .probe_slot     = mfd_sdio_probe_slot,
 };
@@ -281,6 +297,11 @@ static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = {
        .probe_slot     = mfd_emmc_probe_slot,
 };
 
+static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
+       .quirks         = SDHCI_QUIRK_BROKEN_ADMA,
+       .probe_slot     = pch_hc_probe_slot,
+};
+
 /* O2Micro extra registers */
 #define O2_SD_LOCK_WP          0xD3
 #define O2_SD_MULTI_VCC3V      0xEE
@@ -816,6 +837,22 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
                .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_PCH_SDIO0,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_pch_sdio,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_PCH_SDIO1,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_pch_sdio,
+       },
+
        {
                .vendor         = PCI_VENDOR_ID_O2,
                .device         = PCI_DEVICE_ID_O2_8120,
@@ -1206,6 +1243,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
        host->hw_name = "PCI";
        host->ops = &sdhci_pci_ops;
        host->quirks = chip->quirks;
+       host->quirks2 = chip->quirks2;
 
        host->irq = pdev->irq;
 
@@ -1365,6 +1403,7 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
        chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
        if (chip->fixes) {
                chip->quirks = chip->fixes->quirks;
+               chip->quirks2 = chip->fixes->quirks2;
                chip->allow_runtime_pm = chip->fixes->allow_runtime_pm;
        }
        chip->num_slots = slots;
@@ -1379,6 +1418,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
 
        slots = chip->num_slots;        /* Quirk may have changed this */
 
+       pci_enable_msi(pdev);
+
        for (i = 0; i < slots; i++) {
                slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i);
                if (IS_ERR(slot)) {
@@ -1397,6 +1438,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
        return 0;
 
 free:
+       pci_disable_msi(pdev);
+
        pci_set_drvdata(pdev, NULL);
        kfree(chip);
 
@@ -1419,6 +1462,8 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
                for (i = 0; i < chip->num_slots; i++)
                        sdhci_pci_remove_slot(chip->slots[i]);
 
+               pci_disable_msi(pdev);
+
                pci_set_drvdata(pdev, NULL);
                kfree(chip);
        }
index b7f8b33c5f19f7202f66d65fd90ff14b503f8dd4..6dfa82e03c7e4964bff24a7e3fb9eb92468cd0d0 100644 (file)
@@ -300,20 +300,15 @@ static int sdhci_resume(struct device *dev)
 
        return sdhci_resume_host(host);
 }
-
-const struct dev_pm_ops sdhci_pm_ops = {
-       .suspend        = sdhci_suspend,
-       .resume         = sdhci_resume,
-};
 #endif
 
+static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume);
+
 static struct platform_driver sdhci_driver = {
        .driver = {
                .name   = "sdhci",
                .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
                .pm     = &sdhci_pm_ops,
-#endif
        },
        .probe          = sdhci_probe,
        .remove         = __devexit_p(sdhci_remove),
index cb348569454b719a3b33c303de1ee7e17d6a148c..53b26502f6e2ec36123351833cc80a9fd35e8fd6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/gpio.h>
 #include <linux/mmc/card.h>
 
 #include "sdhci-pltfm.h"
 
+#define NVQUIRK_FORCE_SDHCI_SPEC_200   BIT(0)
+#define NVQUIRK_ENABLE_BLOCK_GAP_DET   BIT(1)
+
+struct sdhci_tegra_soc_data {
+       struct sdhci_pltfm_data *pdata;
+       u32 nvquirks;
+};
+
+struct sdhci_tegra {
+       const struct tegra_sdhci_platform_data *plat;
+       const struct sdhci_tegra_soc_data *soc_data;
+};
+
 static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
 {
        u32 val;
@@ -46,7 +60,12 @@ static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
 
 static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
 {
-       if (unlikely(reg == SDHCI_HOST_VERSION)) {
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_tegra *tegra_host = pltfm_host->priv;
+       const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
+
+       if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) &&
+                       (reg == SDHCI_HOST_VERSION))) {
                /* Erratum: Version register is invalid in HW. */
                return SDHCI_SPEC_200;
        }
@@ -56,6 +75,10 @@ static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
 
 static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
 {
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_tegra *tegra_host = pltfm_host->priv;
+       const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
+
        /* Seems like we're getting spurious timeout and crc errors, so
         * disable signalling of them. In case of real errors software
         * timers should take care of eventually detecting them.
@@ -65,7 +88,8 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
 
        writel(val, host->ioaddr + reg);
 
-       if (unlikely(reg == SDHCI_INT_ENABLE)) {
+       if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) &&
+                       (reg == SDHCI_INT_ENABLE))) {
                /* Erratum: Must enable block gap interrupt detection */
                u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
                if (val & SDHCI_INT_CARD_INT)
@@ -76,10 +100,11 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
        }
 }
 
-static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci)
+static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
 {
-       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci);
-       struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_tegra *tegra_host = pltfm_host->priv;
+       const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
 
        if (!gpio_is_valid(plat->wp_gpio))
                return -1;
@@ -98,7 +123,8 @@ static irqreturn_t carddetect_irq(int irq, void *data)
 static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
+       struct sdhci_tegra *tegra_host = pltfm_host->priv;
+       const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
        u32 ctrl;
 
        ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
@@ -124,16 +150,44 @@ static struct sdhci_ops tegra_sdhci_ops = {
        .platform_8bit_width = tegra_sdhci_8bit,
 };
 
-static struct sdhci_pltfm_data sdhci_tegra_pdata = {
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+static struct sdhci_pltfm_data sdhci_tegra20_pdata = {
+       .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+                 SDHCI_QUIRK_SINGLE_POWER_WRITE |
+                 SDHCI_QUIRK_NO_HISPD_BIT |
+                 SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
+       .ops  = &tegra_sdhci_ops,
+};
+
+static struct sdhci_tegra_soc_data soc_data_tegra20 = {
+       .pdata = &sdhci_tegra20_pdata,
+       .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
+                   NVQUIRK_ENABLE_BLOCK_GAP_DET,
+};
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+static struct sdhci_pltfm_data sdhci_tegra30_pdata = {
        .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
                  SDHCI_QUIRK_SINGLE_POWER_WRITE |
                  SDHCI_QUIRK_NO_HISPD_BIT |
                  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
        .ops  = &tegra_sdhci_ops,
 };
 
+static struct sdhci_tegra_soc_data soc_data_tegra30 = {
+       .pdata = &sdhci_tegra30_pdata,
+};
+#endif
+
 static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = {
-       { .compatible = "nvidia,tegra20-sdhci", },
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+       { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
+#endif
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+       { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 },
+#endif
        {}
 };
 MODULE_DEVICE_TABLE(of, sdhci_dt_ids);
@@ -164,13 +218,22 @@ static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata(
 
 static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *match;
+       const struct sdhci_tegra_soc_data *soc_data;
+       struct sdhci_host *host;
        struct sdhci_pltfm_host *pltfm_host;
        struct tegra_sdhci_platform_data *plat;
-       struct sdhci_host *host;
+       struct sdhci_tegra *tegra_host;
        struct clk *clk;
        int rc;
 
-       host = sdhci_pltfm_init(pdev, &sdhci_tegra_pdata);
+       match = of_match_device(sdhci_tegra_dt_match, &pdev->dev);
+       if (match)
+               soc_data = match->data;
+       else
+               soc_data = &soc_data_tegra20;
+
+       host = sdhci_pltfm_init(pdev, soc_data->pdata);
        if (IS_ERR(host))
                return PTR_ERR(host);
 
@@ -187,7 +250,17 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
                goto err_no_plat;
        }
 
-       pltfm_host->priv = plat;
+       tegra_host = devm_kzalloc(&pdev->dev, sizeof(*tegra_host), GFP_KERNEL);
+       if (!tegra_host) {
+               dev_err(mmc_dev(host->mmc), "failed to allocate tegra_host\n");
+               rc = -ENOMEM;
+               goto err_no_plat;
+       }
+
+       tegra_host->plat = plat;
+       tegra_host->soc_data = soc_data;
+
+       pltfm_host->priv = tegra_host;
 
        if (gpio_is_valid(plat->power_gpio)) {
                rc = gpio_request(plat->power_gpio, "sdhci_power");
@@ -283,7 +356,8 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
 {
        struct sdhci_host *host = platform_get_drvdata(pdev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct tegra_sdhci_platform_data *plat = pltfm_host->priv;
+       struct sdhci_tegra *tegra_host = pltfm_host->priv;
+       const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
        int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
 
        sdhci_remove_host(host, dead);
@@ -326,5 +400,5 @@ static struct platform_driver sdhci_tegra_driver = {
 module_platform_driver(sdhci_tegra_driver);
 
 MODULE_DESCRIPTION("SDHCI driver for Tegra");
-MODULE_AUTHOR(" Google, Inc.");
+MODULE_AUTHOR("Google, Inc.");
 MODULE_LICENSE("GPL v2");
index 8d66706824a6105ceeac2f63526372a4f0c521fd..8262cadfdab77b82e5590da88ff0042479d3a697 100644 (file)
@@ -2267,8 +2267,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 {
        irqreturn_t result;
        struct sdhci_host *host = dev_id;
-       u32 intmask;
-       int cardint = 0;
+       u32 intmask, unexpected = 0;
+       int cardint = 0, max_loops = 16;
 
        spin_lock(&host->lock);
 
@@ -2286,6 +2286,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
                goto out;
        }
 
+again:
        DBG("*** %s got interrupt: 0x%08x\n",
                mmc_hostname(host->mmc), intmask);
 
@@ -2344,19 +2345,23 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
        intmask &= ~SDHCI_INT_CARD_INT;
 
        if (intmask) {
-               pr_err("%s: Unexpected interrupt 0x%08x.\n",
-                       mmc_hostname(host->mmc), intmask);
-               sdhci_dumpregs(host);
-
+               unexpected |= intmask;
                sdhci_writel(host, intmask, SDHCI_INT_STATUS);
        }
 
        result = IRQ_HANDLED;
 
-       mmiowb();
+       intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+       if (intmask && --max_loops)
+               goto again;
 out:
        spin_unlock(&host->lock);
 
+       if (unexpected) {
+               pr_err("%s: Unexpected interrupt 0x%08x.\n",
+                          mmc_hostname(host->mmc), unexpected);
+               sdhci_dumpregs(host);
+       }
        /*
         * We have to delay this as it calls back into the driver.
         */
@@ -2379,6 +2384,9 @@ int sdhci_suspend_host(struct sdhci_host *host)
        int ret;
        bool has_tuning_timer;
 
+       if (host->ops->platform_suspend)
+               host->ops->platform_suspend(host);
+
        sdhci_disable_card_detection(host);
 
        /* Disable tuning since we are suspending */
@@ -2423,12 +2431,24 @@ int sdhci_resume_host(struct sdhci_host *host)
        if (ret)
                return ret;
 
-       sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
-       mmiowb();
+       if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) &&
+           (host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) {
+               /* Card keeps power but host controller does not */
+               sdhci_init(host, 0);
+               host->pwr = 0;
+               host->clock = 0;
+               sdhci_do_set_ios(host, &host->mmc->ios);
+       } else {
+               sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
+               mmiowb();
+       }
 
        ret = mmc_resume_host(host->mmc);
        sdhci_enable_card_detection(host);
 
+       if (host->ops->platform_resume)
+               host->ops->platform_resume(host);
+
        /* Set the re-tuning expiration flag */
        if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
            (host->tuning_mode == SDHCI_TUNING_MODE_1))
index ad265b96b75b4f25262186ff68a171202c4474ee..f761f23d2a28ccb287e1da22b2433478833b82f1 100644 (file)
@@ -275,6 +275,8 @@ struct sdhci_ops {
        void    (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
        int     (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
        void    (*hw_reset)(struct sdhci_host *host);
+       void    (*platform_suspend)(struct sdhci_host *host);
+       void    (*platform_resume)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
index 75a485448796e67d553cae26d3e3eda9fa329b98..60f205708f54660b36cacf6e1f120fad4fe3d8b8 100644 (file)
@@ -746,7 +746,6 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
        case MMC_SET_WRITE_PROT:
        case MMC_CLR_WRITE_PROT:
        case MMC_ERASE:
-       case MMC_GEN_CMD:
                tmp |= CMD_SET_RBSY;
                break;
        }
@@ -829,7 +828,6 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
        case MMC_SET_WRITE_PROT:
        case MMC_CLR_WRITE_PROT:
        case MMC_ERASE:
-       case MMC_GEN_CMD:
                mask = MASK_START_CMD | MASK_MRBSYE;
                break;
        default:
index 58da3c44acc5d129428198b7ec80f987fe73d68a..934b68e9efc34e50796495ea61a37d2ed598e155 100644 (file)
@@ -90,6 +90,15 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
        return 0;
 }
 
+static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev)
+{
+       mmc_detect_change(dev_get_drvdata(&pdev->dev), msecs_to_jiffies(100));
+}
+
+static const struct sh_mobile_sdhi_ops sdhi_ops = {
+       .cd_wakeup = sh_mobile_sdhi_cd_wakeup,
+};
+
 static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
 {
        struct sh_mobile_sdhi *priv;
@@ -109,6 +118,12 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
        mmc_data = &priv->mmc_data;
        p->pdata = mmc_data;
 
+       if (p->init) {
+               ret = p->init(pdev, &sdhi_ops);
+               if (ret)
+                       goto einit;
+       }
+
        snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
        priv->clk = clk_get(&pdev->dev, clk_name);
        if (IS_ERR(priv->clk)) {
@@ -117,8 +132,6 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
                goto eclkget;
        }
 
-       clk_enable(priv->clk);
-
        mmc_data->hclk = clk_get_rate(priv->clk);
        mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
        mmc_data->get_cd = sh_mobile_sdhi_get_cd;
@@ -129,6 +142,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
                        mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
                mmc_data->ocr_mask = p->tmio_ocr_mask;
                mmc_data->capabilities |= p->tmio_caps;
+               mmc_data->cd_gpio = p->cd_gpio;
 
                if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
                        priv->param_tx.slave_id = p->dma_slave_tx;
@@ -211,7 +225,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
 
        dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
                 mmc_hostname(host->mmc), (unsigned long)
-                (platform_get_resource(pdev,IORESOURCE_MEM, 0)->start),
+                (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
                 mmc_data->hclk / 1000000);
 
        return ret;
@@ -232,9 +246,11 @@ eirq_sdio:
 eirq_card_detect:
        tmio_mmc_host_remove(host);
 eprobe:
-       clk_disable(priv->clk);
        clk_put(priv->clk);
 eclkget:
+       if (p->cleanup)
+               p->cleanup(pdev);
+einit:
        kfree(priv);
        return ret;
 }
@@ -258,8 +274,11 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
                free_irq(irq, host);
        }
 
-       clk_disable(priv->clk);
        clk_put(priv->clk);
+
+       if (p->cleanup)
+               p->cleanup(pdev);
+
        kfree(priv);
 
        return 0;
index f96c536d130a287768c6317d1dfa9611d30297ac..d857f5c6e7d96d93fa771bee36178b93c901becf 100644 (file)
@@ -47,16 +47,14 @@ struct tmio_mmc_host {
        struct mmc_request      *mrq;
        struct mmc_data         *data;
        struct mmc_host         *mmc;
-       unsigned int            sdio_irq_enabled;
+
+       /* Controller power state */
+       bool                    power;
 
        /* Callbacks for clock / power control */
        void (*set_pwr)(struct platform_device *host, int state);
        void (*set_clk_div)(struct platform_device *host, int state);
 
-       int                     pm_error;
-       /* recognise system-wide suspend in runtime PM methods */
-       bool                    pm_global;
-
        /* pio related stuff */
        struct scatterlist      *sg_ptr;
        struct scatterlist      *sg_orig;
@@ -86,6 +84,7 @@ struct tmio_mmc_host {
        spinlock_t              lock;           /* protect host private data */
        unsigned long           last_req_ts;
        struct mutex            ios_lock;       /* protect set_ios() context */
+       bool                    native_hotplug;
 };
 
 int tmio_mmc_host_probe(struct tmio_mmc_host **host,
index e21988901c367082f9fabb59eccb3b821b4b5843..9a7996ade58e8aaa597ca81758898669726a305d 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/mfd/tmio.h>
+#include <linux/mmc/cd-gpio.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/tmio.h>
 #include <linux/module.h>
@@ -127,7 +128,6 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
        struct tmio_mmc_host *host = mmc_priv(mmc);
 
        if (enable) {
-               host->sdio_irq_enabled = 1;
                host->sdio_irq_mask = TMIO_SDIO_MASK_ALL &
                                        ~TMIO_SDIO_STAT_IOIRQ;
                sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
@@ -136,7 +136,6 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
                host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
                sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
                sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
-               host->sdio_irq_enabled = 0;
        }
 }
 
@@ -304,6 +303,7 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
 {
        struct mmc_data *data = host->data;
        int c = cmd->opcode;
+       u32 irq_mask = TMIO_MASK_CMD;
 
        /* Command 12 is handled by hardware */
        if (cmd->opcode == 12 && !cmd->arg) {
@@ -339,7 +339,9 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
                        c |= TRANSFER_READ;
        }
 
-       tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_CMD);
+       if (!host->native_hotplug)
+               irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
+       tmio_mmc_enable_mmc_irqs(host, irq_mask);
 
        /* Fire off the command */
        sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg);
@@ -758,7 +760,7 @@ fail:
 static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
-       struct tmio_mmc_data *pdata = host->pdata;
+       struct device *dev = &host->pdev->dev;
        unsigned long flags;
 
        mutex_lock(&host->ios_lock);
@@ -766,13 +768,13 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        spin_lock_irqsave(&host->lock, flags);
        if (host->mrq) {
                if (IS_ERR(host->mrq)) {
-                       dev_dbg(&host->pdev->dev,
+                       dev_dbg(dev,
                                "%s.%d: concurrent .set_ios(), clk %u, mode %u\n",
                                current->comm, task_pid_nr(current),
                                ios->clock, ios->power_mode);
                        host->mrq = ERR_PTR(-EINTR);
                } else {
-                       dev_dbg(&host->pdev->dev,
+                       dev_dbg(dev,
                                "%s.%d: CMD%u active since %lu, now %lu!\n",
                                current->comm, task_pid_nr(current),
                                host->mrq->cmd->opcode, host->last_req_ts, jiffies);
@@ -788,13 +790,15 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        spin_unlock_irqrestore(&host->lock, flags);
 
        /*
-        * pdata->power == false only if COLD_CD is available, otherwise only
-        * in short time intervals during probing or resuming
+        * host->power toggles between false and true in both cases - either
+        * or not the controller can be runtime-suspended during inactivity.
+        * But if the controller has to be kept on, the runtime-pm usage_count
+        * is kept positive, so no suspending actually takes place.
         */
        if (ios->power_mode == MMC_POWER_ON && ios->clock) {
-               if (!pdata->power) {
-                       pm_runtime_get_sync(&host->pdev->dev);
-                       pdata->power = true;
+               if (!host->power) {
+                       pm_runtime_get_sync(dev);
+                       host->power = true;
                }
                tmio_mmc_set_clock(host, ios->clock);
                /* power up SD bus */
@@ -805,9 +809,9 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        } else if (ios->power_mode != MMC_POWER_UP) {
                if (host->set_pwr && ios->power_mode == MMC_POWER_OFF)
                        host->set_pwr(host->pdev, 0);
-               if (pdata->power) {
-                       pdata->power = false;
-                       pm_runtime_put(&host->pdev->dev);
+               if (host->power) {
+                       host->power = false;
+                       pm_runtime_put(dev);
                }
                tmio_mmc_clk_stop(host);
        }
@@ -913,7 +917,11 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        else
                mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
-       pdata->power = false;
+       _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
+                                 mmc->caps & MMC_CAP_NEEDS_POLL ||
+                                 mmc->caps & MMC_CAP_NONREMOVABLE);
+
+       _host->power = false;
        pm_runtime_enable(&pdev->dev);
        ret = pm_runtime_resume(&pdev->dev);
        if (ret < 0)
@@ -926,14 +934,13 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
         *  3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL
         *  4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE
         *
-        *  While we increment the rtpm counter for all scenarios when the mmc
-        *  core activates us by calling an appropriate set_ios(), we must
+        *  While we increment the runtime PM counter for all scenarios when
+        *  the mmc core activates us by calling an appropriate set_ios(), we
+        *  must additionally ensure that in case 2) the tmio mmc hardware stays
         *  additionally ensure that in case 2) the tmio mmc hardware stays
         *  powered on during runtime for the card detection to work.
         */
-       if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD
-               || mmc->caps & MMC_CAP_NEEDS_POLL
-               || mmc->caps & MMC_CAP_NONREMOVABLE))
+       if (_host->native_hotplug)
                pm_runtime_get_noresume(&pdev->dev);
 
        tmio_mmc_clk_stop(_host);
@@ -963,9 +970,19 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
                irq_mask |= TMIO_MASK_READOP;
        if (!_host->chan_tx)
                irq_mask |= TMIO_MASK_WRITEOP;
+       if (!_host->native_hotplug)
+               irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
 
        tmio_mmc_enable_mmc_irqs(_host, irq_mask);
 
+       if (pdata->flags & TMIO_MMC_USE_GPIO_CD) {
+               ret = mmc_cd_gpio_request(mmc, pdata->cd_gpio);
+               if (ret < 0) {
+                       tmio_mmc_host_remove(_host);
+                       return ret;
+               }
+       }
+
        *host = _host;
 
        return 0;
@@ -983,22 +1000,22 @@ EXPORT_SYMBOL(tmio_mmc_host_probe);
 void tmio_mmc_host_remove(struct tmio_mmc_host *host)
 {
        struct platform_device *pdev = host->pdev;
+       struct tmio_mmc_data *pdata = host->pdata;
+       struct mmc_host *mmc = host->mmc;
 
-       /*
-        * We don't have to manipulate pdata->power here: if there is a card in
-        * the slot, the runtime PM is active and our .runtime_resume() will not
-        * be run. If there is no card in the slot and the platform can suspend
-        * the controller, the runtime PM is suspended and pdata->power == false,
-        * so, our .runtime_resume() will not try to detect a card in the slot.
-        */
-       if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD
-               || host->mmc->caps & MMC_CAP_NEEDS_POLL
-               || host->mmc->caps & MMC_CAP_NONREMOVABLE)
+       if (pdata->flags & TMIO_MMC_USE_GPIO_CD)
+               /*
+                * This means we can miss a card-eject, but this is anyway
+                * possible, because of delayed processing of hotplug events.
+                */
+               mmc_cd_gpio_free(mmc);
+
+       if (!host->native_hotplug)
                pm_runtime_get_sync(&pdev->dev);
 
        dev_pm_qos_hide_latency_limit(&pdev->dev);
 
-       mmc_remove_host(host->mmc);
+       mmc_remove_host(mmc);
        cancel_work_sync(&host->done);
        cancel_delayed_work_sync(&host->delayed_reset_work);
        tmio_mmc_release_dma(host);
@@ -1007,7 +1024,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
        pm_runtime_disable(&pdev->dev);
 
        iounmap(host->ctl);
-       mmc_free_host(host->mmc);
+       mmc_free_host(mmc);
 }
 EXPORT_SYMBOL(tmio_mmc_host_remove);
 
@@ -1021,8 +1038,6 @@ int tmio_mmc_host_suspend(struct device *dev)
        if (!ret)
                tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
 
-       host->pm_error = pm_runtime_put_sync(dev);
-
        return ret;
 }
 EXPORT_SYMBOL(tmio_mmc_host_suspend);
@@ -1032,20 +1047,10 @@ int tmio_mmc_host_resume(struct device *dev)
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
 
-       /* The MMC core will perform the complete set up */
-       host->pdata->power = false;
-
-       host->pm_global = true;
-       if (!host->pm_error)
-               pm_runtime_get_sync(dev);
-
-       if (host->pm_global) {
-               /* Runtime PM resume callback didn't run */
-               tmio_mmc_reset(host);
-               tmio_mmc_enable_dma(host, true);
-               host->pm_global = false;
-       }
+       tmio_mmc_reset(host);
+       tmio_mmc_enable_dma(host, true);
 
+       /* The MMC core will perform the complete set up */
        return mmc_resume_host(mmc);
 }
 EXPORT_SYMBOL(tmio_mmc_host_resume);
@@ -1062,19 +1067,10 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
 {
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
-       struct tmio_mmc_data *pdata = host->pdata;
 
        tmio_mmc_reset(host);
        tmio_mmc_enable_dma(host, true);
 
-       if (pdata->power) {
-               /* Only entered after a card-insert interrupt */
-               if (!mmc->card)
-                       tmio_mmc_set_ios(mmc, &mmc->ios);
-               mmc_detect_change(mmc, msecs_to_jiffies(100));
-       }
-       host->pm_global = false;
-
        return 0;
 }
 EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
index a2161f631a831f66992d4d84b9756c56b384de3f..2231aec23918fec6c1f65125421d1d35c229c759 100644 (file)
@@ -271,7 +271,7 @@ static int tosa_lcd_resume(struct spi_device *spi)
 }
 #else
 #define tosa_lcd_suspend       NULL
-#define tosa_lcd_reume NULL
+#define tosa_lcd_resume NULL
 #endif
 
 static struct spi_driver tosa_lcd_driver = {
index 70e2017edd70e68c9958d49f1692f3401013df92..36d66653b93191c9c13c21e74dea6f511a6ac9ab 100644 (file)
@@ -1384,10 +1384,23 @@ static void invalidate_bh_lru(void *arg)
        }
        put_cpu_var(bh_lrus);
 }
+
+static bool has_bh_in_lru(int cpu, void *dummy)
+{
+       struct bh_lru *b = per_cpu_ptr(&bh_lrus, cpu);
+       int i;
        
+       for (i = 0; i < BH_LRU_SIZE; i++) {
+               if (b->bhs[i])
+                       return 1;
+       }
+
+       return 0;
+}
+
 void invalidate_bh_lrus(void)
 {
-       on_each_cpu(invalidate_bh_lru, NULL, 1);
+       on_each_cpu_cond(has_bh_in_lru, invalidate_bh_lru, NULL, 1, GFP_KERNEL);
 }
 EXPORT_SYMBOL_GPL(invalidate_bh_lrus);
 
index 7f2b590a36b761182c9d4fa56b16f11ab7171ac9..735ca06430ac9df3aadb6d470f4a16a3ea0e5f89 100644 (file)
@@ -389,7 +389,7 @@ static int exofs_sync_fs(struct super_block *sb, int wait)
        ios->length = offsetof(struct exofs_fscb, s_dev_table_oid);
        memset(fscb, 0, ios->length);
        fscb->s_nextid = cpu_to_le64(sbi->s_nextid);
-       fscb->s_numfiles = cpu_to_le32(sbi->s_numfiles);
+       fscb->s_numfiles = cpu_to_le64(sbi->s_numfiles);
        fscb->s_magic = cpu_to_le16(sb->s_magic);
        fscb->s_newfs = 0;
        fscb->s_version = EXOFS_FSCB_VER;
@@ -529,7 +529,8 @@ static int exofs_devs_2_odi(struct exofs_dt_device_info *dt_dev,
                             struct osd_dev_info *odi)
 {
        odi->systemid_len = le32_to_cpu(dt_dev->systemid_len);
-       memcpy(odi->systemid, dt_dev->systemid, odi->systemid_len);
+       if (likely(odi->systemid_len))
+               memcpy(odi->systemid, dt_dev->systemid, OSD_SYSTEMID_LEN);
 
        odi->osdname_len = le32_to_cpu(dt_dev->osdname_len);
        odi->osdname = dt_dev->osdname;
@@ -565,7 +566,7 @@ int __alloc_dev_table(struct exofs_sb_info *sbi, unsigned numdevs,
 
        aoded = kzalloc(sizeof(*aoded), GFP_KERNEL);
        if (unlikely(!aoded)) {
-               EXOFS_ERR("ERROR: faild allocating Device array[%d]\n",
+               EXOFS_ERR("ERROR: failed allocating Device array[%d]\n",
                          numdevs);
                return -ENOMEM;
        }
index 634c0bcb4fd6878776f9d560e8ad023199b975d4..5acfd9ea8a31390eb0f6b3ab6872f8efc334bc2b 100644 (file)
@@ -793,7 +793,6 @@ filelayout_clear_request_commit(struct nfs_page *req)
        if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
                goto out;
        if (list_is_singular(&req->wb_list)) {
-               struct inode *inode = req->wb_context->dentry->d_inode;
                struct pnfs_layout_segment *lseg;
 
                /* From here we can find the bucket, but for the moment,
index e809d2305ebf3a6431c52a6f0a805672365557fb..f82bde005a822435fe8c4e7e20e99a60f3a5764c 100644 (file)
@@ -270,7 +270,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
                case 0:
                        return 0;
                case -NFS4ERR_OPENMODE:
-                       if (nfs_have_delegation(inode, FMODE_READ)) {
+                       if (inode && nfs_have_delegation(inode, FMODE_READ)) {
                                nfs_inode_return_delegation(inode);
                                exception->retry = 1;
                                return 0;
@@ -282,10 +282,9 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
                case -NFS4ERR_DELEG_REVOKED:
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_BAD_STATEID:
-                       if (state != NULL)
-                               nfs_remove_bad_delegation(state->inode);
                        if (state == NULL)
                                break;
+                       nfs_remove_bad_delegation(state->inode);
                        nfs4_schedule_stateid_recovery(server, state);
                        goto wait_on_recovery;
                case -NFS4ERR_EXPIRED:
@@ -2290,11 +2289,12 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
                switch (err) {
                case 0:
                case -NFS4ERR_WRONGSEC:
-                       break;
+                       goto out;
                default:
                        err = nfs4_handle_exception(server, err, &exception);
                }
        } while (exception.retry);
+out:
        return err;
 }
 
@@ -3712,7 +3712,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                if (acl_len > buflen)
                        goto out_free;
                _copy_from_pages(buf, pages, res.acl_data_offset,
-                               res.acl_len);
+                               acl_len);
        }
        ret = acl_len;
 out_free:
@@ -3824,8 +3824,9 @@ nfs4_async_handle_error(