]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
Merge branch 'for-linus/2634-git-updates' of git://git.fluff.org/bjdooks/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 27 May 2010 17:23:57 +0000 (10:23 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 27 May 2010 17:23:57 +0000 (10:23 -0700)
* 'for-linus/2634-git-updates' of git://git.fluff.org/bjdooks/linux:
  ARM: S5PC100: Fixup cross tree merge problems
  ARM: S5P: Fix the platform external interrupt issues.
  ARM: s5pv210_defconfig: Update s5pv210_defconfig to v2.6.34-git
  ARM: s5pc110_defconfig: Update s5pc110_defconfig to v2.6.34-git
  ARM: s5pc100_defconfig: Update s5pc100_defconfig to v2.6.34-git
  ARM: s5p6442_defconfig: Update s5p6442_defconfig to v2.6.34-git
  ARM: s5p6440_defconfig: Update s5p6440_defconfig to v2.6.34-git
  ARM: s3c6400_defconfig: Update s3c6400_defconfig to v2.6.34-git
  ARM: s3c2410_defconfig: Update s3c2410_defconfig to v2.6.34-git

355 files changed:
Documentation/DMA-API-HOWTO.txt
Documentation/SubmittingDrivers
Documentation/cgroups/cgroups.txt
Documentation/cgroups/memory.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/Locking
Documentation/filesystems/squashfs.txt
Documentation/vm/numa
MAINTAINERS
arch/alpha/Kconfig
arch/alpha/include/asm/scatterlist.h
arch/alpha/math-emu/sfp-util.h
arch/arm/include/asm/scatterlist.h
arch/arm/mach-davinci/include/mach/mmc.h
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-omap3touchbook.c
arch/arm/plat-omap/gpio.c
arch/avr32/include/asm/scatterlist.h
arch/blackfin/include/asm/scatterlist.h
arch/blackfin/kernel/ptrace.c
arch/cris/include/asm/scatterlist.h
arch/frv/include/asm/scatterlist.h
arch/frv/kernel/ptrace.c
arch/frv/kernel/sysctl.c
arch/h8300/include/asm/scatterlist.h
arch/ia64/Kconfig
arch/ia64/include/asm/scatterlist.h
arch/ia64/include/asm/topology.h
arch/ia64/kernel/pci-swiotlb.c
arch/ia64/kernel/ptrace.c
arch/ia64/kernel/smpboot.c
arch/m32r/include/asm/scatterlist.h
arch/m68k/Kconfig
arch/m68k/amiga/config.c
arch/m68k/amiga/platform.c
arch/m68k/include/asm/amigayle.h
arch/m68k/include/asm/atomic.h
arch/m68k/include/asm/cache.h
arch/m68k/include/asm/scatterlist.h
arch/microblaze/include/asm/scatterlist.h
arch/mips/include/asm/scatterlist.h
arch/mn10300/include/asm/scatterlist.h
arch/parisc/Kconfig
arch/parisc/include/asm/scatterlist.h
arch/powerpc/Kconfig
arch/powerpc/include/asm/scatterlist.h
arch/powerpc/include/asm/sfp-machine.h
arch/powerpc/kernel/dma-swiotlb.c
arch/powerpc/kernel/dma.c
arch/powerpc/sysdev/fsl_rio.c
arch/s390/include/asm/scatterlist.h
arch/s390/include/asm/sfp-util.h
arch/s390/kernel/smp.c
arch/score/include/asm/scatterlist.h
arch/sh/Kconfig
arch/sh/kernel/ptrace_32.c
arch/sh/math-emu/sfp-util.h
arch/sparc/Kconfig
arch/sparc/include/asm/scatterlist.h
arch/sparc/math-emu/sfp-util_32.h
arch/sparc/math-emu/sfp-util_64.h
arch/x86/Kconfig
arch/x86/boot/compressed/relocs.c
arch/x86/include/asm/scatterlist.h
arch/x86/include/asm/topology.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpuid.c
arch/x86/kernel/msr.c
arch/x86/kernel/pci-swiotlb.c
arch/x86/kernel/setup_percpu.c
arch/x86/mm/numa.c
arch/x86/mm/numa_64.c
arch/xtensa/include/asm/scatterlist.h
drivers/base/topology.c
drivers/char/Kconfig
drivers/char/Makefile
drivers/char/agp/amd64-agp.c
drivers/char/amiserial.c
drivers/char/applicom.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ppdev.c
drivers/char/ramoops.c [new file with mode: 0644]
drivers/char/vt.c
drivers/edac/i5000_edac.c
drivers/edac/i5400_edac.c
drivers/edac/i82443bxgx_edac.c
drivers/firewire/core-card.c
drivers/firewire/core-cdev.c
drivers/firewire/core-transaction.c
drivers/firewire/core.h
drivers/firewire/ohci.c
drivers/firewire/ohci.h
drivers/gpio/Kconfig
drivers/gpio/cs5535-gpio.c
drivers/gpio/gpiolib.c
drivers/gpio/it8761e_gpio.c
drivers/gpio/langwell_gpio.c
drivers/gpio/max732x.c
drivers/gpio/pca953x.c
drivers/gpio/pl061.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nv40_graph.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_agp.c
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-core.c
drivers/hid/hid-debug.c
drivers/hid/hid-gyration.c
drivers/hid/hid-ids.h
drivers/hid/hid-roccat-kone.c
drivers/hid/hid-roccat-kone.h
drivers/hid/hid-roccat.c [new file with mode: 0644]
drivers/hid/hid-roccat.h [new file with mode: 0644]
drivers/ide/gayle.c
drivers/ieee1394/dv1394.c
drivers/ieee1394/raw1394.c
drivers/ieee1394/video1394.c
drivers/infiniband/hw/ehca/ehca_irq.c
drivers/input/joydev.c
drivers/input/keyboard/amikbd.c
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/max8925_onkey.c [new file with mode: 0644]
drivers/input/misc/twl4030-vibra.c
drivers/input/misc/uinput.c
drivers/input/mouse/amimouse.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/s3c2410_ts.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/isdn/mISDN/timerdev.c
drivers/md/raid5.c
drivers/message/i2o/i2o_config.c
drivers/misc/lkdtm.c
drivers/mmc/core/core.c
drivers/mmc/core/sd_ops.c
drivers/mmc/core/sdio_io.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/at91_mci.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/au1xmmc.c
drivers/mmc/host/bfin_sdh.c
drivers/mmc/host/cb710-mmc.c
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/imxmmc.c
drivers/mmc/host/mmci.c
drivers/mmc/host/msm_sdcc.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-of-core.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-of-hlwd.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-spear.c [new file with mode: 0644]
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sdricoh_cs.c
drivers/mmc/host/sh_mmcif.c [new file with mode: 0644]
drivers/mmc/host/tifm_sd.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/via-sdmmc.c
drivers/mmc/host/wbsd.c
drivers/parport/parport_amiga.c
drivers/rapidio/Kconfig
drivers/rapidio/Makefile
drivers/rapidio/rio-scan.c
drivers/rapidio/rio.c
drivers/rapidio/rio.h
drivers/rapidio/switches/Kconfig [new file with mode: 0644]
drivers/rapidio/switches/Makefile
drivers/rapidio/switches/idtcps.c [new file with mode: 0644]
drivers/rapidio/switches/tsi500.c
drivers/rapidio/switches/tsi568.c [new file with mode: 0644]
drivers/rapidio/switches/tsi57x.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-ab8500.c [new file with mode: 0644]
drivers/rtc/rtc-m41t80.c
drivers/scsi/a2091.c
drivers/scsi/a2091.h
drivers/scsi/a3000.c
drivers/scsi/a3000.h
drivers/scsi/a4000t.c
drivers/scsi/gvp11.c
drivers/scsi/gvp11.h
drivers/scsi/mvme147.c
drivers/scsi/osst.c
drivers/scsi/st.c
drivers/staging/go7007/saa7134-go7007.c
drivers/telephony/ixj.c
drivers/video/bf54x-lq043fb.c
drivers/video/bfin-t350mcqb-fb.c
drivers/video/s3fb.c
drivers/video/via/viafbdev.c
fs/affs/namei.c
fs/aio.c
fs/autofs/root.c
fs/autofs4/dev-ioctl.c
fs/compat.c
fs/exec.c
fs/freevxfs/vxfs_lookup.c
fs/fscache/object-list.c
fs/isofs/dir.c
fs/ncpfs/dir.c
fs/nfs/dir.c
fs/nfs/write.c
fs/proc/array.c
fs/proc/base.c
fs/proc/generic.c
fs/proc/kcore.c
fs/proc/root.c
fs/qnx4/dir.c
fs/read_write.c
fs/reiserfs/dir.c
fs/smbfs/dir.c
fs/squashfs/Kconfig
fs/squashfs/Makefile
fs/squashfs/inode.c
fs/squashfs/namei.c
fs/squashfs/squashfs.h
fs/squashfs/squashfs_fs.h
fs/squashfs/squashfs_fs_i.h
fs/squashfs/squashfs_fs_sb.h
fs/squashfs/super.c
fs/squashfs/symlink.c
fs/squashfs/xattr.c [new file with mode: 0644]
fs/squashfs/xattr.h [new file with mode: 0644]
fs/squashfs/xattr_id.c [new file with mode: 0644]
fs/udf/dir.c
fs/ufs/super.c
fs/ufs/ufs_fs.h
include/asm-generic/dma-mapping-common.h
include/asm-generic/gpio.h
include/asm-generic/scatterlist.h
include/asm-generic/topology.h
include/asm-generic/vmlinux.lds.h
include/linux/aio.h
include/linux/bitmap.h
include/linux/byteorder/big_endian.h
include/linux/byteorder/little_endian.h
include/linux/cgroup.h
include/linux/compat.h
include/linux/cpuset.h
include/linux/cred.h
include/linux/dma-mapping.h
include/linux/firewire.h
include/linux/fs.h
include/linux/gpio.h
include/linux/i2c/max732x.h
include/linux/i2c/pca953x.h
include/linux/init_task.h
include/linux/input.h
include/linux/joystick.h
include/linux/kmod.h
include/linux/memcontrol.h
include/linux/mmc/host.h
include/linux/mmc/sdhci-spear.h [new file with mode: 0644]
include/linux/mmc/sdio_func.h
include/linux/mmc/sh_mmcif.h [new file with mode: 0644]
include/linux/mmzone.h
include/linux/nodemask.h
include/linux/notifier.h
include/linux/page_cgroup.h
include/linux/random.h
include/linux/rio.h
include/linux/rio_drv.h
include/linux/rio_ids.h
include/linux/rio_regs.h
include/linux/sched.h
include/linux/sdhci-pltfm.h [new file with mode: 0644]
include/linux/sem.h
include/linux/swap.h
include/linux/swiotlb.h
include/linux/threads.h
include/linux/topology.h
include/linux/uinput.h
ipc/sem.c
kernel/cgroup.c
kernel/cpu.c
kernel/cpuset.c
kernel/cred.c
kernel/exit.c
kernel/fork.c
kernel/kmod.c
kernel/padata.c
kernel/panic.c
kernel/pid.c
kernel/posix-cpu-timers.c
kernel/profile.c
kernel/ptrace.c
kernel/relay.c
kernel/sched.c
kernel/sched_debug.c
kernel/signal.c
kernel/smp.c
kernel/softirq.c
kernel/sys.c
kernel/timer.c
kernel/workqueue.c
lib/Kconfig.debug
lib/Makefile
lib/bitmap.c
lib/cpu-notifier-error-inject.c [new file with mode: 0644]
lib/crc32.c
lib/idr.c
lib/radix-tree.c
lib/random32.c
lib/swiotlb.c
mm/filemap.c
mm/memcontrol.c
mm/mempolicy.c
mm/migrate.c
mm/nommu.c
mm/oom_kill.c
mm/page_alloc.c
mm/shmem.c
mm/slab.c
net/iucv/iucv.c
net/sunrpc/xprtsock.c
scripts/gen_initramfs_list.sh
security/keys/internal.h
security/keys/keyctl.c
security/keys/process_keys.c
security/keys/request_key.c
sound/core/pcm_lib.c
sound/core/pcm_native.c
sound/pci/aw2/aw2-alsa.c
sound/pci/emu10k1/emufx.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/usb/caiaq/input.c
sound/usb/midi.c
sound/usb/midi.h
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/usb/usbaudio.h
usr/Makefile
usr/initramfs_data.lzo.S [new file with mode: 0644]

index 2e435adfbd6bbedfbe913c38e1c51a9c2db036e9..98ce51796f711317f567a3b5144955178d0fd8da 100644 (file)
@@ -639,6 +639,36 @@ is planned to completely remove virt_to_bus() and bus_to_virt() as
 they are entirely deprecated.  Some ports already do not provide these
 as it is impossible to correctly support them.
 
+                       Handling Errors
+
+DMA address space is limited on some architectures and an allocation
+failure can be determined by:
+
+- checking if dma_alloc_coherent returns NULL or dma_map_sg returns 0
+
+- checking the returned dma_addr_t of dma_map_single and dma_map_page
+  by using dma_mapping_error():
+
+       dma_addr_t dma_handle;
+
+       dma_handle = dma_map_single(dev, addr, size, direction);
+       if (dma_mapping_error(dev, dma_handle)) {
+               /*
+                * reduce current DMA mapping usage,
+                * delay and try again later or
+                * reset driver.
+                */
+       }
+
+Networking drivers must call dev_kfree_skb to free the socket buffer
+and return NETDEV_TX_OK if the DMA mapping fails on the transmit hook
+(ndo_start_xmit). This means that the socket buffer is just dropped in
+the failure case.
+
+SCSI drivers must return SCSI_MLQUEUE_HOST_BUSY if the DMA mapping
+fails in the queuecommand hook. This means that the SCSI subsystem
+passes the command to the driver again later.
+
                Optimizing Unmap State Space Consumption
 
 On many platforms, dma_unmap_{single,page}() is simply a nop.
@@ -703,42 +733,25 @@ to "Closing".
 
 1) Struct scatterlist requirements.
 
-   Struct scatterlist must contain, at a minimum, the following
-   members:
-
-       struct page *page;
-       unsigned int offset;
-       unsigned int length;
-
-   The base address is specified by a "page+offset" pair.
-
-   Previous versions of struct scatterlist contained a "void *address"
-   field that was sometimes used instead of page+offset.  As of Linux
-   2.5., page+offset is always used, and the "address" field has been
-   deleted.
-
-2) More to come...
-
-                       Handling Errors
-
-DMA address space is limited on some architectures and an allocation
-failure can be determined by:
-
-- checking if dma_alloc_coherent returns NULL or dma_map_sg returns 0
-
-- checking the returned dma_addr_t of dma_map_single and dma_map_page
-  by using dma_mapping_error():
-
-       dma_addr_t dma_handle;
-
-       dma_handle = dma_map_single(dev, addr, size, direction);
-       if (dma_mapping_error(dev, dma_handle)) {
-               /*
-                * reduce current DMA mapping usage,
-                * delay and try again later or
-                * reset driver.
-                */
-       }
+   Don't invent the architecture specific struct scatterlist; just use
+   <asm-generic/scatterlist.h>. You need to enable
+   CONFIG_NEED_SG_DMA_LENGTH if the architecture supports IOMMUs
+   (including software IOMMU).
+
+2) ARCH_KMALLOC_MINALIGN
+
+   Architectures must ensure that kmalloc'ed buffer is
+   DMA-safe. Drivers and subsystems depend on it. If an architecture
+   isn't fully DMA-coherent (i.e. hardware doesn't ensure that data in
+   the CPU cache is identical to data in main memory),
+   ARCH_KMALLOC_MINALIGN must be set so that the memory allocator
+   makes sure that kmalloc'ed buffer doesn't share a cache line with
+   the others. See arch/arm/include/asm/cache.h as an example.
+
+   Note that ARCH_KMALLOC_MINALIGN is about DMA memory alignment
+   constraints. You don't need to worry about the architecture data
+   alignment constraints (e.g. the alignment constraints about 64-bit
+   objects).
 
                           Closing
 
index 99e72a81fa2fac5570708ed419e7a89b19040f1c..4947fd8fb1827a2d9c8a9cbcdb734d6b6f5eb98d 100644 (file)
@@ -130,6 +130,8 @@ Linux kernel master tree:
        ftp.??.kernel.org:/pub/linux/kernel/...
        ?? == your country code, such as "us", "uk", "fr", etc.
 
+       http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git
+
 Linux kernel mailing list:
        linux-kernel@vger.kernel.org
        [mail majordomo@vger.kernel.org to subscribe]
@@ -160,3 +162,6 @@ How to NOT write kernel driver by Arjan van de Ven:
 
 Kernel Janitor:
        http://janitor.kernelnewbies.org/
+
+GIT, Fast Version Control System:
+       http://git-scm.com/
index 57444c2609fcb408131c45b4edfab02b05f5b435..b34823ff16469a0e6d57bbca9d659f5968d1e410 100644 (file)
@@ -339,7 +339,7 @@ To mount a cgroup hierarchy with all available subsystems, type:
 The "xxx" is not interpreted by the cgroup code, but will appear in
 /proc/mounts so may be any useful identifying string that you like.
 
-To mount a cgroup hierarchy with just the cpuset and numtasks
+To mount a cgroup hierarchy with just the cpuset and memory
 subsystems, type:
 # mount -t cgroup -o cpuset,memory hier1 /dev/cgroup
 
index 6cab1f29da4c9b94b35c603fd9a91a252c0231aa..7781857dc940ea01d60e7bc0b249cbd15623182d 100644 (file)
@@ -1,18 +1,15 @@
 Memory Resource Controller
 
 NOTE: The Memory Resource Controller has been generically been referred
-to as the memory controller in this document. Do not confuse memory controller
-used here with the memory controller that is used in hardware.
+      to as the memory controller in this document. Do not confuse memory
+      controller used here with the memory controller that is used in hardware.
 
-Salient features
-
-a. Enable control of Anonymous, Page Cache (mapped and unmapped) and
-   Swap Cache memory pages.
-b. The infrastructure allows easy addition of other types of memory to control
-c. Provides *zero overhead* for non memory controller users
-d. Provides a double LRU: global memory pressure causes reclaim from the
-   global LRU; a cgroup on hitting a limit, reclaims from the per
-   cgroup LRU
+(For editors)
+In this document:
+      When we mention a cgroup (cgroupfs's directory) with memory controller,
+      we call it "memory cgroup". When you see git-log and source code, you'll
+      see patch's title and function names tend to use "memcg".
+      In this document, we avoid using it.
 
 Benefits and Purpose of the memory controller
 
@@ -33,6 +30,45 @@ d. A CD/DVD burner could control the amount of memory used by the
 e. There are several other use cases, find one or use the controller just
    for fun (to learn and hack on the VM subsystem).
 
+Current Status: linux-2.6.34-mmotm(development version of 2010/April)
+
+Features:
+ - accounting anonymous pages, file caches, swap caches usage and limiting them.
+ - private LRU and reclaim routine. (system's global LRU and private LRU
+   work independently from each other)
+ - optionally, memory+swap usage can be accounted and limited.
+ - hierarchical accounting
+ - soft limit
+ - moving(recharging) account at moving a task is selectable.
+ - usage threshold notifier
+ - oom-killer disable knob and oom-notifier
+ - Root cgroup has no limit controls.
+
+ Kernel memory and Hugepages are not under control yet. We just manage
+ pages on LRU. To add more controls, we have to take care of performance.
+
+Brief summary of control files.
+
+ tasks                          # attach a task(thread) and show list of threads
+ cgroup.procs                   # show list of processes
+ cgroup.event_control           # an interface for event_fd()
+ memory.usage_in_bytes          # show current memory(RSS+Cache) usage.
+ memory.memsw.usage_in_bytes    # show current memory+Swap usage
+ memory.limit_in_bytes          # set/show limit of memory usage
+ memory.memsw.limit_in_bytes    # set/show limit of memory+Swap usage
+ memory.failcnt                         # show the number of memory usage hits limits
+ memory.memsw.failcnt           # show the number of memory+Swap hits limits
+ memory.max_usage_in_bytes      # show max memory usage recorded
+ memory.memsw.usage_in_bytes    # show max memory+Swap usage recorded
+ memory.soft_limit_in_bytes     # set/show soft limit of memory usage
+ memory.stat                    # show various statistics
+ memory.use_hierarchy           # set/show hierarchical account enabled
+ memory.force_empty             # trigger forced move charge to parent
+ memory.swappiness              # set/show swappiness parameter of vmscan
+                                (See sysctl's vm.swappiness)
+ memory.move_charge_at_immigrate # set/show controls of moving charges
+ memory.oom_control             # set/show oom controls.
+
 1. History
 
 The memory controller has a long history. A request for comments for the memory
@@ -106,14 +142,14 @@ the necessary data structures and check if the cgroup that is being charged
 is over its limit. If it is then reclaim is invoked on the cgroup.
 More details can be found in the reclaim section of this document.
 If everything goes well, a page meta-data-structure called page_cgroup is
-allocated and associated with the page.  This routine also adds the page to
-the per cgroup LRU.
+updated. page_cgroup has its own LRU on cgroup.
+(*) page_cgroup structure is allocated at boot/memory-hotplug time.
 
 2.2.1 Accounting details
 
 All mapped anon pages (RSS) and cache pages (Page Cache) are accounted.
-(some pages which never be reclaimable and will not be on global LRU
- are not accounted. we just accounts pages under usual vm management.)
+Some pages which are never reclaimable and will not be on the global LRU
+are not accounted. We just account pages under usual VM management.
 
 RSS pages are accounted at page_fault unless they've already been accounted
 for earlier. A file page will be accounted for as Page Cache when it's
@@ -121,12 +157,19 @@ inserted into inode (radix-tree). While it's mapped into the page tables of
 processes, duplicate accounting is carefully avoided.
 
 A RSS page is unaccounted when it's fully unmapped. A PageCache page is
-unaccounted when it's removed from radix-tree.
+unaccounted when it's removed from radix-tree. Even if RSS pages are fully
+unmapped (by kswapd), they may exist as SwapCache in the system until they
+are really freed. Such SwapCaches also also accounted.
+A swapped-in page is not accounted until it's mapped.
+
+Note: The kernel does swapin-readahead and read multiple swaps at once.
+This means swapped-in pages may contain pages for other tasks than a task
+causing page fault. So, we avoid accounting at swap-in I/O.
 
 At page migration, accounting information is kept.
 
-Note: we just account pages-on-lru because our purpose is to control amount
-of used pages. not-on-lru pages are tend to be out-of-control from vm view.
+Note: we just account pages-on-LRU because our purpose is to control amount
+of used pages; not-on-LRU pages tend to be out-of-control from VM view.
 
 2.3 Shared Page Accounting
 
@@ -143,6 +186,7 @@ caller of swapoff rather than the users of shmem.
 
 
 2.4 Swap Extension (CONFIG_CGROUP_MEM_RES_CTLR_SWAP)
+
 Swap Extension allows you to record charge for swap. A swapped-in page is
 charged back to original page allocator if possible.
 
@@ -150,13 +194,20 @@ When swap is accounted, following files are added.
  - memory.memsw.usage_in_bytes.
  - memory.memsw.limit_in_bytes.
 
-usage of mem+swap is limited by memsw.limit_in_bytes.
+memsw means memory+swap. Usage of memory+swap is limited by
+memsw.limit_in_bytes.
 
-* why 'mem+swap' rather than swap.
+Example: Assume a system with 4G of swap. A task which allocates 6G of memory
+(by mistake) under 2G memory limitation will use all swap.
+In this case, setting memsw.limit_in_bytes=3G will prevent bad use of swap.
+By using memsw limit, you can avoid system OOM which can be caused by swap
+shortage.
+
+* why 'memory+swap' rather than swap.
 The global LRU(kswapd) can swap out arbitrary pages. Swap-out means
 to move account from memory to swap...there is no change in usage of
-mem+swap. In other words, when we want to limit the usage of swap without
-affecting global LRU, mem+swap limit is better than just limiting swap from
+memory+swap. In other words, when we want to limit the usage of swap without
+affecting global LRU, memory+swap limit is better than just limiting swap from
 OS point of view.
 
 * What happens when a cgroup hits memory.memsw.limit_in_bytes
@@ -168,12 +219,12 @@ it by cgroup.
 
 2.5 Reclaim
 
-Each cgroup maintains a per cgroup LRU that consists of an active
-and inactive list. When a cgroup goes over its limit, we first try
+Each cgroup maintains a per cgroup LRU which has the same structure as
+global VM. When a cgroup goes over its limit, we first try
 to reclaim memory from the cgroup so as to make space for the new
 pages that the cgroup has touched. If the reclaim is unsuccessful,
 an OOM routine is invoked to select and kill the bulkiest task in the
-cgroup.
+cgroup. (See 10. OOM Control below.)
 
 The reclaim algorithm has not been modified for cgroups, except that
 pages that are selected for reclaiming come from the per cgroup LRU
@@ -184,13 +235,22 @@ limits on the root cgroup.
 
 Note2: When panic_on_oom is set to "2", the whole system will panic.
 
-2. Locking
+When oom event notifier is registered, event will be delivered.
+(See oom_control section)
+
+2.6 Locking
 
-The memory controller uses the following hierarchy
+   lock_page_cgroup()/unlock_page_cgroup() should not be called under
+   mapping->tree_lock.
 
-1. zone->lru_lock is used for selecting pages to be isolated
-2. mem->per_zone->lru_lock protects the per cgroup LRU (per zone)
-3. lock_page_cgroup() is used to protect page->page_cgroup
+   Other lock order is following:
+   PG_locked.
+   mm->page_table_lock
+       zone->lru_lock
+         lock_page_cgroup.
+  In many cases, just lock_page_cgroup() is called.
+  per-zone-per-cgroup LRU (cgroup's private LRU) is just guarded by
+  zone->lru_lock, it has no lock of its own.
 
 3. User Interface
 
@@ -199,6 +259,7 @@ The memory controller uses the following hierarchy
 a. Enable CONFIG_CGROUPS
 b. Enable CONFIG_RESOURCE_COUNTERS
 c. Enable CONFIG_CGROUP_MEM_RES_CTLR
+d. Enable CONFIG_CGROUP_MEM_RES_CTLR_SWAP (to use swap extension)
 
 1. Prepare the cgroups
 # mkdir -p /cgroups
@@ -206,31 +267,28 @@ c. Enable CONFIG_CGROUP_MEM_RES_CTLR
 
 2. Make the new group and move bash into it
 # mkdir /cgroups/0
-# echo $$ >  /cgroups/0/tasks
+# echo $$ > /cgroups/0/tasks
 
-Since now we're in the 0 cgroup,
-We can alter the memory limit:
+Since now we're in the 0 cgroup, we can alter the memory limit:
 # echo 4M > /cgroups/0/memory.limit_in_bytes
 
 NOTE: We can use a suffix (k, K, m, M, g or G) to indicate values in kilo,
-mega or gigabytes.
+mega or gigabytes. (Here, Kilo, Mega, Giga are Kibibytes, Mebibytes, Gibibytes.)
+
 NOTE: We can write "-1" to reset the *.limit_in_bytes(unlimited).
 NOTE: We cannot set limits on the root cgroup any more.
 
 # cat /cgroups/0/memory.limit_in_bytes
 4194304
 
-NOTE: The interface has now changed to display the usage in bytes
-instead of pages
-
 We can check the usage:
 # cat /cgroups/0/memory.usage_in_bytes
 1216512
 
 A successful write to this file does not guarantee a successful set of
-this limit to the value written into the file.  This can be due to a
+this limit to the value written into the file. This can be due to a
 number of factors, such as rounding up to page boundaries or the total
-availability of memory on the system.  The user is required to re-read
+availability of memory on the system. The user is required to re-read
 this file after a write to guarantee the value committed by the kernel.
 
 # echo 1 > memory.limit_in_bytes
@@ -245,15 +303,23 @@ caches, RSS and Active pages/Inactive pages are shown.
 
 4. Testing
 
-Balbir posted lmbench, AIM9, LTP and vmmstress results [10] and [11].
-Apart from that v6 has been tested with several applications and regular
-daily use. The controller has also been tested on the PPC64, x86_64 and
-UML platforms.
+For testing features and implementation, see memcg_test.txt.
+
+Performance test is also important. To see pure memory controller's overhead,
+testing on tmpfs will give you good numbers of small overheads.
+Example: do kernel make on tmpfs.
+
+Page-fault scalability is also important. At measuring parallel
+page fault test, multi-process test may be better than multi-thread
+test because it has noise of shared objects/status.
+
+But the above two are testing extreme situations.
+Trying usual test under memory controller is always helpful.
 
 4.1 Troubleshooting
 
 Sometimes a user might find that the application under a cgroup is
-terminated. There are several causes for this:
+terminated by OOM killer. There are several causes for this:
 
 1. The cgroup limit is too low (just too low to do anything useful)
 2. The user is using anonymous memory and swap is turned off or too low
@@ -261,6 +327,9 @@ terminated. There are several causes for this:
 A sync followed by echo 1 > /proc/sys/vm/drop_caches will help get rid of
 some of the pages cached in the cgroup (page cache pages).
 
+To know what happens, disable OOM_Kill by 10. OOM Control(see below) and
+seeing what happens will be helpful.
+
 4.2 Task migration
 
 When a task migrates from one cgroup to another, its charge is not
@@ -268,16 +337,19 @@ carried forward by default. The pages allocated from the original cgroup still
 remain charged to it, the charge is dropped when the page is freed or
 reclaimed.
 
-Note: You can move charges of a task along with task migration. See 8.
+You can move charges of a task along with task migration.
+See 8. "Move charges at task migration"
 
 4.3 Removing a cgroup
 
 A cgroup can be removed by rmdir, but as discussed in sections 4.1 and 4.2, a
 cgroup might have some charge associated with it, even though all
-tasks have migrated away from it.
-Such charges are freed(at default) or moved to its parent. When moved,
-both of RSS and CACHES are moved to parent.
-If both of them are busy, rmdir() returns -EBUSY. See 5.1 Also.
+tasks have migrated away from it. (because we charge against pages, not
+against tasks.)
+
+Such charges are freed or moved to their parent. At moving, both of RSS
+and CACHES are moved to parent.
+rmdir() may return -EBUSY if freeing/moving fails. See 5.1 also.
 
 Charges recorded in swap information is not updated at removal of cgroup.
 Recorded information is discarded and a cgroup which uses swap (swapcache)
@@ -293,10 +365,10 @@ will be charged as a new owner of it.
 
   # echo 0 > memory.force_empty
 
-  Almost all pages tracked by this memcg will be unmapped and freed. Some of
-  pages cannot be freed because it's locked or in-use. Such pages are moved
-  to parent and this cgroup will be empty. But this may return -EBUSY in
-  some too busy case.
+  Almost all pages tracked by this memory cgroup will be unmapped and freed.
+  Some pages cannot be freed because they are locked or in-use. Such pages are
+  moved to parent and this cgroup will be empty. This may return -EBUSY if
+  VM is too busy to free/move all pages immediately.
 
   Typical use case of this interface is that calling this before rmdir().
   Because rmdir() moves all pages to parent, some out-of-use page caches can be
@@ -306,19 +378,41 @@ will be charged as a new owner of it.
 
 memory.stat file includes following statistics
 
+# per-memory cgroup local status
 cache          - # of bytes of page cache memory.
 rss            - # of bytes of anonymous and swap cache memory.
+mapped_file    - # of bytes of mapped file (includes tmpfs/shmem)
 pgpgin         - # of pages paged in (equivalent to # of charging events).
 pgpgout                - # of pages paged out (equivalent to # of uncharging events).
-active_anon    - # of bytes of anonymous and  swap cache memory on active
-                 lru list.
+swap           - # of bytes of swap usage
 inactive_anon  - # of bytes of anonymous memory and swap cache memory on
-                 inactive lru list.
-active_file    - # of bytes of file-backed memory on active lru list.
-inactive_file  - # of bytes of file-backed memory on inactive lru list.
+               LRU list.
+active_anon    - # of bytes of anonymous and swap cache memory on active
+               inactive LRU list.
+inactive_file  - # of bytes of file-backed memory on inactive LRU list.
+active_file    - # of bytes of file-backed memory on active LRU list.
 unevictable    - # of bytes of memory that cannot be reclaimed (mlocked etc).
 
-The following additional stats are dependent on CONFIG_DEBUG_VM.
+# status considering hierarchy (see memory.use_hierarchy settings)
+
+hierarchical_memory_limit - # of bytes of memory limit with regard to hierarchy
+                       under which the memory cgroup is
+hierarchical_memsw_limit - # of bytes of memory+swap limit with regard to
+                       hierarchy under which memory cgroup is.
+
+total_cache            - sum of all children's "cache"
+total_rss              - sum of all children's "rss"
+total_mapped_file      - sum of all children's "cache"
+total_pgpgin           - sum of all children's "pgpgin"
+total_pgpgout          - sum of all children's "pgpgout"
+total_swap             - sum of all children's "swap"
+total_inactive_anon    - sum of all children's "inactive_anon"
+total_active_anon      - sum of all children's "active_anon"
+total_inactive_file    - sum of all children's "inactive_file"
+total_active_file      - sum of all children's "active_file"
+total_unevictable      - sum of all children's "unevictable"
+
+# The following additional stats are dependent on CONFIG_DEBUG_VM.
 
 inactive_ratio         - VM internal parameter. (see mm/page_alloc.c)
 recent_rotated_anon    - VM internal parameter. (see mm/vmscan.c)
@@ -327,24 +421,37 @@ recent_scanned_anon       - VM internal parameter. (see mm/vmscan.c)
 recent_scanned_file    - VM internal parameter. (see mm/vmscan.c)
 
 Memo:
-       recent_rotated means recent frequency of lru rotation.
-       recent_scanned means recent # of scans to lru.
+       recent_rotated means recent frequency of LRU rotation.
+       recent_scanned means recent # of scans to LRU.
        showing for better debug please see the code for meanings.
 
 Note:
        Only anonymous and swap cache memory is listed as part of 'rss' stat.
        This should not be confused with the true 'resident set size' or the
-       amount of physical memory used by the cgroup. Per-cgroup rss
-       accounting is not done yet.
+       amount of physical memory used by the cgroup.
+       'rss + file_mapped" will give you resident set size of cgroup.
+       (Note: file and shmem may be shared among other cgroups. In that case,
+        file_mapped is accounted only when the memory cgroup is owner of page
+        cache.)
 
 5.3 swappiness
-  Similar to /proc/sys/vm/swappiness, but affecting a hierarchy of groups only.
 
-  Following cgroups' swappiness can't be changed.
-  - root cgroup (uses /proc/sys/vm/swappiness).
-  - a cgroup which uses hierarchy and it has child cgroup.
-  - a cgroup which uses hierarchy and not the root of hierarchy.
+Similar to /proc/sys/vm/swappiness, but affecting a hierarchy of groups only.
 
+Following cgroups' swappiness can't be changed.
+- root cgroup (uses /proc/sys/vm/swappiness).
+- a cgroup which uses hierarchy and it has other cgroup(s) below it.
+- a cgroup which uses hierarchy and not the root of hierarchy.
+
+5.4 failcnt
+
+A memory cgroup provides memory.failcnt and memory.memsw.failcnt files.
+This failcnt(== failure count) shows the number of times that a usage counter
+hit its limit. When a memory cgroup hits a limit, failcnt increases and
+memory under it will be reclaimed.
+
+You can reset failcnt by writing 0 to failcnt file.
+# echo 0 > .../memory.failcnt
 
 6. Hierarchy support
 
@@ -363,13 +470,13 @@ hierarchy
 
 In the diagram above, with hierarchical accounting enabled, all memory
 usage of e, is accounted to its ancestors up until the root (i.e, c and root),
-that has memory.use_hierarchy enabled.  If one of the ancestors goes over its
+that has memory.use_hierarchy enabled. If one of the ancestors goes over its
 limit, the reclaim algorithm reclaims from the tasks in the ancestor and the
 children of the ancestor.
 
 6.1 Enabling hierarchical accounting and reclaim
 
-The memory controller by default disables the hierarchy feature. Support
+A memory cgroup by default disables the hierarchy feature. Support
 can be enabled by writing 1 to memory.use_hierarchy file of the root cgroup
 
 # echo 1 > memory.use_hierarchy
@@ -379,10 +486,10 @@ The feature can be disabled by
 # echo 0 > memory.use_hierarchy
 
 NOTE1: Enabling/disabling will fail if the cgroup already has other
-cgroups created below it.
+       cgroups created below it.
 
 NOTE2: When panic_on_oom is set to "2", the whole system will panic in
-case of an oom event in any cgroup.
+       case of an OOM event in any cgroup.
 
 7. Soft limits
 
@@ -392,7 +499,7 @@ is to allow control groups to use as much of the memory as needed, provided
 a. There is no memory contention
 b. They do not exceed their hard limit
 
-When the system detects memory contention or low memory control groups
+When the system detects memory contention or low memory, control groups
 are pushed back to their soft limits. If the soft limit of each control
 group is very high, they are pushed back as much as possible to make
 sure that one control group does not starve the others of memory.
@@ -406,7 +513,7 @@ it gets invoked from balance_pgdat (kswapd).
 7.1 Interface
 
 Soft limits can be setup by using the following commands (in this example we
-assume a soft limit of 256 megabytes)
+assume a soft limit of 256 MiB)
 
 # echo 256M > memory.soft_limit_in_bytes
 
@@ -442,7 +549,7 @@ Note: Charges are moved only when you move mm->owner, IOW, a leader of a thread
 Note: If we cannot find enough space for the task in the destination cgroup, we
       try to make space by reclaiming memory. Task migration may fail if we
       cannot make enough space.
-Note: It can take several seconds if you move charges in giga bytes order.
+Note: It can take several seconds if you move charges much.
 
 And if you want disable it again:
 
@@ -451,21 +558,27 @@ And if you want disable it again:
 8.2 Type of charges which can be move
 
 Each bits of move_charge_at_immigrate has its own meaning about what type of
-charges should be moved.
+charges should be moved. But in any cases, it must be noted that an account of
+a page or a swap can be moved only when it is charged to the task's current(old)
+memory cgroup.
 
   bit | what type of charges would be moved ?
  -----+------------------------------------------------------------------------
    0  | A charge of an anonymous page(or swap of it) used by the target task.
       | Those pages and swaps must be used only by the target task. You must
       | enable Swap Extension(see 2.4) to enable move of swap charges.
-
-Note: Those pages and swaps must be charged to the old cgroup.
-Note: More type of pages(e.g. file cache, shmem,) will be supported by other
-      bits in future.
+ -----+------------------------------------------------------------------------
+   1  | A charge of file pages(normal file, tmpfs file(e.g. ipc shared memory)
+      | and swaps of tmpfs file) mmapped by the target task. Unlike the case of
+      | anonymous pages, file pages(and swaps) in the range mmapped by the task
+      | will be moved even if the task hasn't done page fault, i.e. they might
+      | not be the task's "RSS", but other task's "RSS" that maps the same file.
+      | And mapcount of the page is ignored(the page can be moved even if
+      | page_mapcount(page) > 1). You must enable Swap Extension(see 2.4) to
+      | enable move of swap charges.
 
 8.3 TODO
 
-- Add support for other types of pages(e.g. file cache, shmem, etc.).
 - Implement madvise(2) to let users decide the vma to be moved or not to be
   moved.
 - All of moving charge operations are done under cgroup_mutex. It's not good
@@ -473,22 +586,61 @@ Note: More type of pages(e.g. file cache, shmem,) will be supported by other
 
 9. Memory thresholds
 
-Memory controler implements memory thresholds using cgroups notification
+Memory cgroup implements memory thresholds using cgroups notification
 API (see cgroups.txt). It allows to register multiple memory and memsw
 thresholds and gets notifications when it crosses.
 
 To register a threshold application need:
- - create an eventfd using eventfd(2);
- - open memory.usage_in_bytes or memory.memsw.usage_in_bytes;
- - write string like "<event_fd> <memory.usage_in_bytes> <threshold>" to
-   cgroup.event_control.
+- create an eventfd using eventfd(2);
+- open memory.usage_in_bytes or memory.memsw.usage_in_bytes;
+- write string like "<event_fd> <fd of memory.usage_in_bytes> <threshold>" to
+  cgroup.event_control.
 
 Application will be notified through eventfd when memory usage crosses
 threshold in any direction.
 
 It's applicable for root and non-root cgroup.
 
-10. TODO
+10. OOM Control
+
+memory.oom_control file is for OOM notification and other controls.
+
+Memory cgroup implements OOM notifier using cgroup notification
+API (See cgroups.txt). It allows to register multiple OOM notification
+delivery and gets notification when OOM happens.
+
+To register a notifier, application need:
+ - create an eventfd using eventfd(2)
+ - open memory.oom_control file
+ - write string like "<event_fd> <fd of memory.oom_control>" to
+   cgroup.event_control
+
+Application will be notified through eventfd when OOM happens.
+OOM notification doesn't work for root cgroup.
+
+You can disable OOM-killer by writing "1" to memory.oom_control file, as:
+
+       #echo 1 > memory.oom_control
+
+This operation is only allowed to the top cgroup of sub-hierarchy.
+If OOM-killer is disabled, tasks under cgroup will hang/sleep
+in memory cgroup's OOM-waitqueue when they request accountable memory.
+
+For running them, you have to relax the memory cgroup's OOM status by
+       * enlarge limit or reduce usage.
+To reduce usage,
+       * kill some tasks.
+       * move some tasks to other group with account migration.
+       * remove some files (on tmpfs?)
+
+Then, stopped tasks will work again.
+
+At reading, current status of OOM is shown.
+       oom_kill_disable 0 or 1 (if 1, oom-killer is disabled)
+       under_oom        0 or 1 (if 1, the memory cgroup is under OOM, tasks may
+                                be stopped.)
+
+11. TODO
 
 1. Add support for accounting huge pages (as a separate controller)
 2. Make per-cgroup scanner reclaim not-shared pages first
index a86152ae2f6f6b5fc8e43b458f750d58df2e700d..672be0109d02617dfa03536c9a4fae7ad4ae4831 100644 (file)
@@ -646,3 +646,13 @@ Who:       Thomas Gleixner <tglx@linutronix.de>
 
 ----------------------------
 
+What:  old ieee1394 subsystem (CONFIG_IEEE1394)
+When:  2.6.37
+Files: drivers/ieee1394/ except init_ohci1394_dma.c
+Why:   superseded by drivers/firewire/ (CONFIG_FIREWIRE) which offers more
+       features, better performance, and better security, all with smaller
+       and more modern code base
+Who:   Stefan Richter <stefanr@s5r6.in-berlin.de>
+
+----------------------------
+
index af1608070cd599341df31c2040f8aa1b1e502a9f..61c98f03baa1da676388d15742a0a628657ec291 100644 (file)
@@ -429,8 +429,9 @@ check_flags:                no
 implementations.  If your fs is not using generic_file_llseek, you
 need to acquire and release the appropriate locks in your ->llseek().
 For many filesystems, it is probably safe to acquire the inode
-mutex.  Note some filesystems (i.e. remote ones) provide no
-protection for i_size so you will need to use the BKL.
+mutex or just to use i_size_read() instead.
+Note: this does not protect the file->f_pos against concurrent modifications
+since this is something the userspace has to take care about.
 
 Note: ext2_release() was *the* source of contention on fs-intensive
 loads and dropping BKL on ->release() helps to get rid of that (we still
index b324c033035ad097fda59b86897ae0720df9f09b..203f7202cc9e3439607d4131b5b0196b83ab7ea1 100644 (file)
@@ -38,7 +38,8 @@ Hard link support:            yes                     no
 Real inode numbers:            yes                     no
 32-bit uids/gids:              yes                     no
 File creation time:            yes                     no
-Xattr and ACL support:         no                      no
+Xattr support:                 yes                     no
+ACL support:                   no                      no
 
 Squashfs compresses data, inodes and directories.  In addition, inode and
 directory data are highly compacted, and packed on byte boundaries.  Each
@@ -58,7 +59,7 @@ obtained from this site also.
 3. SQUASHFS FILESYSTEM DESIGN
 -----------------------------
 
-A squashfs filesystem consists of seven parts, packed together on a byte
+A squashfs filesystem consists of a maximum of eight parts, packed together on a byte
 alignment:
 
         ---------------
@@ -80,6 +81,9 @@ alignment:
        |---------------|
        |    uid/gid    |
        |  lookup table |
+       |---------------|
+       |     xattr     |
+       |     table     |
         ---------------
 
 Compressed data blocks are written to the filesystem as files are read from
@@ -192,6 +196,26 @@ This table is stored compressed into metadata blocks.  A second index table is
 used to locate these.  This second index table for speed of access (and because
 it is small) is read at mount time and cached in memory.
 
+3.7 Xattr table
+---------------
+
+The xattr table contains extended attributes for each inode.  The xattrs
+for each inode are stored in a list, each list entry containing a type,
+name and value field.  The type field encodes the xattr prefix
+("user.", "trusted." etc) and it also encodes how the name/value fields
+should be interpreted.  Currently the type indicates whether the value
+is stored inline (in which case the value field contains the xattr value),
+or if it is stored out of line (in which case the value field stores a
+reference to where the actual value is stored).  This allows large values
+to be stored out of line improving scanning and lookup performance and it
+also allows values to be de-duplicated, the value being stored once, and
+all other occurences holding an out of line reference to that value.
+
+The xattr lists are packed into compressed 8K metadata blocks.
+To reduce overhead in inodes, rather than storing the on-disk
+location of the xattr list inside each inode, a 32-bit xattr id
+is stored.  This xattr id is mapped into the location of the xattr
+list using a second xattr id lookup table.
 
 4. TODOS AND OUTSTANDING ISSUES
 -------------------------------
@@ -199,9 +223,7 @@ it is small) is read at mount time and cached in memory.
 4.1 Todo list
 -------------
 
-Implement Xattr and ACL support.  The Squashfs 4.0 filesystem layout has hooks
-for these but the code has not been written.  Once the code has been written
-the existing layout should not require modification.
+Implement ACL support.
 
 4.2 Squashfs internal cache
 ---------------------------
index e93ad9425e2a162b949b015c53da2b155a897b29..a200a386429d568776c3737e860b0b2c81672c52 100644 (file)
 Started Nov 1999 by Kanoj Sarcar <kanoj@sgi.com>
 
-The intent of this file is to have an uptodate, running commentary 
-from different people about NUMA specific code in the Linux vm.
-
-What is NUMA? It is an architecture where the memory access times
-for different regions of memory from a given processor varies
-according to the "distance" of the memory region from the processor.
-Each region of memory to which access times are the same from any 
-cpu, is called a node. On such architectures, it is beneficial if
-the kernel tries to minimize inter node communications. Schemes
-for this range from kernel text and read-only data replication
-across nodes, and trying to house all the data structures that
-key components of the kernel need on memory on that node.
-
-Currently, all the numa support is to provide efficient handling
-of widely discontiguous physical memory, so architectures which 
-are not NUMA but can have huge holes in the physical address space
-can use the same code. All this code is bracketed by CONFIG_DISCONTIGMEM.
-
-The initial port includes NUMAizing the bootmem allocator code by
-encapsulating all the pieces of information into a bootmem_data_t
-structure. Node specific calls have been added to the allocator. 
-In theory, any platform which uses the bootmem allocator should 
-be able to put the bootmem and mem_map data structures anywhere
-it deems best.
-
-Each node's page allocation data structures have also been encapsulated
-into a pg_data_t. The bootmem_data_t is just one part of this. To 
-make the code look uniform between NUMA and regular UMA platforms, 
-UMA platforms have a statically allocated pg_data_t too (contig_page_data).
-For the sake of uniformity, the function num_online_nodes() is also defined
-for all platforms. As we run benchmarks, we might decide to NUMAize 
-more variables like low_on_memory, nr_free_pages etc into the pg_data_t.
-
-The NUMA aware page allocation code currently tries to allocate pages 
-from different nodes in a round robin manner.  This will be changed to 
-do concentratic circle search, starting from current node, once the 
-NUMA port achieves more maturity. The call alloc_pages_node has been 
-added, so that drivers can make the call and not worry about whether 
-it is running on a NUMA or UMA platform.
+What is NUMA?
+
+This question can be answered from a couple of perspectives:  the
+hardware view and the Linux software view.
+
+From the hardware perspective, a NUMA system is a computer platform that
+comprises multiple components or assemblies each of which may contain 0
+or more CPUs, local memory, and/or IO buses.  For brevity and to
+disambiguate the hardware view of these physical components/assemblies
+from the software abstraction thereof, we'll call the components/assemblies
+'cells' in this document.
+
+Each of the 'cells' may be viewed as an SMP [symmetric multi-processor] subset
+of the system--although some components necessary for a stand-alone SMP system
+may not be populated on any given cell.   The cells of the NUMA system are
+connected together with some sort of system interconnect--e.g., a crossbar or
+point-to-point link are common types of NUMA system interconnects.  Both of
+these types of interconnects can be aggregated to create NUMA platforms with
+cells at multiple distances from other cells.
+
+For Linux, the NUMA platforms of interest are primarily what is known as Cache
+Coherent NUMA or ccNUMA systems.   With ccNUMA systems, all memory is visible
+to and accessible from any CPU attached to any cell and cache coherency
+is handled in hardware by the processor caches and/or the system interconnect.
+
+Memory access time and effective memory bandwidth varies depending on how far
+away the cell containing the CPU or IO bus making the memory access is from the
+cell containing the target memory.  For example, access to memory by CPUs
+attached to the same cell will experience faster access times and higher
+bandwidths than accesses to memory on other, remote cells.  NUMA platforms
+can have cells at multiple remote distances from any given cell.
+
+Platform vendors don't build NUMA systems just to make software developers'
+lives interesting.  Rather, this architecture is a means to provide scalable
+memory bandwidth.  However, to achieve scalable memory bandwidth, system and
+application software must arrange for a large majority of the memory references
+[cache misses] to be to "local" memory--memory on the same cell, if any--or
+to the closest cell with memory.
+
+This leads to the Linux software view of a NUMA system:
+
+Linux divides the system's hardware resources into multiple software
+abstractions called "nodes".  Linux maps the nodes onto the physical cells
+of the hardware platform, abstracting away some of the details for some
+architectures.  As with physical cells, software nodes may contain 0 or more
+CPUs, memory and/or IO buses.  And, again, memory accesses to memory on
+"closer" nodes--nodes that map to closer cells--will generally experience
+faster access times and higher effective bandwidth than accesses to more
+remote cells.
+
+For some architectures, such as x86, Linux will "hide" any node representing a
+physical cell that has no memory attached, and reassign any CPUs attached to
+that cell to a node representing a cell that does have memory.  Thus, on
+these architectures, one cannot assume that all CPUs that Linux associates with
+a given node will see the same local memory access times and bandwidth.
+
+In addition, for some architectures, again x86 is an example, Linux supports
+the emulation of additional nodes.  For NUMA emulation, linux will carve up
+the existing nodes--or the system memory for non-NUMA platforms--into multiple
+nodes.  Each emulated node will manage a fraction of the underlying cells'
+physical memory.  NUMA emluation is useful for testing NUMA kernel and
+application features on non-NUMA platforms, and as a sort of memory resource
+management mechanism when used together with cpusets.
+[see Documentation/cgroups/cpusets.txt]
+
+For each node with memory, Linux constructs an independent memory management
+subsystem, complete with its own free page lists, in-use page lists, usage
+statistics and locks to mediate access.  In addition, Linux constructs for
+each memory zone [one or more of DMA, DMA32, NORMAL, HIGH_MEMORY, MOVABLE],
+an ordered "zonelist".  A zonelist specifies the zones/nodes to visit when a
+selected zone/node cannot satisfy the allocation request.  This situation,
+when a zone has no available memory to satisfy a request, is called
+"overflow" or "fallback".
+
+Because some nodes contain multiple zones containing different types of
+memory, Linux must decide whether to order the zonelists such that allocations
+fall back to the same zone type on a different node, or to a different zone
+type on the same node.  This is an important consideration because some zones,
+such as DMA or DMA32, represent relatively scarce resources.  Linux chooses
+a default zonelist order based on the sizes of the various zone types relative
+to the total memory of the node and the total memory of the system.  The
+default zonelist order may be overridden using the numa_zonelist_order kernel
+boot parameter or sysctl.  [see Documentation/kernel-parameters.txt and
+Documentation/sysctl/vm.txt]
+
+By default, Linux will attempt to satisfy memory allocation requests from the
+node to which the CPU that executes the request is assigned.  Specifically,
+Linux will attempt to allocate from the first node in the appropriate zonelist
+for the node where the request originates.  This is called "local allocation."
+If the "local" node cannot satisfy the request, the kernel will examine other
+nodes' zones in the selected zonelist looking for the first zone in the list
+that can satisfy the request.
+
+Local allocation will tend to keep subsequent access to the allocated memory
+"local" to the underlying physical resources and off the system interconnect--
+as long as the task on whose behalf the kernel allocated some memory does not
+later migrate away from that memory.  The Linux scheduler is aware of the
+NUMA topology of the platform--embodied in the "scheduling domains" data
+structures [see Documentation/scheduler/sched-domains.txt]--and the scheduler
+attempts to minimize task migration to distant scheduling domains.  However,
+the scheduler does not take a task's NUMA footprint into account directly.
+Thus, under sufficient imbalance, tasks can migrate between nodes, remote
+from their initial node and kernel data structures.
+
+System administrators and application designers can restrict a task's migration
+to improve NUMA locality using various CPU affinity command line interfaces,
+such as taskset(1) and numactl(1), and program interfaces such as
+sched_setaffinity(2).  Further, one can modify the kernel's default local
+allocation behavior using Linux NUMA memory policy.
+[see Documentation/vm/numa_memory_policy.]
+
+System administrators can restrict the CPUs and nodes' memories that a non-
+privileged user can specify in the scheduling or NUMA commands and functions
+using control groups and CPUsets.  [see Documentation/cgroups/CPUsets.txt]
+
+On architectures that do not hide memoryless nodes, Linux will include only
+zones [nodes] with memory in the zonelists.  This means that for a memoryless
+node the "local memory node"--the node of the first zone in CPU's node's
+zonelist--will not be the node itself.  Rather, it will be the node that the
+kernel selected as the nearest node with memory when it built the zonelists.
+So, default, local allocations will succeed with the kernel supplying the
+closest available memory.  This is a consequence of the same mechanism that
+allows such allocations to fallback to other nearby nodes when a node that
+does contain memory overflows.
+
+Some kernel allocations do not want or cannot tolerate this allocation fallback
+behavior.  Rather they want to be sure they get memory from the specified node
+or get notified that the node has no free memory.  This is usually the case when
+a subsystem allocates per CPU memory resources, for example.
+
+A typical model for making such an allocation is to obtain the node id of the
+node to which the "current CPU" is attached using one of the kernel's
+numa_node_id() or CPU_to_node() functions and then request memory from only
+the node id returned.  When such an allocation fails, the requesting subsystem
+may revert to its own fallback path.  The slab kernel memory allocator is an
+example of this.  Or, the subsystem may choose to disable or not to enable
+itself on allocation failure.  The kernel profiling subsystem is an example of
+this.
+
+If the architecture supports--does not hide--memoryless nodes, then CPUs
+attached to memoryless nodes would always incur the fallback path overhead
+or some subsystems would fail to initialize if they attempted to allocated
+memory exclusively from a node without memory.  To support such
+architectures transparently, kernel subsystems can use the numa_mem_id()
+or cpu_to_mem() function to locate the "local memory node" for the calling or
+specified CPU.  Again, this is the same node from which default, local page
+allocations will be attempted.
index a8fe9b461e09c64df9e4cf618ced7f588a4fea7b..8b7eba2de603f08b131650b027d8dd82e69c0373 100644 (file)
@@ -969,6 +969,18 @@ M: Wan ZongShun <mcuos.com@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.mcuos.com
 S:     Maintained
+F:     arch/arm/mach-w90x900/
+F:     arch/arm/mach-nuc93x/
+F:     drivers/input/keyboard/w90p910_keypad.c
+F:     drivers/input/touchscreen/w90p910_ts.c
+F:     drivers/watchdog/nuc900_wdt.c
+F:     drivers/net/arm/w90p910_ether.c
+F:     drivers/mtd/nand/w90p910_nand.c
+F:     drivers/rtc/rtc-nuc900.c
+F:     drivers/spi/spi_nuc900.c
+F:     drivers/usb/host/ehci-w90x900.c
+F:     drivers/video/nuc900fb.c
+F:     drivers/sound/soc/nuc900/
 
 ARM/U300 MACHINE SUPPORT
 M:     Linus Walleij <linus.walleij@stericsson.com>
@@ -4992,6 +5004,12 @@ L:       linux-mmc@vger.kernel.org
 S:     Maintained
 F:     drivers/mmc/host/sdhci-s3c.c
 
+SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) ST SPEAR DRIVER
+M:     Viresh Kumar <viresh.kumar@st.com>
+L:     linux-mmc@vger.kernel.org
+S:     Maintained
+F:     drivers/mmc/host/sdhci-spear.c
+
 SECURITY SUBSYSTEM
 M:     James Morris <jmorris@namei.org>
 L:     linux-security-module@vger.kernel.org (suggested Cc:)
index 24efdfe277fc3977bce3815d0470b335d1bb9777..3e2e540a0f2a85ce92aa0a70f604bc4a461c3517 100644 (file)
@@ -61,6 +61,9 @@ config ZONE_DMA
 config NEED_DMA_MAP_STATE
        def_bool y
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config GENERIC_ISA_DMA
        bool
        default y
index 440747ca6349058d31f04b6191ed2de0870ce557..5728c52a7412307c49c78098b72918d42499ac8b 100644 (file)
@@ -1,24 +1,7 @@
 #ifndef _ALPHA_SCATTERLIST_H
 #define _ALPHA_SCATTERLIST_H
 
-#include <asm/page.h>
-#include <asm/types.h>
-  
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-
-       unsigned int length;
-
-       dma_addr_t dma_address;
-       __u32 dma_length;
-};
-
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->dma_length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (~0UL)
 
index d4c6ae7fee477aa0c4c0b6f944748735c8ee4627..f53707f7745569c3a1ab48526ccf5d6753a1221e 100644 (file)
@@ -28,3 +28,8 @@ extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long,
 #define UDIV_NEEDS_NORMALIZATION 1  
 
 #define abort()                        goto bad_insn
+
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN -1
+#endif
+#define __BYTE_ORDER __LITTLE_ENDIAN
index bcda59f399417d3d3493a7a9800a59c900094751..2f87870d93471d79d9913da8fadfcb9f1b3efe67 100644 (file)
@@ -3,9 +3,6 @@
 
 #include <asm/memory.h>
 #include <asm/types.h>
-
 #include <asm-generic/scatterlist.h>
 
-#undef ARCH_HAS_SG_CHAIN
-
 #endif /* _ASMARM_SCATTERLIST_H */
index 5a85e24f36730c759173da5810ca5f6a9fa298d1..d4f1e9675069514015bce168140bb46fa2322d42 100644 (file)
@@ -22,6 +22,9 @@ struct davinci_mmc_config {
 
        /* Version of the MMC/SD controller */
        u8      version;
+
+       /* Number of sg segments */
+       u8      nr_sg;
 };
 void davinci_setup_mmc(int module, struct davinci_mmc_config *config);
 
index e7d629b3c76aca4c20038863cc78cf3cf6a008aa..f474a80b886733582af7f3dba04929ce02cd561b 100644 (file)
@@ -137,9 +137,7 @@ static void ads7846_dev_init(void)
        }
 
        gpio_direction_input(ts_gpio);
-
-       omap_set_gpio_debounce(ts_gpio, 1);
-       omap_set_gpio_debounce_time(ts_gpio, 0xa);
+       gpio_set_debounce(ts_gpio, 310);
 }
 
 static int ads7846_get_pendown_state(void)
index 5fcb52e71298a8846f29734f3f96951546ff2d90..fefd7e6e97796a9ede0ce8076de96f9ee437fb9d 100644 (file)
@@ -209,8 +209,7 @@ static void ads7846_dev_init(void)
        }
 
        gpio_direction_input(ts_gpio);
-       omap_set_gpio_debounce(ts_gpio, 1);
-       omap_set_gpio_debounce_time(ts_gpio, 0xa);
+       gpio_set_debounce(ts_gpio, 310);
 }
 
 static int ads7846_get_pendown_state(void)
index 81bba194b030b46804f4e215a99a849a3ab03159..b952610138121862368aab2296ef30552bdc5528 100644 (file)
@@ -579,9 +579,7 @@ static void ads7846_dev_init(void)
                printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
 
        gpio_direction_input(OMAP3_EVM_TS_GPIO);
-
-       omap_set_gpio_debounce(OMAP3_EVM_TS_GPIO, 1);
-       omap_set_gpio_debounce_time(OMAP3_EVM_TS_GPIO, 0xa);
+       gpio_set_debounce(OMAP3_EVM_TS_GPIO, 310);
 }
 
 static int ads7846_get_pendown_state(void)
index 395d049bf010ad8f67e050cd4877ab7c54f4399e..db06dc910ba755c6988cc11155c3f047dff3c792 100644 (file)
@@ -130,8 +130,8 @@ static struct platform_device pandora_keys_gpio = {
 static void __init pandora_keys_gpio_init(void)
 {
        /* set debounce time for GPIO banks 4 and 6 */
-       omap_set_gpio_debounce_time(32 * 3, GPIO_DEBOUNCE_TIME);
-       omap_set_gpio_debounce_time(32 * 5, GPIO_DEBOUNCE_TIME);
+       gpio_set_debounce(32 * 3, GPIO_DEBOUNCE_TIME);
+       gpio_set_debounce(32 * 5, GPIO_DEBOUNCE_TIME);
 }
 
 static int board_keymap[] = {
index 2504d41f923e01bcbf6dd82b92ceb03139c1c8bf..2f5f8233dd5b8857bcfddb29d178f802fbd1271f 100644 (file)
@@ -328,8 +328,7 @@ static void __init omap3_ads7846_init(void)
        }
 
        gpio_direction_input(OMAP3_TS_GPIO);
-       omap_set_gpio_debounce(OMAP3_TS_GPIO, 1);
-       omap_set_gpio_debounce_time(OMAP3_TS_GPIO, 0xa);
+       gpio_set_debounce(OMAP3_TS_GPIO, 310);
 }
 
 static struct ads7846_platform_data ads7846_config = {
index dc2ac42d63195f0dbe6c3b7acd964eef117e9661..393e9219a5b68afe61f6416c3fac531cc188cefc 100644 (file)
@@ -624,79 +624,58 @@ do {      \
        __raw_writel(l, base + reg); \
 } while(0)
 
-void omap_set_gpio_debounce(int gpio, int enable)
+/**
+ * _set_gpio_debounce - low level gpio debounce time
+ * @bank: the gpio bank we're acting upon
+ * @gpio: the gpio number on this @gpio
+ * @debounce: debounce time to use
+ *
+ * OMAP's debounce time is in 31us steps so we need
+ * to convert and round up to the closest unit.
+ */
+static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
+               unsigned debounce)
 {
-       struct gpio_bank *bank;
-       void __iomem *reg;
-       unsigned long flags;
-       u32 val, l = 1 << get_gpio_index(gpio);
+       void __iomem            *reg = bank->base;
+       u32                     val;
+       u32                     l;
+
+       if (debounce < 32)
+               debounce = 0x01;
+       else if (debounce > 7936)
+               debounce = 0xff;
+       else
+               debounce = (debounce / 0x1f) - 1;
 
-       if (cpu_class_is_omap1())
-               return;
+       l = 1 << get_gpio_index(gpio);
 
-       bank = get_gpio_bank(gpio);
-       reg = bank->base;
+       if (cpu_is_omap44xx())
+               reg += OMAP4_GPIO_DEBOUNCINGTIME;
+       else
+               reg += OMAP24XX_GPIO_DEBOUNCE_VAL;
+
+       __raw_writel(debounce, reg);
 
+       reg = bank->base;
        if (cpu_is_omap44xx())
                reg += OMAP4_GPIO_DEBOUNCENABLE;
        else
                reg += OMAP24XX_GPIO_DEBOUNCE_EN;
 
-       if (!(bank->mod_usage & l)) {
-               printk(KERN_ERR "GPIO %d not requested\n", gpio);
-               return;
-       }
-
-       spin_lock_irqsave(&bank->lock, flags);
        val = __raw_readl(reg);
 
-       if (enable && !(val & l))
+       if (debounce) {
                val |= l;
-       else if (!enable && (val & l))
-               val &= ~l;
-       else
-               goto done;
-
-       if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
-               bank->dbck_enable_mask = val;
-               if (enable)
+               if (cpu_is_omap34xx() || cpu_is_omap44xx())
                        clk_enable(bank->dbck);
-               else
+       } else {
+               val &= ~l;
+               if (cpu_is_omap34xx() || cpu_is_omap44xx())
                        clk_disable(bank->dbck);
        }
 
        __raw_writel(val, reg);
-done:
-       spin_unlock_irqrestore(&bank->lock, flags);
 }
-EXPORT_SYMBOL(omap_set_gpio_debounce);
-
-void omap_set_gpio_debounce_time(int gpio, int enc_time)
-{
-       struct gpio_bank *bank;
-       void __iomem *reg;
-
-       if (cpu_class_is_omap1())
-               return;
-
-       bank = get_gpio_bank(gpio);
-       reg = bank->base;
-
-       if (!bank->mod_usage) {
-               printk(KERN_ERR "GPIO not requested\n");
-               return;
-       }
-
-       enc_time &= 0xff;
-
-       if (cpu_is_omap44xx())
-               reg += OMAP4_GPIO_DEBOUNCINGTIME;
-       else
-               reg += OMAP24XX_GPIO_DEBOUNCE_VAL;
-
-       __raw_writel(enc_time, reg);
-}
-EXPORT_SYMBOL(omap_set_gpio_debounce_time);
 
 #ifdef CONFIG_ARCH_OMAP2PLUS
 static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio,
@@ -1656,6 +1635,20 @@ static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
        return 0;
 }
 
+static int gpio_debounce(struct gpio_chip *chip, unsigned offset,
+               unsigned debounce)
+{
+       struct gpio_bank *bank;
+       unsigned long flags;
+
+       bank = container_of(chip, struct gpio_bank, chip);
+       spin_lock_irqsave(&bank->lock, flags);
+       _set_gpio_debounce(bank, offset, debounce);
+       spin_unlock_irqrestore(&bank->lock, flags);
+
+       return 0;
+}
+
 static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct gpio_bank *bank;
@@ -1909,6 +1902,7 @@ static int __init _omap_gpio_init(void)
                bank->chip.direction_input = gpio_input;
                bank->chip.get = gpio_get;
                bank->chip.direction_output = gpio_output;
+               bank->chip.set_debounce = gpio_debounce;
                bank->chip.set = gpio_set;
                bank->chip.to_irq = gpio_2irq;
                if (bank_is_mpuio(bank)) {
index 377320e3bd1741b19d7c5acdc2ad2de78502ae6a..06394e5ead6c51543c71ea16793cd6cad371589d 100644 (file)
@@ -1,25 +1,7 @@
 #ifndef __ASM_AVR32_SCATTERLIST_H
 #define __ASM_AVR32_SCATTERLIST_H
 
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-   unsigned long       sg_magic;
-#endif
-    unsigned long      page_link;
-    unsigned int       offset;
-    dma_addr_t         dma_address;
-    unsigned int       length;
-};
-
-/* These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns.
- */
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0xffffffff)
 
index 04f448711cd09eb1755875b87bfe2db353aff15f..64d41d34ab0b84cafce79f11bcddfa812d8682ff 100644 (file)
@@ -1,27 +1,7 @@
 #ifndef _BLACKFIN_SCATTERLIST_H
 #define _BLACKFIN_SCATTERLIST_H
 
-#include <linux/mm.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-       dma_addr_t dma_address;
-       unsigned int length;
-};
-
-/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg)      ((sg)->dma_address)
-#define sg_dma_len(sg)          ((sg)->length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD      (0xffffffff)
 
index 43eb969405d1657bd0aba85b2528e9d28296bd55..6ec77685df526899c6998fe3030513714d42d5a8 100644 (file)
@@ -292,28 +292,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        break;
                }
 
-#ifdef CONFIG_BINFMT_ELF_FDPIC
-       case PTRACE_GETFDPIC: {
-               unsigned long tmp = 0;
-
-               switch (addr) {
-               case_PTRACE_GETFDPIC_EXEC:
-               case PTRACE_GETFDPIC_EXEC:
-                       tmp = child->mm->context.exec_fdpic_loadmap;
-                       break;
-               case_PTRACE_GETFDPIC_INTERP:
-               case PTRACE_GETFDPIC_INTERP:
-                       tmp = child->mm->context.interp_fdpic_loadmap;
-                       break;
-               default:
-                       break;
-               }
-
-               ret = put_user(tmp, datap);
-               break;
-       }
-#endif
-
                /* when I and D space are separate, this will have to be fixed. */
        case PTRACE_POKEDATA:
                pr_debug("ptrace: PTRACE_PEEKDATA\n");
@@ -357,8 +335,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        case PTRACE_PEEKUSR:
                switch (addr) {
 #ifdef CONFIG_BINFMT_ELF_FDPIC /* backwards compat */
-               case PT_FDPIC_EXEC:   goto case_PTRACE_GETFDPIC_EXEC;
-               case PT_FDPIC_INTERP: goto case_PTRACE_GETFDPIC_INTERP;
+               case PT_FDPIC_EXEC:
+                       request = PTRACE_GETFDPIC;
+                       addr = PTRACE_GETFDPIC_EXEC;
+                       goto case_default;
+               case PT_FDPIC_INTERP:
+                       request = PTRACE_GETFDPIC;
+                       addr = PTRACE_GETFDPIC_INTERP;
+                       goto case_default;
 #endif
                default:
                        ret = get_reg(child, addr, datap);
@@ -385,6 +369,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                             0, sizeof(struct pt_regs),
                                             (const void __user *)data);
 
+       case_default:
        default:
                ret = ptrace_request(child, request, addr, data);
                break;
index faff53ad1f96cd56327caf8c182ad70c81fc161f..249a7842ff5f906280fba7b1fa0a5affdeccee1d 100644 (file)
@@ -1,22 +1,7 @@
 #ifndef __ASM_CRIS_SCATTERLIST_H
 #define __ASM_CRIS_SCATTERLIST_H
 
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       char *  address;    /* Location data is to be transferred to */
-       unsigned int length;
-
-       /* The following is i386 highmem junk - not used by us */
-       unsigned long page_link;
-       unsigned int offset;/* for highmem, page offset */
-
-};
-
-#define sg_dma_address(sg)     ((sg)->address)
-#define sg_dma_len(sg)         ((sg)->length)
-/* i386 junk */
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0x1fffffff)
 
index 4bca8a28546c2474e6300d041e117186175dc0ea..1614bfd7e3a4bb8902509ea7eb04fd7e31020710 100644 (file)
@@ -1,45 +1,7 @@
 #ifndef _ASM_SCATTERLIST_H
 #define _ASM_SCATTERLIST_H
 
-#include <asm/types.h>
-
-/*
- * Drivers must set either ->address or (preferred) page and ->offset
- * to indicate where data must be transferred to/from.
- *
- * Using page is recommended since it handles highmem data as well as
- * low mem. ->address is restricted to data which has a virtual mapping, and
- * it will go away in the future. Updating to page can be automated very
- * easily -- something like
- *
- * sg->address = some_ptr;
- *
- * can be rewritten as
- *
- * sg_set_buf(sg, some_ptr, length);
- *
- * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens
- */
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;         /* for highmem, page offset */
-
-       dma_addr_t      dma_address;
-       unsigned int    length;
-};
-
-/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0xffffffffUL)
 
index 60eeed3694c0764d2d0b9d7d3a0c2cffe14b9a89..fac028936a041aab80f80506901e643787caaf3b 100644 (file)
@@ -344,26 +344,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                             0, sizeof(child->thread.user->f),
                                             (const void __user *)data);
 
-       case PTRACE_GETFDPIC:
-               tmp = 0;
-               switch (addr) {
-               case PTRACE_GETFDPIC_EXEC:
-                       tmp = child->mm->context.exec_fdpic_loadmap;
-                       break;
-               case PTRACE_GETFDPIC_INTERP:
-                       tmp = child->mm->context.interp_fdpic_loadmap;
-                       break;
-               default:
-                       break;
-               }
-
-               ret = 0;
-               if (put_user(tmp, (unsigned long *) data)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               break;
-
        default:
                ret = ptrace_request(child, request, addr, data);
                break;
index 71abd1510a59d5e453b5a4567c237a32a1f18a44..6c155d69da297b9f7d9b0dcab63814ccf095fd8e 100644 (file)
@@ -46,8 +46,9 @@ static void frv_change_dcache_mode(unsigned long newmode)
 /*
  * handle requests to dynamically switch the write caching mode delivered by /proc
  */
-static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp,
-                                void __user *buffer, size_t *lenp, loff_t *ppos)
+static int procctl_frv_cachemode(ctl_table *table, int write,
+                                void __user *buffer, size_t *lenp,
+                                loff_t *ppos)
 {
        unsigned long hsr0;
        char buff[8];
@@ -84,7 +85,7 @@ static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp,
        }
 
        /* read the state */
-       if (filp->f_pos > 0) {
+       if (*ppos > 0) {
                *lenp = 0;
                return 0;
        }
@@ -110,7 +111,7 @@ static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp,
                return -EFAULT;
 
        *lenp = len;
-       filp->f_pos = len;
+       *ppos = len;
        return 0;
 
 } /* end procctl_frv_cachemode() */
@@ -120,8 +121,9 @@ static int procctl_frv_cachemode(ctl_table *table, int write, struct file *filp,
  * permit the mm_struct the nominated process is using have its MMU context ID pinned
  */
 #ifdef CONFIG_MMU
-static int procctl_frv_pin_cxnr(ctl_table *table, int write, struct file *filp,
-                               void __user *buffer, size_t *lenp, loff_t *ppos)
+static int procctl_frv_pin_cxnr(ctl_table *table, int write,
+                               void __user *buffer, size_t *lenp,
+                               loff_t *ppos)
 {
        pid_t pid;
        char buff[16], *p;
@@ -150,7 +152,7 @@ static int procctl_frv_pin_cxnr(ctl_table *table, int write, struct file *filp,
        }
 
        /* read the currently pinned CXN */
-       if (filp->f_pos > 0) {
+       if (*ppos > 0) {
                *lenp = 0;
                return 0;
        }
@@ -163,7 +165,7 @@ static int procctl_frv_pin_cxnr(ctl_table *table, int write, struct file *filp,
                return -EFAULT;
 
        *lenp = len;
-       filp->f_pos = len;
+       *ppos = len;
        return 0;
 
 } /* end procctl_frv_pin_cxnr() */
index d3ecdd87ac90b0ca8642d6d38886f6afc14a56fe..de08a4a2cc1c4f76cb9c403d5b33a04b04f242b0 100644 (file)
@@ -1,17 +1,7 @@
 #ifndef _H8300_SCATTERLIST_H
 #define _H8300_SCATTERLIST_H
 
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;
-       dma_addr_t      dma_address;
-       unsigned int    length;
-};
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD      (0xffffffff)
 
index 9676100b83ee02563047459766d81ba59d701beb..95610820041ea33bf76f9097fcab9d2312a475ea 100644 (file)
@@ -56,6 +56,9 @@ config MMU
 config NEED_DMA_MAP_STATE
        def_bool y
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config SWIOTLB
        bool
 
@@ -495,6 +498,14 @@ config HAVE_ARCH_NODEDATA_EXTENSION
        def_bool y
        depends on NUMA
 
+config USE_PERCPU_NUMA_NODE_ID
+       def_bool y
+       depends on NUMA
+
+config HAVE_MEMORYLESS_NODES
+       def_bool y
+       depends on NUMA
+
 config ARCH_PROC_KCORE_TEXT
        def_bool y
        depends on PROC_KCORE
index d8e98961dec77e42be573f1778b6d69a542c21a2..f299a4fb25c86e08fb516fcb1fa22e6df8bab1e1 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _ASM_IA64_SCATTERLIST_H
 #define _ASM_IA64_SCATTERLIST_H
 
+#include <asm-generic/scatterlist.h>
 /*
  * It used to be that ISA_DMA_THRESHOLD had something to do with the
  * DMA-limits of ISA-devices.  Nowadays, its only remaining use (apart
@@ -10,7 +11,6 @@
  * that's 4GB - 1.
  */
 #define ISA_DMA_THRESHOLD      0xffffffff
-
-#include <asm-generic/scatterlist.h>
+#define ARCH_HAS_SG_CHAIN
 
 #endif /* _ASM_IA64_SCATTERLIST_H */
index d323071d0f915e95ad60d6c45974a4e9788aedae..09f646753d1aa2203c2b0942f2294ae0e11d6e67 100644 (file)
  */
 #define RECLAIM_DISTANCE 15
 
-/*
- * Returns the number of the node containing CPU 'cpu'
- */
-#define cpu_to_node(cpu) (int)(cpu_to_node_map[cpu])
-
 /*
  * Returns a bitmask of CPUs on Node 'node'.
  */
index 3095654f9ab394839b9ae52509b5ec786c9f7837..d9485d952ed0a8c26fe8677b09e5ba249a5f9c25 100644 (file)
@@ -31,8 +31,6 @@ struct dma_map_ops swiotlb_dma_ops = {
        .unmap_sg = swiotlb_unmap_sg_attrs,
        .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
        .sync_single_for_device = swiotlb_sync_single_for_device,
-       .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
-       .sync_single_range_for_device = swiotlb_sync_single_range_for_device,
        .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
        .sync_sg_for_device = swiotlb_sync_sg_for_device,
        .dma_supported = swiotlb_dma_supported,
index 0dec7f702448a07b6fc520342969411423d6445a..7c7909f9bc938b1bda4f1ece171ebd962aec2cfd 100644 (file)
@@ -638,7 +638,7 @@ ptrace_attach_sync_user_rbs (struct task_struct *child)
         */
 
        read_lock(&tasklist_lock);
-       if (child->signal) {
+       if (child->sighand) {
                spin_lock_irq(&child->sighand->siglock);
                if (child->state == TASK_STOPPED &&
                    !test_and_set_tsk_thread_flag(child, TIF_RESTORE_RSE)) {
@@ -662,7 +662,7 @@ ptrace_attach_sync_user_rbs (struct task_struct *child)
         * job control stop, so that SIGCONT can be used to wake it up.
         */
        read_lock(&tasklist_lock);
-       if (child->signal) {
+       if (child->sighand) {
                spin_lock_irq(&child->sighand->siglock);
                if (child->state == TASK_TRACED &&
                    (child->signal->flags & SIGNAL_STOP_STOPPED)) {
index e5230b2ff2c5e4dbc7d74d84c4142d0634e92a63..518e876a410da1467608d4ea20ed03c2f606def4 100644 (file)
@@ -390,6 +390,12 @@ smp_callin (void)
 
        fix_b0_for_bsp();
 
+       /*
+        * numa_node_id() works after this.
+        */
+       set_numa_node(cpu_to_node_map[cpuid]);
+       set_numa_mem(local_memory_node(cpu_to_node_map[cpuid]));
+
        ipi_call_lock_irq();
        spin_lock(&vector_lock);
        /* Setup the per cpu irq handling data structures */
@@ -632,6 +638,7 @@ void __devinit smp_prepare_boot_cpu(void)
 {
        cpu_set(smp_processor_id(), cpu_online_map);
        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;
        paravirt_post_smp_prepare_boot_cpu();
 }
index 1ed372c73d0bd9ef05f143289ccecc77cbc3ada5..aeeddd8dac17b7feb6726e73ff3b7c61ce193ba1 100644 (file)
@@ -1,20 +1,7 @@
 #ifndef _ASM_M32R_SCATTERLIST_H
 #define _ASM_M32R_SCATTERLIST_H
 
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-    unsigned long sg_magic;
-#endif
-    char *  address;    /* Location data is to be transferred to, NULL for
-                         * highmem page */
-    unsigned long page_link;
-    unsigned int offset;/* for highmem, page offset */
-
-    dma_addr_t dma_address;
-    unsigned int length;
-};
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0x1fffffff)
 
index b5da298ba61df539b07bcadd8ef979d465215d5d..2e3737b92ffca3e36d0005317feee1d38dee526e 100644 (file)
@@ -7,6 +7,7 @@ config M68K
        default y
        select HAVE_AOUT
        select HAVE_IDE
+       select GENERIC_ATOMIC64
 
 config MMU
        bool
index d2cc35d985328f7a240ad85216fc9123820be008..b1577f741fa8c46789c4324662dcb87f6a6369ce 100644 (file)
@@ -97,10 +97,6 @@ static void amiga_get_model(char *model);
 static void amiga_get_hardware_list(struct seq_file *m);
 /* amiga specific timer functions */
 static unsigned long amiga_gettimeoffset(void);
-static int a3000_hwclk(int, struct rtc_time *);
-static int a2000_hwclk(int, struct rtc_time *);
-static int amiga_set_clock_mmss(unsigned long);
-static unsigned int amiga_get_ss(void);
 extern void amiga_mksound(unsigned int count, unsigned int ticks);
 static void amiga_reset(void);
 extern void amiga_init_sound(void);
@@ -138,10 +134,6 @@ static struct {
        }
 };
 
-static struct resource rtc_resource = {
-       .start = 0x00dc0000, .end = 0x00dcffff
-};
-
 static struct resource ram_resource[NUM_MEMINFO];
 
 
@@ -387,15 +379,6 @@ void __init config_amiga(void)
        mach_get_model       = amiga_get_model;
        mach_get_hardware_list = amiga_get_hardware_list;
        mach_gettimeoffset   = amiga_gettimeoffset;
-       if (AMIGAHW_PRESENT(A3000_CLK)) {
-               mach_hwclk         = a3000_hwclk;
-               rtc_resource.name = "A3000 RTC";
-               request_resource(&iomem_resource, &rtc_resource);
-       } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-               mach_hwclk         = a2000_hwclk;
-               rtc_resource.name = "A2000 RTC";
-               request_resource(&iomem_resource, &rtc_resource);
-       }
 
        /*
         * default MAX_DMA=0xffffffff on all machines. If we don't do so, the SCSI
@@ -404,8 +387,6 @@ void __init config_amiga(void)
         */
        mach_max_dma_address = 0xffffffff;
 
-       mach_set_clock_mmss  = amiga_set_clock_mmss;
-       mach_get_ss          = amiga_get_ss;
        mach_reset           = amiga_reset;
 #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
        mach_beep            = amiga_mksound;
@@ -530,161 +511,6 @@ static unsigned long amiga_gettimeoffset(void)
        return ticks + offset;
 }
 
-static int a3000_hwclk(int op, struct rtc_time *t)
-{
-       tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
-
-       if (!op) { /* read */
-               t->tm_sec  = tod_3000.second1 * 10 + tod_3000.second2;
-               t->tm_min  = tod_3000.minute1 * 10 + tod_3000.minute2;
-               t->tm_hour = tod_3000.hour1   * 10 + tod_3000.hour2;
-               t->tm_mday = tod_3000.day1    * 10 + tod_3000.day2;
-               t->tm_wday = tod_3000.weekday;
-               t->tm_mon  = tod_3000.month1  * 10 + tod_3000.month2 - 1;
-               t->tm_year = tod_3000.year1   * 10 + tod_3000.year2;
-               if (t->tm_year <= 69)
-                       t->tm_year += 100;
-       } else {
-               tod_3000.second1 = t->tm_sec / 10;
-               tod_3000.second2 = t->tm_sec % 10;
-               tod_3000.minute1 = t->tm_min / 10;
-               tod_3000.minute2 = t->tm_min % 10;
-               tod_3000.hour1   = t->tm_hour / 10;
-               tod_3000.hour2   = t->tm_hour % 10;
-               tod_3000.day1    = t->tm_mday / 10;
-               tod_3000.day2    = t->tm_mday % 10;
-               if (t->tm_wday != -1)
-                       tod_3000.weekday = t->tm_wday;
-               tod_3000.month1  = (t->tm_mon + 1) / 10;
-               tod_3000.month2  = (t->tm_mon + 1) % 10;
-               if (t->tm_year >= 100)
-                       t->tm_year -= 100;
-               tod_3000.year1   = t->tm_year / 10;
-               tod_3000.year2   = t->tm_year % 10;
-       }
-
-       tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
-
-       return 0;
-}
-
-static int a2000_hwclk(int op, struct rtc_time *t)
-{
-       int cnt = 5;
-
-       tod_2000.cntrl1 = TOD2000_CNTRL1_HOLD;
-
-       while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt) {
-               tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
-               udelay(70);
-               tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
-               --cnt;
-       }
-
-       if (!cnt)
-               printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n",
-                       tod_2000.cntrl1);
-
-       if (!op) { /* read */
-               t->tm_sec  = tod_2000.second1     * 10 + tod_2000.second2;
-               t->tm_min  = tod_2000.minute1     * 10 + tod_2000.minute2;
-               t->tm_hour = (tod_2000.hour1 & 3) * 10 + tod_2000.hour2;
-               t->tm_mday = tod_2000.day1        * 10 + tod_2000.day2;
-               t->tm_wday = tod_2000.weekday;
-               t->tm_mon  = tod_2000.month1      * 10 + tod_2000.month2 - 1;
-               t->tm_year = tod_2000.year1       * 10 + tod_2000.year2;
-               if (t->tm_year <= 69)
-                       t->tm_year += 100;
-
-               if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)) {
-                       if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
-                               t->tm_hour = 0;
-                       else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
-                               t->tm_hour += 12;
-               }
-       } else {
-               tod_2000.second1 = t->tm_sec / 10;
-               tod_2000.second2 = t->tm_sec % 10;
-               tod_2000.minute1 = t->tm_min / 10;
-               tod_2000.minute2 = t->tm_min % 10;
-               if (tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)
-                       tod_2000.hour1 = t->tm_hour / 10;
-               else if (t->tm_hour >= 12)
-                       tod_2000.hour1 = TOD2000_HOUR1_PM +
-                               (t->tm_hour - 12) / 10;
-               else
-                       tod_2000.hour1 = t->tm_hour / 10;
-               tod_2000.hour2   = t->tm_hour % 10;
-               tod_2000.day1    = t->tm_mday / 10;
-               tod_2000.day2    = t->tm_mday % 10;
-               if (t->tm_wday != -1)
-                       tod_2000.weekday = t->tm_wday;
-               tod_2000.month1  = (t->tm_mon + 1) / 10;
-               tod_2000.month2  = (t->tm_mon + 1) % 10;
-               if (t->tm_year >= 100)
-                       t->tm_year -= 100;
-               tod_2000.year1   = t->tm_year / 10;
-               tod_2000.year2   = t->tm_year % 10;
-       }
-
-       tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
-
-       return 0;
-}
-
-static int amiga_set_clock_mmss(unsigned long nowtime)
-{
-       short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
-
-       if (AMIGAHW_PRESENT(A3000_CLK)) {
-               tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
-
-               tod_3000.second1 = real_seconds / 10;
-               tod_3000.second2 = real_seconds % 10;
-               tod_3000.minute1 = real_minutes / 10;
-               tod_3000.minute2 = real_minutes % 10;
-
-               tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
-       } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-               int cnt = 5;
-
-               tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
-
-               while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt) {
-                       tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
-                       udelay(70);
-                       tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
-                       --cnt;
-               }
-
-               if (!cnt)
-                       printk(KERN_INFO "set_clock_mmss: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
-
-               tod_2000.second1 = real_seconds / 10;
-               tod_2000.second2 = real_seconds % 10;
-               tod_2000.minute1 = real_minutes / 10;
-               tod_2000.minute2 = real_minutes % 10;
-
-               tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
-       }
-
-       return 0;
-}
-
-static unsigned int amiga_get_ss(void)
-{
-       unsigned int s;
-
-       if (AMIGAHW_PRESENT(A3000_CLK)) {
-               tod_3000.cntrl1 = TOD3000_CNTRL1_HOLD;
-               s = tod_3000.second1 * 10 + tod_3000.second2;
-               tod_3000.cntrl1 = TOD3000_CNTRL1_FREE;
-       } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
-               s = tod_2000.second1 * 10 + tod_2000.second2;
-       }
-       return s;
-}
-
 static NORET_TYPE void amiga_reset(void)
     ATTRIB_NORET;
 
index 38f18bf14737cbff063eb3cb5d3767d13575dec7..7fd8b41723ea4b4b4e4f763c1aebf8cd3ce6a44a 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/zorro.h>
 
 #include <asm/amigahw.h>
+#include <asm/amigayle.h>
 
 
 #ifdef CONFIG_ZORRO
@@ -55,11 +56,77 @@ static int __init amiga_init_bus(void)
 
 subsys_initcall(amiga_init_bus);
 
-#endif /* CONFIG_ZORRO */
+
+static int z_dev_present(zorro_id id)
+{
+       unsigned int i;
+
+       for (i = 0; i < zorro_num_autocon; i++)
+               if (zorro_autocon[i].rom.er_Manufacturer == ZORRO_MANUF(id) &&
+                   zorro_autocon[i].rom.er_Product == ZORRO_PROD(id))
+                       return 1;
+
+       return 0;
+}
+
+#else /* !CONFIG_ZORRO */
+
+static inline int z_dev_present(zorro_id id) { return 0; }
+
+#endif /* !CONFIG_ZORRO */
+
+
+static const struct resource a3000_scsi_resource __initconst = {
+       .start  = 0xdd0000,
+       .end    = 0xdd00ff,
+       .flags  = IORESOURCE_MEM,
+};
+
+
+static const struct resource a4000t_scsi_resource __initconst = {
+       .start  = 0xdd0000,
+       .end    = 0xdd0fff,
+       .flags  = IORESOURCE_MEM,
+};
+
+
+static const struct resource a1200_ide_resource __initconst = {
+       .start  = 0xda0000,
+       .end    = 0xda1fff,
+       .flags  = IORESOURCE_MEM,
+};
+
+static const struct gayle_ide_platform_data a1200_ide_pdata __initconst = {
+       .base           = 0xda0000,
+       .irqport        = 0xda9000,
+       .explicit_ack   = 1,
+};
+
+
+static const struct resource a4000_ide_resource __initconst = {
+       .start  = 0xdd2000,
+       .end    = 0xdd3fff,
+       .flags  = IORESOURCE_MEM,
+};
+
+static const struct gayle_ide_platform_data a4000_ide_pdata __initconst = {
+       .base           = 0xdd2020,
+       .irqport        = 0xdd3020,
+       .explicit_ack   = 0,
+};
+
+
+static const struct resource amiga_rtc_resource __initconst = {
+       .start  = 0x00dc0000,
+       .end    = 0x00dcffff,
+       .flags  = IORESOURCE_MEM,
+};
 
 
 static int __init amiga_init_devices(void)
 {
+       struct platform_device *pdev;
+
        if (!MACH_IS_AMIGA)
                return -ENODEV;
 
@@ -77,6 +144,53 @@ static int __init amiga_init_devices(void)
        if (AMIGAHW_PRESENT(AMI_FLOPPY))
                platform_device_register_simple("amiga-floppy", -1, NULL, 0);
 
+       if (AMIGAHW_PRESENT(A3000_SCSI))
+               platform_device_register_simple("amiga-a3000-scsi", -1,
+                                               &a3000_scsi_resource, 1);
+
+       if (AMIGAHW_PRESENT(A4000_SCSI))
+               platform_device_register_simple("amiga-a4000t-scsi", -1,
+                                               &a4000t_scsi_resource, 1);
+
+       if (AMIGAHW_PRESENT(A1200_IDE) ||
+           z_dev_present(ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE)) {
+               pdev = platform_device_register_simple("amiga-gayle-ide", -1,
+                                                      &a1200_ide_resource, 1);
+               platform_device_add_data(pdev, &a1200_ide_pdata,
+                                        sizeof(a1200_ide_pdata));
+       }
+
+       if (AMIGAHW_PRESENT(A4000_IDE)) {
+               pdev = platform_device_register_simple("amiga-gayle-ide", -1,
+                                                      &a4000_ide_resource, 1);
+               platform_device_add_data(pdev, &a4000_ide_pdata,
+                                        sizeof(a4000_ide_pdata));
+       }
+
+
+       /* other I/O hardware */
+       if (AMIGAHW_PRESENT(AMI_KEYBOARD))
+               platform_device_register_simple("amiga-keyboard", -1, NULL, 0);
+
+       if (AMIGAHW_PRESENT(AMI_MOUSE))
+               platform_device_register_simple("amiga-mouse", -1, NULL, 0);
+
+       if (AMIGAHW_PRESENT(AMI_SERIAL))
+               platform_device_register_simple("amiga-serial", -1, NULL, 0);
+
+       if (AMIGAHW_PRESENT(AMI_PARALLEL))
+               platform_device_register_simple("amiga-parallel", -1, NULL, 0);
+
+
+       /* real time clocks */
+       if (AMIGAHW_PRESENT(A2000_CLK))
+               platform_device_register_simple("rtc-msm6242", -1,
+                                               &amiga_rtc_resource, 1);
+
+       if (AMIGAHW_PRESENT(A3000_CLK))
+               platform_device_register_simple("rtc-rp5c01", -1,
+                                               &amiga_rtc_resource, 1);
+
        return 0;
 }
 
index bb5a6aa329f3e840ae9ae4fe9acc3a6749789f42..a01453d9c231ba9b0da87050b7322aeab91ce83c 100644 (file)
@@ -104,4 +104,10 @@ struct GAYLE {
 #define GAYLE_CFG_250NS                0x00
 #define GAYLE_CFG_720NS                0x0c
 
+struct gayle_ide_platform_data {
+       unsigned long base;
+       unsigned long irqport;
+       int explicit_ack;       /* A1200 IDE needs explicit ack */
+};
+
 #endif /* asm-m68k/amigayle.h */
index 8d29145ebb27b66b6402c0c04367032c15d1e35c..eab36dcacf6c427241b64e969343f23649ccd11a 100644 (file)
@@ -3,3 +3,5 @@
 #else
 #include "atomic_mm.h"
 #endif
+
+#include <asm-generic/atomic64.h>
index fed3fd30de7e468797a85ff5945119c436f92fce..ecafbe1718c3cccee4a0441efaca9670b0548c59 100644 (file)
@@ -8,4 +8,6 @@
 #define        L1_CACHE_SHIFT  4
 #define        L1_CACHE_BYTES  (1<< L1_CACHE_SHIFT)
 
+#define ARCH_KMALLOC_MINALIGN  L1_CACHE_BYTES
+
 #endif
index e27ad902b1cff9bb26792f3fe99ee96a45fa8bc5..175da06c6b9549c27bb87ccd11a06f9d0a4a4b13 100644 (file)
@@ -1,23 +1,9 @@
 #ifndef _M68K_SCATTERLIST_H
 #define _M68K_SCATTERLIST_H
 
-#include <linux/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-       unsigned int length;
-
-       dma_addr_t dma_address; /* A place to hang host-specific addresses at. */
-};
+#include <asm-generic/scatterlist.h>
 
 /* This is bogus and should go away. */
 #define ISA_DMA_THRESHOLD (0x00ffffff)
 
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
-
 #endif /* !(_M68K_SCATTERLIST_H) */
index 35d786fe93ae0dcba7e1cf434606e9e61d1b05c2..dc4a8900cc8087dd6b315e484ada573bb1f7ef1d 100644 (file)
@@ -1 +1,3 @@
 #include <asm-generic/scatterlist.h>
+
+#define ISA_DMA_THRESHOLD      (~0UL)
index 83d69fe17c9f1404e481e2d2cbb22985f0be2cf5..9af65e79be36d3d8398d96a063836af90c506842 100644 (file)
@@ -1,27 +1,7 @@
 #ifndef __ASM_SCATTERLIST_H
 #define __ASM_SCATTERLIST_H
 
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;
-       dma_addr_t      dma_address;
-       unsigned int    length;
-};
-
-/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0x00ffffffUL)
 
index 67535901b9ffaf34e2ac366017313bf6dbd44da8..7bd00b9e030d427083567d9a223856cfee7d2e18 100644 (file)
 #ifndef _ASM_SCATTERLIST_H
 #define _ASM_SCATTERLIST_H
 
-#include <asm/types.h>
-
-/*
- * Drivers must set either ->address or (preferred) page and ->offset
- * to indicate where data must be transferred to/from.
- *
- * Using page is recommended since it handles highmem data as well as
- * low mem. ->address is restricted to data which has a virtual mapping, and
- * it will go away in the future. Updating to page can be automated very
- * easily -- something like
- *
- * sg->address = some_ptr;
- *
- * can be rewritten as
- *
- * sg_set_page(virt_to_page(some_ptr));
- * sg->offset = (unsigned long) some_ptr & ~PAGE_MASK;
- *
- * and that's it. There's no excuse for not highmem enabling YOUR driver. /jens
- */
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;         /* for highmem, page offset */
-       dma_addr_t      dma_address;
-       unsigned int    length;
-};
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (0x00ffffff)
 
-/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns.
- */
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
-
 #endif /* _ASM_SCATTERLIST_H */
index 9c4da3d63bfb9056ca6adf42da80575adb1f6b40..05a366a5c4d5c28431d3910aa69d993e7372e737 100644 (file)
@@ -98,6 +98,9 @@ config STACKTRACE_SUPPORT
 config NEED_DMA_MAP_STATE
        def_bool y
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config ISA_DMA_API
        bool
 
index 62269b31ebf4a89d404ec157cd653cba848de2f7..2c3b79b54b28ba4899233970ef377002039912b9 100644 (file)
@@ -3,25 +3,9 @@
 
 #include <asm/page.h>
 #include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-
-       unsigned int length;
-
-       /* an IOVA can be 64-bits on some PA-Risc platforms. */
-       dma_addr_t iova;        /* I/O Virtual Address */
-       __u32      iova_length; /* bytes mapped */
-};
-
-#define sg_virt_addr(sg) ((unsigned long)sg_virt(sg))
-#define sg_dma_address(sg) ((sg)->iova)
-#define sg_dma_len(sg)     ((sg)->iova_length)
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (~0UL)
+#define sg_virt_addr(sg) ((unsigned long)sg_virt(sg))
 
 #endif /* _ASM_PARISC_SCATTERLIST_H */
index c4c4549c22bbe8a3ce06149429096d0c87207c73..66a315e06dce88691322901a7ab7c6d38c702f4b 100644 (file)
@@ -663,6 +663,9 @@ config ZONE_DMA
 config NEED_DMA_MAP_STATE
        def_bool (PPC64 || NOT_COHERENT_CACHE)
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config GENERIC_ISA_DMA
        bool
        depends on PPC64 || POWER4 || 6xx && !CPM2
index 912bf597870f700188e907c7f424557108a86624..34cc78fd0ef4281d423faf3022f36f59bf7884a2 100644 (file)
@@ -9,38 +9,12 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#ifdef __KERNEL__
-#include <linux/types.h>
 #include <asm/dma.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long sg_magic;
-#endif
-       unsigned long page_link;
-       unsigned int offset;
-       unsigned int length;
-
-       /* For TCE or SWIOTLB support */
-       dma_addr_t dma_address;
-       u32 dma_length;
-};
-
-/*
- * These macros should be used after a dma_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->dma_length)
+#include <asm-generic/scatterlist.h>
 
 #ifdef __powerpc64__
 #define ISA_DMA_THRESHOLD      (~0UL)
 #endif
-
 #define ARCH_HAS_SG_CHAIN
 
-#endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_SCATTERLIST_H */
index 8b8fab91ad1e39a8abb162f448166c3eeb29be43..3a7a67a0d006cfe24d0b2bd626e7361d771dde1b 100644 (file)
 #define abort()                                                                \
        return 0
 
+#ifdef __BIG_ENDIAN
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+
 /* Exception flags. */
 #define EFLAG_INVALID          (1 << (31 - 2))
 #define EFLAG_OVERFLOW         (1 << (31 - 3))
index 4ff4da2c238bcd8585775cb4f2cb1432b89330c4..e7fe218b86978e52b2ff50f9d34c6efbd4b64790 100644 (file)
@@ -39,8 +39,8 @@ struct dma_map_ops swiotlb_dma_ops = {
        .dma_supported = swiotlb_dma_supported,
        .map_page = swiotlb_map_page,
        .unmap_page = swiotlb_unmap_page,
-       .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
-       .sync_single_range_for_device = swiotlb_sync_single_range_for_device,
+       .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+       .sync_single_for_device = swiotlb_sync_single_for_device,
        .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
        .sync_sg_for_device = swiotlb_sync_sg_for_device,
        .mapping_error = swiotlb_dma_mapping_error,
index 6c1df5757cd6e1a260a96557f5d9f7ea1f807f94..8d1de6f31d5a6befad3d93715d4ddf338b027b55 100644 (file)
@@ -127,11 +127,11 @@ static inline void dma_direct_sync_sg(struct device *dev,
                __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
 }
 
-static inline void dma_direct_sync_single_range(struct device *dev,
-               dma_addr_t dma_handle, unsigned long offset, size_t size,
-               enum dma_data_direction direction)
+static inline void dma_direct_sync_single(struct device *dev,
+                                         dma_addr_t dma_handle, size_t size,
+                                         enum dma_data_direction direction)
 {
-       __dma_sync(bus_to_virt(dma_handle+offset), size, direction);
+       __dma_sync(bus_to_virt(dma_handle), size, direction);
 }
 #endif
 
@@ -144,8 +144,8 @@ struct dma_map_ops dma_direct_ops = {
        .map_page       = dma_direct_map_page,
        .unmap_page     = dma_direct_unmap_page,
 #ifdef CONFIG_NOT_COHERENT_CACHE
-       .sync_single_range_for_cpu      = dma_direct_sync_single_range,
-       .sync_single_range_for_device   = dma_direct_sync_single_range,
+       .sync_single_for_cpu            = dma_direct_sync_single,
+       .sync_single_for_device         = dma_direct_sync_single,
        .sync_sg_for_cpu                = dma_direct_sync_sg,
        .sync_sg_for_device             = dma_direct_sync_sg,
 #endif
index 6a1fde0d22b04b016ee723ec8baa0c35e0bf0b96..cd37e49e70349d05cc82c48e83b0bd6a42faa9ce 100644 (file)
@@ -1,6 +1,15 @@
 /*
  * Freescale MPC85xx/MPC86xx RapidIO support
  *
+ * Copyright 2009 Sysgo AG
+ * Thomas Moll <thomas.moll@sysgo.com>
+ * - fixed maintenance access routines, check for aligned access
+ *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine@idt.com>
+ * - Added Port-Write message handling
+ * - Added Machine Check exception handling
+ *
  * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc.
  * Zhang Wei <wei.zhang@freescale.com>
  *
 #include <linux/of_platform.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/kfifo.h>
 
 #include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/uaccess.h>
+
+#undef DEBUG_PW        /* Port-Write debugging */
 
 /* RapidIO definition irq, which read from OF-tree */
 #define IRQ_RIO_BELL(m)                (((struct rio_priv *)(m->priv))->bellirq)
 #define IRQ_RIO_TX(m)          (((struct rio_priv *)(m->priv))->txirq)
 #define IRQ_RIO_RX(m)          (((struct rio_priv *)(m->priv))->rxirq)
+#define IRQ_RIO_PW(m)          (((struct rio_priv *)(m->priv))->pwirq)
 
 #define RIO_ATMU_REGS_OFFSET   0x10c00
 #define RIO_P_MSG_REGS_OFFSET  0x11000
 #define RIO_S_MSG_REGS_OFFSET  0x13000
 #define RIO_ESCSR              0x158
 #define RIO_CCSR               0x15c
+#define RIO_LTLEDCSR           0x0608
+#define  RIO_LTLEDCSR_IER      0x80000000
+#define  RIO_LTLEDCSR_PRT      0x01000000
+#define RIO_LTLEECSR           0x060c
+#define RIO_EPWISR             0x10010
 #define RIO_ISR_AACR           0x10120
 #define RIO_ISR_AACR_AA                0x1     /* Accept All ID */
 #define RIO_MAINT_WIN_SIZE     0x400000
 #define RIO_MSG_ISR_QFI                0x00000010
 #define RIO_MSG_ISR_DIQI       0x00000001
 
+#define RIO_IPWMR_SEN          0x00100000
+#define RIO_IPWMR_QFIE         0x00000100
+#define RIO_IPWMR_EIE          0x00000020
+#define RIO_IPWMR_CQ           0x00000002
+#define RIO_IPWMR_PWE          0x00000001
+
+#define RIO_IPWSR_QF           0x00100000
+#define RIO_IPWSR_TE           0x00000080
+#define RIO_IPWSR_QFI          0x00000010
+#define RIO_IPWSR_PWD          0x00000008
+#define RIO_IPWSR_PWB          0x00000004
+
 #define RIO_MSG_DESC_SIZE      32
 #define RIO_MSG_BUFFER_SIZE    4096
 #define RIO_MIN_TX_RING_SIZE   2
@@ -121,7 +153,7 @@ struct rio_msg_regs {
        u32 pad10[26];
        u32 pwmr;
        u32 pwsr;
-       u32 pad11;
+       u32 epwqbar;
        u32 pwqbar;
 };
 
@@ -160,6 +192,14 @@ struct rio_msg_rx_ring {
        void *dev_id;
 };
 
+struct rio_port_write_msg {
+       void *virt;
+       dma_addr_t phys;
+       u32 msg_count;
+       u32 err_count;
+       u32 discard_count;
+};
+
 struct rio_priv {
        struct device *dev;
        void __iomem *regs_win;
@@ -172,11 +212,64 @@ struct rio_priv {
        struct rio_dbell_ring dbell_ring;
        struct rio_msg_tx_ring msg_tx_ring;
        struct rio_msg_rx_ring msg_rx_ring;
+       struct rio_port_write_msg port_write_msg;
        int bellirq;
        int txirq;
        int rxirq;
+       int pwirq;
+       struct work_struct pw_work;
+       struct kfifo pw_fifo;
+       spinlock_t pw_fifo_lock;
 };
 
+#define __fsl_read_rio_config(x, addr, err, op)                \
+       __asm__ __volatile__(                           \
+               "1:     "op" %1,0(%2)\n"                \
+               "       eieio\n"                        \
+               "2:\n"                                  \
+               ".section .fixup,\"ax\"\n"              \
+               "3:     li %1,-1\n"                     \
+               "       li %0,%3\n"                     \
+               "       b 2b\n"                         \
+               ".section __ex_table,\"a\"\n"           \
+               "       .align 2\n"                     \
+               "       .long 1b,3b\n"                  \
+               ".text"                                 \
+               : "=r" (err), "=r" (x)                  \
+               : "b" (addr), "i" (-EFAULT), "0" (err))
+
+static void __iomem *rio_regs_win;
+
+static int (*saved_mcheck_exception)(struct pt_regs *regs);
+
+static int fsl_rio_mcheck_exception(struct pt_regs *regs)
+{
+       const struct exception_table_entry *entry = NULL;
+       unsigned long reason = (mfspr(SPRN_MCSR) & MCSR_MASK);
+
+       if (reason & MCSR_BUS_RBERR) {
+               reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR));
+               if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) {
+                       /* Check if we are prepared to handle this fault */
+                       entry = search_exception_tables(regs->nip);
+                       if (entry) {
+                               pr_debug("RIO: %s - MC Exception handled\n",
+                                        __func__);
+                               out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR),
+                                        0);
+                               regs->msr |= MSR_RI;
+                               regs->nip = entry->fixup;
+                               return 1;
+                       }
+               }
+       }
+
+       if (saved_mcheck_exception)
+               return saved_mcheck_exception(regs);
+       else
+               return cur_cpu_spec->machine_check(regs);
+}
+
 /**
  * fsl_rio_doorbell_send - Send a MPC85xx doorbell message
  * @mport: RapidIO master port info
@@ -277,27 +370,44 @@ fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid,
 {
        struct rio_priv *priv = mport->priv;
        u8 *data;
+       u32 rval, err = 0;
 
        pr_debug
            ("fsl_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n",
             index, destid, hopcount, offset, len);
+
+       /* 16MB maintenance window possible */
+       /* allow only aligned access to maintenance registers */
+       if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len))
+               return -EINVAL;
+
        out_be32(&priv->maint_atmu_regs->rowtar,
-                (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+                (destid << 22) | (hopcount << 12) | (offset >> 12));
+       out_be32(&priv->maint_atmu_regs->rowtear,  (destid >> 10));
 
-       data = (u8 *) priv->maint_win + offset;
+       data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1));
        switch (len) {
        case 1:
-               *val = in_8((u8 *) data);
+               __fsl_read_rio_config(rval, data, err, "lbz");
                break;
        case 2:
-               *val = in_be16((u16 *) data);
+               __fsl_read_rio_config(rval, data, err, "lhz");
                break;
-       default:
-               *val = in_be32((u32 *) data);
+       case 4:
+               __fsl_read_rio_config(rval, data, err, "lwz");
                break;
+       default:
+               return -EINVAL;
        }
 
-       return 0;
+       if (err) {
+               pr_debug("RIO: cfg_read error %d for %x:%x:%x\n",
+                        err, destid, hopcount, offset);
+       }
+
+       *val = rval;
+
+       return err;
 }
 
 /**
@@ -322,10 +432,17 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
        pr_debug
            ("fsl_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",
             index, destid, hopcount, offset, len, val);
+
+       /* 16MB maintenance windows possible */
+       /* allow only aligned access to maintenance registers */
+       if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len))
+               return -EINVAL;
+
        out_be32(&priv->maint_atmu_regs->rowtar,
-                (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+                (destid << 22) | (hopcount << 12) | (offset >> 12));
+       out_be32(&priv->maint_atmu_regs->rowtear,  (destid >> 10));
 
-       data = (u8 *) priv->maint_win + offset;
+       data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1));
        switch (len) {
        case 1:
                out_8((u8 *) data, val);
@@ -333,9 +450,11 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
        case 2:
                out_be16((u16 *) data, val);
                break;
-       default:
+       case 4:
                out_be32((u32 *) data, val);
                break;
+       default:
+               return -EINVAL;
        }
 
        return 0;
@@ -930,6 +1049,223 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport)
        return rc;
 }
 
+/**
+ * fsl_rio_port_write_handler - MPC85xx port write interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ *
+ * Handles port write interrupts. Parses a list of registered
+ * port write event handlers and executes a matching event handler.
+ */
+static irqreturn_t
+fsl_rio_port_write_handler(int irq, void *dev_instance)
+{
+       u32 ipwmr, ipwsr;
+       struct rio_mport *port = (struct rio_mport *)dev_instance;
+       struct rio_priv *priv = port->priv;
+       u32 epwisr, tmp;
+
+       ipwmr = in_be32(&priv->msg_regs->pwmr);
+       ipwsr = in_be32(&priv->msg_regs->pwsr);
+
+       epwisr = in_be32(priv->regs_win + RIO_EPWISR);
+       if (epwisr & 0x80000000) {
+               tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+               pr_info("RIO_LTLEDCSR = 0x%x\n", tmp);
+               out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
+       }
+
+       if (!(epwisr & 0x00000001))
+               return IRQ_HANDLED;
+
+#ifdef DEBUG_PW
+       pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr);
+       if (ipwsr & RIO_IPWSR_QF)
+               pr_debug(" QF");
+       if (ipwsr & RIO_IPWSR_TE)
+               pr_debug(" TE");
+       if (ipwsr & RIO_IPWSR_QFI)
+               pr_debug(" QFI");
+       if (ipwsr & RIO_IPWSR_PWD)
+               pr_debug(" PWD");
+       if (ipwsr & RIO_IPWSR_PWB)
+               pr_debug(" PWB");
+       pr_debug(" )\n");
+#endif
+       out_be32(&priv->msg_regs->pwsr,
+                ipwsr & (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
+
+       if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) {
+               priv->port_write_msg.err_count++;
+               pr_info("RIO: Port-Write Transaction Err (%d)\n",
+                        priv->port_write_msg.err_count);
+       }
+       if (ipwsr & RIO_IPWSR_PWD) {
+               priv->port_write_msg.discard_count++;
+               pr_info("RIO: Port Discarded Port-Write Msg(s) (%d)\n",
+                        priv->port_write_msg.discard_count);
+       }
+
+       /* Schedule deferred processing if PW was received */
+       if (ipwsr & RIO_IPWSR_QFI) {
+               /* Save PW message (if there is room in FIFO),
+                * otherwise discard it.
+                */
+               if (kfifo_avail(&priv->pw_fifo) >= RIO_PW_MSG_SIZE) {
+                       priv->port_write_msg.msg_count++;
+                       kfifo_in(&priv->pw_fifo, priv->port_write_msg.virt,
+                                RIO_PW_MSG_SIZE);
+               } else {
+                       priv->port_write_msg.discard_count++;
+                       pr_info("RIO: ISR Discarded Port-Write Msg(s) (%d)\n",
+                                priv->port_write_msg.discard_count);
+               }
+               schedule_work(&priv->pw_work);
+       }
+
+       /* Issue Clear Queue command. This allows another
+        * port-write to be received.
+        */
+       out_be32(&priv->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ);
+
+       return IRQ_HANDLED;
+}
+
+static void fsl_pw_dpc(struct work_struct *work)
+{
+       struct rio_priv *priv = container_of(work, struct rio_priv, pw_work);
+       unsigned long flags;
+       u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)];
+
+       /*
+        * Process port-write messages
+        */
+       spin_lock_irqsave(&priv->pw_fifo_lock, flags);
+       while (kfifo_out(&priv->pw_fifo, (unsigned char *)msg_buffer,
+                        RIO_PW_MSG_SIZE)) {
+               /* Process one message */
+               spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
+#ifdef DEBUG_PW
+               {
+               u32 i;
+               pr_debug("%s : Port-Write Message:", __func__);
+               for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
+                       if ((i%4) == 0)
+                               pr_debug("\n0x%02x: 0x%08x", i*4,
+                                        msg_buffer[i]);
+                       else
+                               pr_debug(" 0x%08x", msg_buffer[i]);
+               }
+               pr_debug("\n");
+               }
+#endif
+               /* Pass the port-write message to RIO core for processing */
+               rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
+               spin_lock_irqsave(&priv->pw_fifo_lock, flags);
+       }
+       spin_unlock_irqrestore(&priv->pw_fifo_lock, flags);
+}
+
+/**
+ * fsl_rio_pw_enable - enable/disable port-write interface init
+ * @mport: Master port implementing the port write unit
+ * @enable:    1=enable; 0=disable port-write message handling
+ */
+static int fsl_rio_pw_enable(struct rio_mport *mport, int enable)
+{
+       struct rio_priv *priv = mport->priv;
+       u32 rval;
+
+       rval = in_be32(&priv->msg_regs->pwmr);
+
+       if (enable)
+               rval |= RIO_IPWMR_PWE;
+       else
+               rval &= ~RIO_IPWMR_PWE;
+
+       out_be32(&priv->msg_regs->pwmr, rval);
+
+       return 0;
+}
+
+/**
+ * fsl_rio_port_write_init - MPC85xx port write interface init
+ * @mport: Master port implementing the port write unit
+ *
+ * Initializes port write unit hardware and DMA buffer
+ * ring. Called from fsl_rio_setup(). Returns %0 on success
+ * or %-ENOMEM on failure.
+ */
+static int fsl_rio_port_write_init(struct rio_mport *mport)
+{
+       struct rio_priv *priv = mport->priv;
+       int rc = 0;
+
+       /* Following configurations require a disabled port write controller */
+       out_be32(&priv->msg_regs->pwmr,
+                in_be32(&priv->msg_regs->pwmr) & ~RIO_IPWMR_PWE);
+
+       /* Initialize port write */
+       priv->port_write_msg.virt = dma_alloc_coherent(priv->dev,
+                                       RIO_PW_MSG_SIZE,
+                                       &priv->port_write_msg.phys, GFP_KERNEL);
+       if (!priv->port_write_msg.virt) {
+               pr_err("RIO: unable allocate port write queue\n");
+               return -ENOMEM;
+       }
+
+       priv->port_write_msg.err_count = 0;
+       priv->port_write_msg.discard_count = 0;
+
+       /* Point dequeue/enqueue pointers at first entry */
+       out_be32(&priv->msg_regs->epwqbar, 0);
+       out_be32(&priv->msg_regs->pwqbar, (u32) priv->port_write_msg.phys);
+
+       pr_debug("EIPWQBAR: 0x%08x IPWQBAR: 0x%08x\n",
+                in_be32(&priv->msg_regs->epwqbar),
+                in_be32(&priv->msg_regs->pwqbar));
+
+       /* Clear interrupt status IPWSR */
+       out_be32(&priv->msg_regs->pwsr,
+                (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD));
+
+       /* Configure port write contoller for snooping enable all reporting,
+          clear queue full */
+       out_be32(&priv->msg_regs->pwmr,
+                RIO_IPWMR_SEN | RIO_IPWMR_QFIE | RIO_IPWMR_EIE | RIO_IPWMR_CQ);
+
+
+       /* Hook up port-write handler */
+       rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, 0,
+                        "port-write", (void *)mport);
+       if (rc < 0) {
+               pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
+               goto err_out;
+       }
+
+       INIT_WORK(&priv->pw_work, fsl_pw_dpc);
+       spin_lock_init(&priv->pw_fifo_lock);
+       if (kfifo_alloc(&priv->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) {
+               pr_err("FIFO allocation failed\n");
+               rc = -ENOMEM;
+               goto err_out_irq;
+       }
+
+       pr_debug("IPWMR: 0x%08x IPWSR: 0x%08x\n",
+                in_be32(&priv->msg_regs->pwmr),
+                in_be32(&priv->msg_regs->pwsr));
+
+       return rc;
+
+err_out_irq:
+       free_irq(IRQ_RIO_PW(mport), (void *)mport);
+err_out:
+       dma_free_coherent(priv->dev, RIO_PW_MSG_SIZE,
+                         priv->port_write_msg.virt,
+                         priv->port_write_msg.phys);
+       return rc;
+}
+
 static char *cmdline = NULL;
 
 static int fsl_rio_get_hdid(int index)
@@ -1057,7 +1393,7 @@ int fsl_rio_setup(struct of_device *dev)
        dev_info(&dev->dev, "LAW start 0x%016llx, size 0x%016llx.\n",
                        law_start, law_size);
 
-       ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL);
+       ops = kzalloc(sizeof(struct rio_ops), GFP_KERNEL);
        if (!ops) {
                rc = -ENOMEM;
                goto err_ops;
@@ -1067,6 +1403,7 @@ int fsl_rio_setup(struct of_device *dev)
        ops->cread = fsl_rio_config_read;
        ops->cwrite = fsl_rio_config_write;
        ops->dsend = fsl_rio_doorbell_send;
+       ops->pwenable = fsl_rio_pw_enable;
 
        port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL);
        if (!port) {
@@ -1089,11 +1426,12 @@ int fsl_rio_setup(struct of_device *dev)
        port->iores.flags = IORESOURCE_MEM;
        port->iores.name = "rio_io_win";
 
+       priv->pwirq   = irq_of_parse_and_map(dev->node, 0);
        priv->bellirq = irq_of_parse_and_map(dev->dev.of_node, 2);
        priv->txirq = irq_of_parse_and_map(dev->dev.of_node, 3);
        priv->rxirq = irq_of_parse_and_map(dev->dev.of_node, 4);
-       dev_info(&dev->dev, "bellirq: %d, txirq: %d, rxirq %d\n", priv->bellirq,
-                               priv->txirq, priv->rxirq);
+       dev_info(&dev->dev, "pwirq: %d, bellirq: %d, txirq: %d, rxirq %d\n",
+                priv->pwirq, priv->bellirq, priv->txirq, priv->rxirq);
 
        rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
        rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
@@ -1109,6 +1447,7 @@ int fsl_rio_setup(struct of_device *dev)
        rio_register_mport(port);
 
        priv->regs_win = ioremap(regs.start, regs.end - regs.start + 1);
+       rio_regs_win = priv->regs_win;
 
        /* Probe the master port phy type */
        ccsr = in_be32(priv->regs_win + RIO_CCSR);
@@ -1166,7 +1505,8 @@ int fsl_rio_setup(struct of_device *dev)
 
        /* Configure maintenance transaction window */
        out_be32(&priv->maint_atmu_regs->rowbar, law_start >> 12);
-       out_be32(&priv->maint_atmu_regs->rowar, 0x80077015);    /* 4M */
+       out_be32(&priv->maint_atmu_regs->rowar,
+                0x80077000 | (ilog2(RIO_MAINT_WIN_SIZE) - 1));
 
        priv->maint_win = ioremap(law_start, RIO_MAINT_WIN_SIZE);
 
@@ -1175,6 +1515,12 @@ int fsl_rio_setup(struct of_device *dev)
                        (law_start + RIO_MAINT_WIN_SIZE) >> 12);
        out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b);    /* 4k */
        fsl_rio_doorbell_init(port);
+       fsl_rio_port_write_init(port);
+
+       saved_mcheck_exception = ppc_md.machine_check_exception;
+       ppc_md.machine_check_exception = fsl_rio_mcheck_exception;
+       /* Ensure that RFXE is set */
+       mtspr(SPRN_HID1, (mfspr(SPRN_HID1) | 0x20000));
 
        return 0;
 err:
index 35d786fe93ae0dcba7e1cf434606e9e61d1b05c2..be44d94cba549d386e1b6a3abaed0d88b8628336 100644 (file)
@@ -1 +1,3 @@
+#define ISA_DMA_THRESHOLD      (~0UL)
+
 #include <asm-generic/scatterlist.h>
index 7d43fee17e32ecef55cd41a0b5b7d4659d9e66fc..0addc6466d958aede3954efeb6b7071077344e6c 100644 (file)
@@ -73,3 +73,5 @@ extern unsigned long __udiv_qrnnd (unsigned int *, unsigned int,
 #define UDIV_NEEDS_NORMALIZATION 0
 
 #define abort() return 0
+
+#define __BYTE_ORDER __BIG_ENDIAN
index e4d98de83dd8393586118ec7ee760d4907385c05..541053ed234ea1c0cd8a893de5bf16c9c30d9022 100644 (file)
@@ -944,21 +944,21 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
        struct cpu *c = &per_cpu(cpu_devices, cpu);
        struct sys_device *s = &c->sysdev;
        struct s390_idle_data *idle;
+       int err = 0;
 
        switch (action) {
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
                idle = &per_cpu(s390_idle, cpu);
                memset(idle, 0, sizeof(struct s390_idle_data));
-               if (sysfs_create_group(&s->kobj, &cpu_online_attr_group))
-                       return NOTIFY_BAD;
+               err = sysfs_create_group(&s->kobj, &cpu_online_attr_group);
                break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
                sysfs_remove_group(&s->kobj, &cpu_online_attr_group);
                break;
        }
-       return NOTIFY_OK;
+       return notifier_from_errno(err);
 }
 
 static struct notifier_block __cpuinitdata smp_cpu_nb = {
index 9f533b8362c788170bfb451a02b40bbe9771829f..4fa1a665821557a0af3f25912bc679df36254917 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _ASM_SCORE_SCATTERLIST_H
 #define _ASM_SCORE_SCATTERLIST_H
 
+#define ISA_DMA_THRESHOLD      (~0UL)
+
 #include <asm-generic/scatterlist.h>
 
 #endif /* _ASM_SCORE_SCATTERLIST_H */
index 0e318c905eea984d57824526f50be505be82ddbd..c5ee4ce60b576d0e5155e940f9230a29cc622639 100644 (file)
@@ -186,6 +186,9 @@ config DMA_NONCOHERENT
 config NEED_DMA_MAP_STATE
        def_bool DMA_NONCOHERENT
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 source "init/Kconfig"
 
 source "kernel/Kconfig.freezer"
index d4104ce9fe53c8a01fc354c41e0d57c5359a1d68..6c4bbba2a67573e2d1a72d2362bc28b4af4e2428 100644 (file)
@@ -435,29 +435,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                             REGSET_DSP,
                                             0, sizeof(struct pt_dspregs),
                                             (const void __user *)data);
-#endif
-#ifdef CONFIG_BINFMT_ELF_FDPIC
-       case PTRACE_GETFDPIC: {
-               unsigned long tmp = 0;
-
-               switch (addr) {
-               case PTRACE_GETFDPIC_EXEC:
-                       tmp = child->mm->context.exec_fdpic_loadmap;
-                       break;
-               case PTRACE_GETFDPIC_INTERP:
-                       tmp = child->mm->context.interp_fdpic_loadmap;
-                       break;
-               default:
-                       break;
-               }
-
-               ret = 0;
-               if (put_user(tmp, datap)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               break;
-       }
 #endif
        default:
                ret = ptrace_request(child, request, addr, data);
index e8526021892fd1c69e171afa33890709e7fd6db2..8ae1bd310ad0d2d9f8b9e5694e6bd755e1f33eac 100644 (file)
@@ -66,3 +66,7 @@
   } while (0)
 
 #define abort()        return 0
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+
index d6781ce687e24cfeec3e8c9b61939f4b2a3831b8..6f1470baa314e8787213efedb78e0a3f9d6f9e56 100644 (file)
@@ -133,6 +133,9 @@ config ZONE_DMA
 config NEED_DMA_MAP_STATE
        def_bool y
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config GENERIC_ISA_DMA
        bool
        default y if SPARC32
index d1120257b0330cd25f6d6db0cac22ef700917c29..433e45f05fd4c1f593cf66df60b448668aed665e 100644 (file)
@@ -1,8 +1,9 @@
 #ifndef _SPARC_SCATTERLIST_H
 #define _SPARC_SCATTERLIST_H
 
-#define sg_dma_len(sg)         ((sg)->dma_length)
-
 #include <asm-generic/scatterlist.h>
 
+#define ISA_DMA_THRESHOLD      (~0UL)
+#define ARCH_HAS_SG_CHAIN
+
 #endif /* !(_SPARC_SCATTERLIST_H) */
index 0ea35afbb914f94cd01f3e01f6d2f3de699994d0..d1b2aff3c2599af38c347570be032abe5b4311da 100644 (file)
 
 #define abort()                                                                \
        return 0
+
+#ifdef __BIG_ENDIAN
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
index d17c9bc7218149d79e90f215f10117c8d2425440..425d3cf01af4a71b7fedb4d3ce2a809416aa8fba 100644 (file)
 
 #define abort() \
        return 0
+
+#ifdef __BIG_ENDIAN
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
index e0c619c55b4e27149866cee2c932d8e2a6212f9b..dcb0593b4a66348a204a44fee3366c5da0848ad1 100644 (file)
@@ -109,6 +109,9 @@ config SBUS
 config NEED_DMA_MAP_STATE
        def_bool (X86_64 || DMAR || DMA_API_DEBUG)
 
+config NEED_SG_DMA_LENGTH
+       def_bool y
+
 config GENERIC_ISA_DMA
        def_bool y
 
@@ -1703,6 +1706,10 @@ config HAVE_ARCH_EARLY_PFN_TO_NID
        def_bool X86_64
        depends on NUMA
 
+config USE_PERCPU_NUMA_NODE_ID
+       def_bool X86_64
+       depends on NUMA
+
 menu "Power management and ACPI options"
 
 config ARCH_HIBERNATION_HEADER
index 7b1aaa20c7b523b323606ab66f8d8567a7a322f3..89bbf4e4d05d834c7923a23de080b71dd5ebab24 100644 (file)
@@ -195,11 +195,11 @@ static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
 
 
 
-#if __BYTE_ORDER == __LITTLE_ENDIAN
+#if BYTE_ORDER == LITTLE_ENDIAN
 #define le16_to_cpu(val) (val)
 #define le32_to_cpu(val) (val)
 #endif
-#if __BYTE_ORDER == __BIG_ENDIAN
+#if BYTE_ORDER == BIG_ENDIAN
 #define le16_to_cpu(val) bswap_16(val)
 #define le32_to_cpu(val) bswap_32(val)
 #endif
index 75af592677ec0fd76af2101309eff68eedf1fb23..fb0b1874396f5fd172c1c61e0adae1da37be2e46 100644 (file)
@@ -1,8 +1,9 @@
 #ifndef _ASM_X86_SCATTERLIST_H
 #define _ASM_X86_SCATTERLIST_H
 
-#define ISA_DMA_THRESHOLD (0x00ffffff)
-
 #include <asm-generic/scatterlist.h>
 
+#define ISA_DMA_THRESHOLD (0x00ffffff)
+#define ARCH_HAS_SG_CHAIN
+
 #endif /* _ASM_X86_SCATTERLIST_H */
index c5087d7965871c5d9ec8e93d96c7fc4a8c5b3469..21899cc31e52110242dc6f041c08048701ecee32 100644 (file)
 extern int cpu_to_node_map[];
 
 /* Returns the number of the node containing CPU 'cpu' */
-static inline int cpu_to_node(int cpu)
+static inline int __cpu_to_node(int cpu)
 {
        return cpu_to_node_map[cpu];
 }
-#define early_cpu_to_node(cpu) cpu_to_node(cpu)
+#define early_cpu_to_node __cpu_to_node
+#define cpu_to_node __cpu_to_node
 
 #else /* CONFIG_X86_64 */
 
 /* Mappings between logical cpu number and node number */
 DECLARE_EARLY_PER_CPU(int, x86_cpu_to_node_map);
 
-/* Returns the number of the current Node. */
-DECLARE_PER_CPU(int, node_number);
-#define numa_node_id()         percpu_read(node_number)
-
 #ifdef CONFIG_DEBUG_PER_CPU_MAPS
-extern int cpu_to_node(int cpu);
+/*
+ * override generic percpu implementation of cpu_to_node
+ */
+extern int __cpu_to_node(int cpu);
+#define cpu_to_node __cpu_to_node
+
 extern int early_cpu_to_node(int cpu);
 
 #else  /* !CONFIG_DEBUG_PER_CPU_MAPS */
 
-/* Returns the number of the node containing CPU 'cpu' */
-static inline int cpu_to_node(int cpu)
-{
-       return per_cpu(x86_cpu_to_node_map, cpu);
-}
-
 /* Same function but used if called before per_cpu areas are setup */
 static inline int early_cpu_to_node(int cpu)
 {
@@ -170,6 +166,10 @@ static inline int numa_node_id(void)
 {
        return 0;
 }
+/*
+ * indicate override:
+ */
+#define numa_node_id numa_node_id
 
 static inline int early_cpu_to_node(int cpu)
 {
index cc83a002786e0bb16163afd17ffba909f88abe14..68e4a6f2211e2e8ea52015e5c4a8861f4f5269d9 100644 (file)
@@ -1121,9 +1121,9 @@ void __cpuinit cpu_init(void)
        oist = &per_cpu(orig_ist, cpu);
 
 #ifdef CONFIG_NUMA
-       if (cpu != 0 && percpu_read(node_number) == 0 &&
-           cpu_to_node(cpu) != NUMA_NO_NODE)
-               percpu_write(node_number, cpu_to_node(cpu));
+       if (cpu != 0 && percpu_read(numa_node) == 0 &&
+           early_cpu_to_node(cpu) != NUMA_NO_NODE)
+               set_numa_node(early_cpu_to_node(cpu));
 #endif
 
        me = current;
index 81c499eceb21d88f62499a86cb9b0034d8519858..e1a0a3bf9716722671325212dceb559db2a47bf3 100644 (file)
@@ -190,7 +190,7 @@ thermal_throttle_cpu_callback(struct notifier_block *nfb,
                mutex_unlock(&therm_cpu_lock);
                break;
        }
-       return err ? NOTIFY_BAD : NOTIFY_OK;
+       return notifier_from_errno(err);
 }
 
 static struct notifier_block thermal_throttle_cpu_notifier __cpuinitdata =
index 8b862d5900fe4a29b6bc100770e371db41ee0d91..1b7b31ab7d86536ecde1d68034cf882216ac32a6 100644 (file)
@@ -170,7 +170,7 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb,
                cpuid_device_destroy(cpu);
                break;
        }
-       return err ? NOTIFY_BAD : NOTIFY_OK;
+       return notifier_from_errno(err);
 }
 
 static struct notifier_block __refdata cpuid_class_cpu_notifier =
index 4d4468e9f47cbc7ba182ea92c78ec989c0a8b555..7bf2dc4c8f701de8965fc1e124126863c7384552 100644 (file)
@@ -230,7 +230,7 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb,
                msr_device_destroy(cpu);
                break;
        }
-       return err ? NOTIFY_BAD : NOTIFY_OK;
+       return notifier_from_errno(err);
 }
 
 static struct notifier_block __refdata msr_class_cpu_notifier = {
index 7d2829dde20e8cbbf538ea6fcf39384510a65426..a5bc528d43282a344936922328d2b5bf59b187ae 100644 (file)
@@ -31,8 +31,6 @@ static struct dma_map_ops swiotlb_dma_ops = {
        .free_coherent = swiotlb_free_coherent,
        .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
        .sync_single_for_device = swiotlb_sync_single_for_device,
-       .sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
-       .sync_single_range_for_device = swiotlb_sync_single_range_for_device,
        .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
        .sync_sg_for_device = swiotlb_sync_sg_for_device,
        .map_sg = swiotlb_map_sg_attrs,
index ef6370b00e70ce50ab73ed6b6ad5a1db48b749ab..a867940a6dfc4dfb31ac1f28a54ccb98d11aff46 100644 (file)
@@ -265,10 +265,10 @@ void __init setup_per_cpu_areas(void)
 
 #if defined(CONFIG_X86_64) && defined(CONFIG_NUMA)
        /*
-        * make sure boot cpu node_number is right, when boot cpu is on the
+        * make sure boot cpu numa_node is right, when boot cpu is on the
         * node that doesn't have mem installed
         */
-       per_cpu(node_number, boot_cpu_id) = cpu_to_node(boot_cpu_id);
+       set_cpu_numa_node(boot_cpu_id, early_cpu_to_node(boot_cpu_id));
 #endif
 
        /* Setup node to cpumask map */
index 550df481accd58d8ce23e7c96549f0507b1365b8..10c27bb1e95fd15aacba23ce8a68701b8778b2ad 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/topology.h>
 #include <linux/module.h>
 #include <linux/bootmem.h>
+#include <linux/random.h>
 
 #ifdef CONFIG_DEBUG_PER_CPU_MAPS
 # define DBG(x...) printk(KERN_DEBUG x)
@@ -65,3 +66,19 @@ const struct cpumask *cpumask_of_node(int node)
 }
 EXPORT_SYMBOL(cpumask_of_node);
 #endif
+
+/*
+ * Return the bit number of a random bit set in the nodemask.
+ *   (returns -1 if nodemask is empty)
+ */
+int __node_random(const nodemask_t *maskp)
+{
+       int w, bit = -1;
+
+       w = nodes_weight(*maskp);
+       if (w)
+               bit = bitmap_ord_to_pos(maskp->bits,
+                       get_random_int() % w, MAX_NUMNODES);
+       return bit;
+}
+EXPORT_SYMBOL(__node_random);
index 8948f47fde056f9e723640c7791732fe4e68ae63..a7bcc23ef96c989f5fef986cbd7816dfd551d20e 100644 (file)
@@ -33,9 +33,6 @@ int numa_off __initdata;
 static unsigned long __initdata nodemap_addr;
 static unsigned long __initdata nodemap_size;
 
-DEFINE_PER_CPU(int, node_number) = 0;
-EXPORT_PER_CPU_SYMBOL(node_number);
-
 /*
  * Map cpu index to node index
  */
@@ -809,7 +806,7 @@ void __cpuinit numa_set_node(int cpu, int node)
        per_cpu(x86_cpu_to_node_map, cpu) = node;
 
        if (node != NUMA_NO_NODE)
-               per_cpu(node_number, cpu) = node;
+               set_cpu_numa_node(cpu, node);
 }
 
 void __cpuinit numa_clear_node(int cpu)
@@ -867,7 +864,7 @@ void __cpuinit numa_remove_cpu(int cpu)
        numa_set_cpumask(cpu, 0);
 }
 
-int cpu_to_node(int cpu)
+int __cpu_to_node(int cpu)
 {
        if (early_per_cpu_ptr(x86_cpu_to_node_map)) {
                printk(KERN_WARNING
@@ -877,7 +874,7 @@ int cpu_to_node(int cpu)
        }
        return per_cpu(x86_cpu_to_node_map, cpu);
 }
-EXPORT_SYMBOL(cpu_to_node);
+EXPORT_SYMBOL(__cpu_to_node);
 
 /*
  * Same function as cpu_to_node() but used if called before the
index 810080bb0a2b2cfa498c39fed32c11d2897763bd..b1f9fdc1d5ba98b90076965a4c50915f99829d6f 100644 (file)
 #ifndef _XTENSA_SCATTERLIST_H
 #define _XTENSA_SCATTERLIST_H
 
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;
-       dma_addr_t      dma_address;
-       unsigned int    length;
-};
-
-/*
- * These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg)      ((sg)->dma_address)
-#define sg_dma_len(sg)          ((sg)->length)
-
+#include <asm-generic/scatterlist.h>
 
 #define ISA_DMA_THRESHOLD (~0UL)
 
index bf6b13206d00cbb4dda735829b6df2f740b80fa9..9fc630ce1ddb4b46f93dd2c35a459849399efa8b 100644 (file)
@@ -162,7 +162,7 @@ static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
                topology_remove_dev(cpu);
                break;
        }
-       return rc ? NOTIFY_BAD : NOTIFY_OK;
+       return notifier_from_errno(rc);
 }
 
 static int __cpuinit topology_sysfs_init(void)
index e21175be25d0b1c88f2b0fe3ec717f014e17b7f6..f09fc0e2062dfdf9b0d2c4d816cd4fada77c4628 100644 (file)
@@ -1121,5 +1121,12 @@ config DEVPORT
 
 source "drivers/s390/char/Kconfig"
 
+config RAMOOPS
+       tristate "Log panic/oops to a RAM buffer"
+       default n
+       help
+         This enables panic and oops messages to be logged to a circular
+         buffer in RAM where it can be read back at some later point.
+
 endmenu
 
index d39be4cf1f5d3eacedfeae1ca74f27b28304fa71..88d6eac697547a5f19018180993de5c2fdfc1b54 100644 (file)
@@ -108,6 +108,7 @@ obj-$(CONFIG_HANGCHECK_TIMER)       += hangcheck-timer.o
 obj-$(CONFIG_TCG_TPM)          += tpm/
 
 obj-$(CONFIG_PS3_FLASH)                += ps3flash.o
+obj-$(CONFIG_RAMOOPS)          += ramoops.o
 
 obj-$(CONFIG_JS_RTC)           += js-rtc.o
 js-rtc-y = rtc.o
index 67ea3a60de74580fe7ba3f99ac579725b23a2f45..70312da4c968f9e4af7c39e9a5a649b4952f8bd3 100644 (file)
@@ -384,7 +384,7 @@ static int __devinit uli_agp_init(struct pci_dev *pdev)
 {
        u32 httfea,baseaddr,enuscr;
        struct pci_dev *dev1;
-       int i;
+       int i, ret;
        unsigned size = amd64_fetch_size();
 
        dev_info(&pdev->dev, "setting up ULi AGP\n");
@@ -400,15 +400,18 @@ static int __devinit uli_agp_init(struct pci_dev *pdev)
 
        if (i == ARRAY_SIZE(uli_sizes)) {
                dev_info(&pdev->dev, "no ULi size found for %d\n", size);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto put;
        }
 
        /* shadow x86-64 registers into ULi registers */
        pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &httfea);
 
        /* if x86-64 aperture base is beyond 4G, exit here */
-       if ((httfea & 0x7fff) >> (32 - 25))
-               return -ENODEV;
+       if ((httfea & 0x7fff) >> (32 - 25)) {
+               ret = -ENODEV;
+               goto put;
+       }
 
        httfea = (httfea& 0x7fff) << 25;
 
@@ -420,9 +423,10 @@ static int __devinit uli_agp_init(struct pci_dev *pdev)
        enuscr= httfea+ (size * 1024 * 1024) - 1;
        pci_write_config_dword(dev1, ULI_X86_64_HTT_FEA_REG, httfea);
        pci_write_config_dword(dev1, ULI_X86_64_ENU_SCR_REG, enuscr);
-
+       ret = 0;
+put:
        pci_dev_put(dev1);
-       return 0;
+       return ret;
 }
 
 
@@ -441,7 +445,7 @@ static int nforce3_agp_init(struct pci_dev *pdev)
 {
        u32 tmp, apbase, apbar, aplimit;
        struct pci_dev *dev1;
-       int i;
+       int i, ret;
        unsigned size = amd64_fetch_size();
 
        dev_info(&pdev->dev, "setting up Nforce3 AGP\n");
@@ -458,7 +462,8 @@ static int nforce3_agp_init(struct pci_dev *pdev)
 
        if (i == ARRAY_SIZE(nforce3_sizes)) {
                dev_info(&pdev->dev, "no NForce3 size found for %d\n", size);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto put;
        }
 
        pci_read_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, &tmp);
@@ -472,7 +477,8 @@ static int nforce3_agp_init(struct pci_dev *pdev)
        /* if x86-64 aperture base is beyond 4G, exit here */
        if ( (apbase & 0x7fff) >> (32 - 25) ) {
                dev_info(&pdev->dev, "aperture base > 4G\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto put;
        }
 
        apbase = (apbase & 0x7fff) << 25;
@@ -488,9 +494,11 @@ static int nforce3_agp_init(struct pci_dev *pdev)
        pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE2, apbase);
        pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT2, aplimit);
 
+       ret = 0;
+put:
        pci_dev_put(dev1);
 
-       return 0;
+       return ret;
 }
 
 static int __devinit agp_amd64_probe(struct pci_dev *pdev,
index 56b27671adc46b23c80ca24425241048d0cae7ea..4f8d60c25a980f1dc73d648c235dcaf81fa165ec 100644 (file)
@@ -84,6 +84,7 @@ static char *serial_version = "4.30";
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
+#include <linux/platform_device.h>
 
 #include <asm/setup.h>
 
@@ -1954,29 +1955,16 @@ static const struct tty_operations serial_ops = {
 /*
  * The serial driver boot-time initialization code!
  */
-static int __init rs_init(void)
+static int __init amiga_serial_probe(struct platform_device *pdev)
 {
        unsigned long flags;
        struct serial_state * state;
        int error;
 
-       if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL))
-               return -ENODEV;
-
        serial_driver = alloc_tty_driver(1);
        if (!serial_driver)
                return -ENOMEM;
 
-       /*
-        *  We request SERDAT and SERPER only, because the serial registers are
-        *  too spreaded over the custom register space
-        */
-       if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4,
-                               "amiserial [Paula]")) {
-               error = -EBUSY;
-               goto fail_put_tty_driver;
-       }
-
        IRQ_ports = NULL;
 
        show_serial_version();
@@ -1998,7 +1986,7 @@ static int __init rs_init(void)
 
        error = tty_register_driver(serial_driver);
        if (error)
-               goto fail_release_mem_region;
+               goto fail_put_tty_driver;
 
        state = rs_table;
        state->magic = SSTATE_MAGIC;
@@ -2050,23 +2038,24 @@ static int __init rs_init(void)
        ciab.ddra |= (SER_DTR | SER_RTS);   /* outputs */
        ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR);  /* inputs */
 
+       platform_set_drvdata(pdev, state);
+
        return 0;
 
 fail_free_irq:
        free_irq(IRQ_AMIGA_TBE, state);
 fail_unregister:
        tty_unregister_driver(serial_driver);
-fail_release_mem_region:
-       release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
 fail_put_tty_driver:
        put_tty_driver(serial_driver);
        return error;
 }
 
-static __exit void rs_exit(void) 
+static int __exit amiga_serial_remove(struct platform_device *pdev)
 {
        int error;
-       struct async_struct *info = rs_table[0].info;
+       struct serial_state *state = platform_get_drvdata(pdev);
+       struct async_struct *info = state->info;
 
        /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
        tasklet_kill(&info->tlet);
@@ -2075,19 +2064,38 @@ static __exit void rs_exit(void)
                       error);
        put_tty_driver(serial_driver);
 
-       if (info) {
-         rs_table[0].info = NULL;
-         kfree(info);
-       }
+       rs_table[0].info = NULL;
+       kfree(info);
 
        free_irq(IRQ_AMIGA_TBE, rs_table);
        free_irq(IRQ_AMIGA_RBF, rs_table);
 
-       release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
+       platform_set_drvdata(pdev, NULL);
+
+       return error;
+}
+
+static struct platform_driver amiga_serial_driver = {
+       .remove = __exit_p(amiga_serial_remove),
+       .driver   = {
+               .name   = "amiga-serial",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init amiga_serial_init(void)
+{
+       return platform_driver_probe(&amiga_serial_driver, amiga_serial_probe);
+}
+
+module_init(amiga_serial_init);
+
+static void __exit amiga_serial_exit(void)
+{
+       platform_driver_unregister(&amiga_serial_driver);
 }
 
-module_init(rs_init)
-module_exit(rs_exit)
+module_exit(amiga_serial_exit);
 
 
 #if defined(CONFIG_SERIAL_CONSOLE) && !defined(MODULE)
@@ -2154,3 +2162,4 @@ console_initcall(amiserial_console_init);
 #endif /* CONFIG_SERIAL_CONSOLE && !MODULE */
 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:amiga-serial");
index 63313a33ba5f3a1060974c4bf1d3f41caeea207e..f4ae0e0fb631b522f1b02a0a4ea68e2f98df0897 100644 (file)
@@ -703,14 +703,9 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        /* In general, the device is only openable by root anyway, so we're not
           particularly concerned that bogus ioctls can flood the console. */
 
-       adgl = kmalloc(sizeof(struct st_ram_io), GFP_KERNEL);
-       if (!adgl)
-               return -ENOMEM;
-
-       if (copy_from_user(adgl, argp, sizeof(struct st_ram_io))) {
-               kfree(adgl);
-               return -EFAULT;
-       }
+       adgl = memdup_user(argp, sizeof(struct st_ram_io));
+       if (IS_ERR(adgl))
+               return PTR_ERR(adgl);
 
        lock_kernel();  
        IndexCard = adgl->num_card-1;
index c6ad4234378d7e5cd0818d839e81c3b641e1d426..4f3f8c9ec2629d52de7c538b5bad895628a61299 100644 (file)
@@ -2505,12 +2505,11 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum,
                        return rv;
                }
 
-               printk(KERN_INFO
-                      "ipmi: Found new BMC (man_id: 0x%6.6x, "
-                      " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
-                      bmc->id.manufacturer_id,
-                      bmc->id.product_id,
-                      bmc->id.device_id);
+               dev_info(intf->si_dev, "Found new BMC (man_id: 0x%6.6x, "
+                        "prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
+                        bmc->id.manufacturer_id,
+                        bmc->id.product_id,
+                        bmc->id.device_id);
        }
 
        /*
@@ -4037,8 +4036,8 @@ static void ipmi_request_event(void)
 
 static struct timer_list ipmi_timer;
 
-/* Call every ~100 ms. */
-#define IPMI_TIMEOUT_TIME      100
+/* Call every ~1000 ms. */
+#define IPMI_TIMEOUT_TIME      1000
 
 /* How many jiffies does it take to get to the timeout time. */
 #define IPMI_TIMEOUT_JIFFIES   ((IPMI_TIMEOUT_TIME * HZ) / 1000)
index 47ffe4a90a95d0372cb178c893ed3e92128d135b..35603dd4e6c5276911dec0b3a11464a152beb8a5 100644 (file)
@@ -107,6 +107,14 @@ enum si_type {
 };
 static char *si_to_str[] = { "kcs", "smic", "bt" };
 
+enum ipmi_addr_src {
+       SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS,
+       SI_PCI, SI_DEVICETREE, SI_DEFAULT
+};
+static char *ipmi_addr_src_to_str[] = { NULL, "hotmod", "hardcoded", "SPMI",
+                                       "ACPI", "SMBIOS", "PCI",
+                                       "device-tree", "default" };
+
 #define DEVICE_NAME "ipmi_si"
 
 static struct platform_driver ipmi_driver = {
@@ -188,7 +196,7 @@ struct smi_info {
        int (*irq_setup)(struct smi_info *info);
        void (*irq_cleanup)(struct smi_info *info);
        unsigned int io_size;
-       char *addr_source; /* ACPI, PCI, SMBIOS, hardcode, default. */
+       enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */
        void (*addr_source_cleanup)(struct smi_info *info);
        void *addr_source_data;
 
@@ -300,6 +308,7 @@ static int num_max_busy_us;
 
 static int unload_when_empty = 1;
 
+static int add_smi(struct smi_info *smi);
 static int try_smi_init(struct smi_info *smi);
 static void cleanup_one_si(struct smi_info *to_clean);
 
@@ -314,9 +323,14 @@ static void deliver_recv_msg(struct smi_info *smi_info,
 {
        /* Deliver the message to the upper layer with the lock
           released. */
-       spin_unlock(&(smi_info->si_lock));
-       ipmi_smi_msg_received(smi_info->intf, msg);
-       spin_lock(&(smi_info->si_lock));
+
+       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));
+       }
 }
 
 static void return_hosed_msg(struct smi_info *smi_info, int cCode)
@@ -445,6 +459,9 @@ static inline void disable_si_irq(struct smi_info *smi_info)
        if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
                start_disable_irq(smi_info);
                smi_info->interrupt_disabled = 1;
+               if (!atomic_read(&smi_info->stop_operation))
+                       mod_timer(&smi_info->si_timer,
+                                 jiffies + SI_TIMEOUT_JIFFIES);
        }
 }
 
@@ -576,9 +593,8 @@ static void handle_transaction_done(struct smi_info *smi_info)
                smi_info->handlers->get_result(smi_info->si_sm, msg, 3);
                if (msg[2] != 0) {
                        /* Error clearing flags */
-                       printk(KERN_WARNING
-                              "ipmi_si: Error clearing flags: %2.2x\n",
-                              msg[2]);
+                       dev_warn(smi_info->dev,
+                                "Error clearing flags: %2.2x\n", msg[2]);
                }
                if (smi_info->si_state == SI_CLEARING_FLAGS_THEN_SET_IRQ)
                        start_enable_irq(smi_info);
@@ -670,9 +686,8 @@ static void handle_transaction_done(struct smi_info *smi_info)
                /* We got the flags from the SMI, now handle them. */
                smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
                if (msg[2] != 0) {
-                       printk(KERN_WARNING
-                              "ipmi_si: Could not enable interrupts"
-                              ", failed get, using polled mode.\n");
+                       dev_warn(smi_info->dev, "Could not enable interrupts"
+                                ", failed get, using polled mode.\n");
                        smi_info->si_state = SI_NORMAL;
                } else {
                        msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
@@ -693,11 +708,11 @@ static void handle_transaction_done(struct smi_info *smi_info)
 
                /* We got the flags from the SMI, now handle them. */
                smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
-               if (msg[2] != 0) {
-                       printk(KERN_WARNING
-                              "ipmi_si: Could not enable interrupts"
-                              ", failed set, using polled mode.\n");
-               }
+               if (msg[2] != 0)
+                       dev_warn(smi_info->dev, "Could not enable interrupts"
+                                ", failed set, using polled mode.\n");
+               else
+                       smi_info->interrupt_disabled = 0;
                smi_info->si_state = SI_NORMAL;
                break;
        }
@@ -709,9 +724,8 @@ static void handle_transaction_done(struct smi_info *smi_info)
                /* We got the flags from the SMI, now handle them. */
                smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
                if (msg[2] != 0) {
-                       printk(KERN_WARNING
-                              "ipmi_si: Could not disable interrupts"
-                              ", failed get.\n");
+                       dev_warn(smi_info->dev, "Could not disable interrupts"
+                                ", failed get.\n");
                        smi_info->si_state = SI_NORMAL;
                } else {
                        msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
@@ -733,9 +747,8 @@ static void handle_transaction_done(struct smi_info *smi_info)
                /* We got the flags from the SMI, now handle them. */
                smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
                if (msg[2] != 0) {
-                       printk(KERN_WARNING
-                              "ipmi_si: Could not disable interrupts"
-                              ", failed set.\n");
+                       dev_warn(smi_info->dev, "Could not disable interrupts"
+                                ", failed set.\n");
                }
                smi_info->si_state = SI_NORMAL;
                break;
@@ -877,6 +890,11 @@ static void sender(void                *send_info,
        printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
 #endif
 
+       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
@@ -997,6 +1015,8 @@ static int ipmi_thread(void *data)
                        ; /* do nothing */
                else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait)
                        schedule();
+               else if (smi_result == SI_SM_IDLE)
+                       schedule_timeout_interruptible(100);
                else
                        schedule_timeout_interruptible(0);
        }
@@ -1039,6 +1059,7 @@ static void smi_timeout(unsigned long data)
        unsigned long     flags;
        unsigned long     jiffies_now;
        long              time_diff;
+       long              timeout;
 #ifdef DEBUG_TIMING
        struct timeval    t;
 #endif
@@ -1059,9 +1080,9 @@ static void smi_timeout(unsigned long data)
 
        if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
                /* Running with interrupts, only do long timeouts. */
-               smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+               timeout = jiffies + SI_TIMEOUT_JIFFIES;
                smi_inc_stat(smi_info, long_timeouts);
-               goto do_add_timer;
+               goto do_mod_timer;
        }
 
        /*
@@ -1070,14 +1091,15 @@ static void smi_timeout(unsigned long data)
         */
        if (smi_result == SI_SM_CALL_WITH_DELAY) {
                smi_inc_stat(smi_info, short_timeouts);
-               smi_info->si_timer.expires = jiffies + 1;
+               timeout = jiffies + 1;
        } else {
                smi_inc_stat(smi_info, long_timeouts);
-               smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
+               timeout = jiffies + SI_TIMEOUT_JIFFIES;
        }
 
- do_add_timer:
-       add_timer(&(smi_info->si_timer));
+ do_mod_timer:
+       if (smi_result != SI_SM_IDLE)
+               mod_timer(&(smi_info->si_timer), timeout);
 }
 
 static irqreturn_t si_irq_handler(int irq, void *data)
@@ -1144,10 +1166,10 @@ static int smi_start_processing(void       *send_info,
                new_smi->thread = kthread_run(ipmi_thread, new_smi,
                                              "kipmi%d", new_smi->intf_num);
                if (IS_ERR(new_smi->thread)) {
-                       printk(KERN_NOTICE "ipmi_si_intf: Could not start"
-                              " kernel thread due to error %ld, only using"
-                              " timers to drive the interface\n",
-                              PTR_ERR(new_smi->thread));
+                       dev_notice(new_smi->dev, "Could not start"
+                                  " kernel thread due to error %ld, only using"
+                                  " timers to drive the interface\n",
+                                  PTR_ERR(new_smi->thread));
                        new_smi->thread = NULL;
                }
        }
@@ -1308,14 +1330,13 @@ static int std_irq_setup(struct smi_info *info)
                                 DEVICE_NAME,
                                 info);
        if (rv) {
-               printk(KERN_WARNING
-                      "ipmi_si: %s unable to claim interrupt %d,"
-                      " running polled\n",
-                      DEVICE_NAME, info->irq);
+               dev_warn(info->dev, "%s unable to claim interrupt %d,"
+                        " running polled\n",
+                        DEVICE_NAME, info->irq);
                info->irq = 0;
        } else {
                info->irq_cleanup = std_irq_cleanup;
-               printk("  Using irq %d\n", info->irq);
+               dev_info(info->dev, "Using irq %d\n", info->irq);
        }
 
        return rv;
@@ -1406,8 +1427,8 @@ static int port_setup(struct smi_info *info)
                info->io.outputb = port_outl;
                break;
        default:
-               printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n",
-                      info->io.regsize);
+               dev_warn(info->dev, "Invalid register size: %d\n",
+                        info->io.regsize);
                return -EINVAL;
        }
 
@@ -1529,8 +1550,8 @@ static int mem_setup(struct smi_info *info)
                break;
 #endif
        default:
-               printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n",
-                      info->io.regsize);
+               dev_warn(info->dev, "Invalid register size: %d\n",
+                        info->io.regsize);
                return -EINVAL;
        }
 
@@ -1755,7 +1776,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
                                goto out;
                        }
 
-                       info->addr_source = "hotmod";
+                       info->addr_source = SI_HOTMOD;
                        info->si_type = si_type;
                        info->io.addr_data = addr;
                        info->io.addr_type = addr_space;
@@ -1777,7 +1798,9 @@ static int hotmod_handler(const char *val, struct kernel_param *kp)
                                info->irq_setup = std_irq_setup;
                        info->slave_addr = ipmb;
 
-                       try_smi_init(info);
+                       if (!add_smi(info))
+                               if (try_smi_init(info))
+                                       cleanup_one_si(info);
                } else {
                        /* remove */
                        struct smi_info *e, *tmp_e;
@@ -1813,7 +1836,8 @@ static __devinit void hardcode_find_bmc(void)
                if (!info)
                        return;
 
-               info->addr_source = "hardcoded";
+               info->addr_source = SI_HARDCODED;
+               printk(KERN_INFO PFX "probing via hardcoded address\n");
 
                if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
                        info->si_type = SI_KCS;
@@ -1822,8 +1846,7 @@ static __devinit void hardcode_find_bmc(void)
                } else if (strcmp(si_type[i], "bt") == 0) {
                        info->si_type = SI_BT;
                } else {
-                       printk(KERN_WARNING
-                              "ipmi_si: Interface type specified "
+                       printk(KERN_WARNING PFX "Interface type specified "
                               "for interface %d, was invalid: %s\n",
                               i, si_type[i]);
                        kfree(info);
@@ -1841,11 +1864,9 @@ static __devinit void hardcode_find_bmc(void)
                        info->io.addr_data = addrs[i];
                        info->io.addr_type = IPMI_MEM_ADDR_SPACE;
                } else {
-                       printk(KERN_WARNING
-                              "ipmi_si: Interface type specified "
-                              "for interface %d, "
-                              "but port and address were not set or "
-                              "set to zero.\n", i);
+                       printk(KERN_WARNING PFX "Interface type specified "
+                              "for interface %d, but port and address were "
+                              "not set or set to zero.\n", i);
                        kfree(info);
                        continue;
                }
@@ -1863,7 +1884,9 @@ static __devinit void hardcode_find_bmc(void)
                        info->irq_setup = std_irq_setup;
                info->slave_addr = slave_addrs[i];
 
-               try_smi_init(info);
+               if (!add_smi(info))
+                       if (try_smi_init(info))
+                               cleanup_one_si(info);
        }
 }
 
@@ -1923,15 +1946,13 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
                                          &ipmi_acpi_gpe,
                                          info);
        if (status != AE_OK) {
-               printk(KERN_WARNING
-                      "ipmi_si: %s unable to claim ACPI GPE %d,"
-                      " running polled\n",
-                      DEVICE_NAME, info->irq);
+               dev_warn(info->dev, "%s unable to claim ACPI GPE %d,"
+                        " running polled\n", DEVICE_NAME, info->irq);
                info->irq = 0;
                return -EINVAL;
        } else {
                info->irq_cleanup = acpi_gpe_irq_cleanup;
-               printk("  Using ACPI GPE %d\n", info->irq);
+               dev_info(info->dev, "Using ACPI GPE %d\n", info->irq);
                return 0;
        }
 }
@@ -1989,8 +2010,8 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
        u8               addr_space;
 
        if (spmi->IPMIlegacy != 1) {
-           printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy);
-           return -ENODEV;
+               printk(KERN_INFO PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy);
+               return -ENODEV;
        }
 
        if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
@@ -2000,11 +2021,12 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
-               printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");
+               printk(KERN_ERR PFX "Could not allocate SI data (3)\n");
                return -ENOMEM;
        }
 
-       info->addr_source = "SPMI";
+       info->addr_source = SI_SPMI;
+       printk(KERN_INFO PFX "probing via SPMI\n");
 
        /* Figure out the interface type. */
        switch (spmi->InterfaceType) {
@@ -2018,8 +2040,8 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
                info->si_type = SI_BT;
                break;
        default:
-               printk(KERN_INFO "ipmi_si: Unknown ACPI/SPMI SI type %d\n",
-                       spmi->InterfaceType);
+               printk(KERN_INFO PFX "Unknown ACPI/SPMI SI type %d\n",
+                      spmi->InterfaceType);
                kfree(info);
                return -EIO;
        }
@@ -2055,13 +2077,12 @@ static __devinit int try_init_spmi(struct SPMITable *spmi)
                info->io.addr_type = IPMI_IO_ADDR_SPACE;
        } else {
                kfree(info);
-               printk(KERN_WARNING
-                      "ipmi_si: Unknown ACPI I/O Address type\n");
+               printk(KERN_WARNING PFX "Unknown ACPI I/O Address type\n");
                return -EIO;
        }
        info->io.addr_data = spmi->addr.address;
 
-       try_smi_init(info);
+       add_smi(info);
 
        return 0;
 }
@@ -2093,6 +2114,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
 {
        struct acpi_device *acpi_dev;
        struct smi_info *info;
+       struct resource *res;
        acpi_handle handle;
        acpi_status status;
        unsigned long long tmp;
@@ -2105,7 +2127,8 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
        if (!info)
                return -ENOMEM;
 
-       info->addr_source = "ACPI";
+       info->addr_source = SI_ACPI;
+       printk(KERN_INFO PFX "probing via ACPI\n");
 
        handle = acpi_dev->handle;
 
@@ -2125,22 +2148,26 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
                info->si_type = SI_BT;
                break;
        default:
-               dev_info(&dev->dev, "unknown interface type %lld\n", tmp);
+               dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp);
                goto err_free;
        }
 
-       if (pnp_port_valid(dev, 0)) {
+       res = pnp_get_resource(dev, IORESOURCE_IO, 0);
+       if (res) {
                info->io_setup = port_setup;
                info->io.addr_type = IPMI_IO_ADDR_SPACE;
-               info->io.addr_data = pnp_port_start(dev, 0);
-       } else if (pnp_mem_valid(dev, 0)) {
-               info->io_setup = mem_setup;
-               info->io.addr_type = IPMI_MEM_ADDR_SPACE;
-               info->io.addr_data = pnp_mem_start(dev, 0);
        } else {
+               res = pnp_get_resource(dev, IORESOURCE_MEM, 0);
+               if (res) {
+                       info->io_setup = mem_setup;
+                       info->io.addr_type = IPMI_MEM_ADDR_SPACE;
+               }
+       }
+       if (!res) {
                dev_err(&dev->dev, "no I/O or memory address\n");
                goto err_free;
        }
+       info->io.addr_data = res->start;
 
        info->io.regspacing = DEFAULT_REGSPACING;
        info->io.regsize = DEFAULT_REGSPACING;
@@ -2156,10 +2183,14 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
                info->irq_setup = std_irq_setup;
        }
 
-       info->dev = &acpi_dev->dev;
+       info->dev = &dev->dev;
        pnp_set_drvdata(dev, info);
 
-       return try_smi_init(info);
+       dev_info(info->dev, "%pR regsize %d spacing %d irq %d\n",
+                res, info->io.regsize, info->io.regspacing,
+                info->irq);
+
+       return add_smi(info);
 
 err_free:
        kfree(info);
@@ -2264,12 +2295,12 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info) {
-               printk(KERN_ERR
-                      "ipmi_si: Could not allocate SI data\n");
+               printk(KERN_ERR PFX "Could not allocate SI data\n");
                return;
        }
 
-       info->addr_source = "SMBIOS";
+       info->addr_source = SI_SMBIOS;
+       printk(KERN_INFO PFX "probing via SMBIOS\n");
 
        switch (ipmi_data->type) {
        case 0x01: /* KCS */
@@ -2299,8 +2330,7 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
 
        default:
                kfree(info);
-               printk(KERN_WARNING
-                      "ipmi_si: Unknown SMBIOS I/O Address type: %d.\n",
+               printk(KERN_WARNING PFX "Unknown SMBIOS I/O Address type: %d\n",
                       ipmi_data->addr_space);
                return;
        }
@@ -2318,7 +2348,7 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
        if (info->irq)
                info->irq_setup = std_irq_setup;
 
-       try_smi_init(info);
+       add_smi(info);
 }
 
 static void __devinit dmi_find_bmc(void)
@@ -2368,7 +2398,8 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
        if (!info)
                return -ENOMEM;
 
-       info->addr_source = "PCI";
+       info->addr_source = SI_PCI;
+       dev_info(&pdev->dev, "probing via PCI");
 
        switch (class_type) {
        case PCI_ERMC_CLASSCODE_TYPE_SMIC:
@@ -2385,15 +2416,13 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
 
        default:
                kfree(info);
-               printk(KERN_INFO "ipmi_si: %s: Unknown IPMI type: %d\n",
-                      pci_name(pdev), class_type);
+               dev_info(&pdev->dev, "Unknown IPMI type: %d\n", class_type);
                return -ENOMEM;
        }
 
        rv = pci_enable_device(pdev);
        if (rv) {
-               printk(KERN_ERR "ipmi_si: %s: couldn't enable PCI device\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "couldn't enable PCI device\n");
                kfree(info);
                return rv;
        }
@@ -2421,7 +2450,11 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
        info->dev = &pdev->dev;
        pci_set_drvdata(pdev, info);
 
-       return try_smi_init(info);
+       dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n",
+               &pdev->resource[0], info->io.regsize, info->io.regspacing,
+               info->irq);
+
+       return add_smi(info);
 }
 
 static void __devexit ipmi_pci_remove(struct pci_dev *pdev)
@@ -2473,7 +2506,7 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
        int ret;
        int proplen;
 
-       dev_info(&dev->dev, PFX "probing via device tree\n");
+       dev_info(&dev->dev, "probing via device tree\n");
 
        ret = of_address_to_resource(np, 0, &resource);
        if (ret) {
@@ -2503,12 +2536,12 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
 
        if (!info) {
                dev_err(&dev->dev,
-                       PFX "could not allocate memory for OF probe\n");
+                       "could not allocate memory for OF probe\n");
                return -ENOMEM;
        }
 
        info->si_type           = (enum si_type) match->data;
-       info->addr_source       = "device-tree";
+       info->addr_source       = SI_DEVICETREE;
        info->irq_setup         = std_irq_setup;
 
        if (resource.flags & IORESOURCE_IO) {
@@ -2528,13 +2561,13 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
        info->irq               = irq_of_parse_and_map(dev->dev.of_node, 0);
        info->dev               = &dev->dev;
 
-       dev_dbg(&dev->dev, "addr 0x%lx regsize %d spacing %d irq %x\n",
+       dev_dbg(&dev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n",
                info->io.addr_data, info->io.regsize, info->io.regspacing,
                info->irq);
 
        dev_set_drvdata(&dev->dev, info);
 
-       return try_smi_init(info);
+       return add_smi(info);
 }
 
 static int __devexit ipmi_of_remove(struct of_device *dev)
@@ -2643,9 +2676,8 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
 
        rv = wait_for_msg_done(smi_info);
        if (rv) {
-               printk(KERN_WARNING
-                      "ipmi_si: Error getting response from get global,"
-                      " enables command, the event buffer is not"
+               printk(KERN_WARNING PFX "Error getting response from get"
+                      " global enables command, the event buffer is not"
                       " enabled.\n");
                goto out;
        }
@@ -2657,10 +2689,8 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
                        resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
                        resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD   ||
                        resp[2] != 0) {
-               printk(KERN_WARNING
-                      "ipmi_si: Invalid return from get global"
-                      " enables command, cannot enable the event"
-                      " buffer.\n");
+               printk(KERN_WARNING PFX "Invalid return from get global"
+                      " enables command, cannot enable the event buffer.\n");
                rv = -EINVAL;
                goto out;
        }
@@ -2676,9 +2706,8 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
 
        rv = wait_for_msg_done(smi_info);
        if (rv) {
-               printk(KERN_WARNING
-                      "ipmi_si: Error getting response from set global,"
-                      " enables command, the event buffer is not"
+               printk(KERN_WARNING PFX "Error getting response from set"
+                      " global, enables command, the event buffer is not"
                       " enabled.\n");
                goto out;
        }
@@ -2689,10 +2718,8 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
        if (resp_len < 3 ||
                        resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
                        resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) {
-               printk(KERN_WARNING
-                      "ipmi_si: Invalid return from get global,"
-                      "enables command, not enable the event"
-                      " buffer.\n");
+               printk(KERN_WARNING PFX "Invalid return from get global,"
+                      "enables command, not enable the event buffer.\n");
                rv = -EINVAL;
                goto out;
        }
@@ -2951,7 +2978,7 @@ static __devinit void default_find_bmc(void)
                if (!info)
                        return;
 
-               info->addr_source = NULL;
+               info->addr_source = SI_DEFAULT;
 
                info->si_type = ipmi_defaults[i].type;
                info->io_setup = port_setup;
@@ -2963,14 +2990,16 @@ static __devinit void default_find_bmc(void)
                info->io.regsize = DEFAULT_REGSPACING;
                info->io.regshift = 0;
 
-               if (try_smi_init(info) == 0) {
-                       /* Found one... */
-                       printk(KERN_INFO "ipmi_si: Found default %s state"
-                              " machine at %s address 0x%lx\n",
-                              si_to_str[info->si_type],
-                              addr_space_to_str[info->io.addr_type],
-                              info->io.addr_data);
-                       return;
+               if (add_smi(info) == 0) {
+                       if ((try_smi_init(info)) == 0) {
+                               /* Found one... */
+                               printk(KERN_INFO PFX "Found default %s"
+                               " state machine at %s address 0x%lx\n",
+                               si_to_str[info->si_type],
+                               addr_space_to_str[info->io.addr_type],
+                               info->io.addr_data);
+                       } else
+                               cleanup_one_si(info);
                }
        }
 }
@@ -2989,34 +3018,48 @@ static int is_new_interface(struct smi_info *info)
        return 1;
 }
 
-static int try_smi_init(struct smi_info *new_smi)
+static int add_smi(struct smi_info *new_smi)
 {
-       int rv;
-       int i;
-
-       if (new_smi->addr_source) {
-               printk(KERN_INFO "ipmi_si: Trying %s-specified %s state"
-                      " machine at %s address 0x%lx, slave address 0x%x,"
-                      " irq %d\n",
-                      new_smi->addr_source,
-                      si_to_str[new_smi->si_type],
-                      addr_space_to_str[new_smi->io.addr_type],
-                      new_smi->io.addr_data,
-                      new_smi->slave_addr, new_smi->irq);
-       }
+       int rv = 0;
 
+       printk(KERN_INFO PFX "Adding %s-specified %s state machine",
+                       ipmi_addr_src_to_str[new_smi->addr_source],
+                       si_to_str[new_smi->si_type]);
        mutex_lock(&smi_infos_lock);
        if (!is_new_interface(new_smi)) {
-               printk(KERN_WARNING "ipmi_si: duplicate interface\n");
+               printk(KERN_CONT PFX "duplicate interface\n");
                rv = -EBUSY;
                goto out_err;
        }
 
+       printk(KERN_CONT "\n");
+
        /* So we know not to free it unless we have allocated one. */
        new_smi->intf = NULL;
        new_smi->si_sm = NULL;
        new_smi->handlers = NULL;
 
+       list_add_tail(&new_smi->link, &smi_infos);
+
+out_err:
+       mutex_unlock(&smi_infos_lock);
+       return rv;
+}
+
+static int try_smi_init(struct smi_info *new_smi)
+{
+       int rv = 0;
+       int i;
+
+       printk(KERN_INFO PFX "Trying %s-specified %s state"
+              " machine at %s address 0x%lx, slave address 0x%x,"
+              " irq %d\n",
+              ipmi_addr_src_to_str[new_smi->addr_source],
+              si_to_str[new_smi->si_type],
+              addr_space_to_str[new_smi->io.addr_type],
+              new_smi->io.addr_data,
+              new_smi->slave_addr, new_smi->irq);
+
        switch (new_smi->si_type) {
        case SI_KCS:
                new_smi->handlers = &kcs_smi_handlers;
@@ -3039,7 +3082,8 @@ static int try_smi_init(struct smi_info *new_smi)
        /* Allocate the state machine's data and initialize it. */
        new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);
        if (!new_smi->si_sm) {
-               printk(KERN_ERR "Could not allocate state machine memory\n");
+               printk(KERN_ERR PFX
+                      "Could not allocate state machine memory\n");
                rv = -ENOMEM;
                goto out_err;
        }
@@ -3049,7 +3093,7 @@ static int try_smi_init(struct smi_info *new_smi)
        /* Now that we know the I/O size, we can set up the I/O. */
        rv = new_smi->io_setup(new_smi);
        if (rv) {
-               printk(KERN_ERR "Could not set up I/O space\n");
+               printk(KERN_ERR PFX "Could not set up I/O space\n");
                goto out_err;
        }
 
@@ -3059,8 +3103,7 @@ static int try_smi_init(struct smi_info *new_smi)
        /* Do low-level detection first. */
        if (new_smi->handlers->detect(new_smi->si_sm)) {
                if (new_smi->addr_source)
-                       printk(KERN_INFO "ipmi_si: Interface detection"
-                              " failed\n");
+                       printk(KERN_INFO PFX "Interface detection failed\n");
                rv = -ENODEV;
                goto out_err;
        }
@@ -3072,7 +3115,7 @@ static int try_smi_init(struct smi_info *new_smi)
        rv = try_get_dev_id(new_smi);
        if (rv) {
                if (new_smi->addr_source)
-                       printk(KERN_INFO "ipmi_si: There appears to be no BMC"
+                       printk(KERN_INFO PFX "There appears to be no BMC"
                               " at this location\n");
                goto out_err;
        }
@@ -3088,7 +3131,7 @@ static int try_smi_init(struct smi_info *new_smi)
        for (i = 0; i < SI_NUM_STATS; i++)
                atomic_set(&new_smi->stats[i], 0);
 
-       new_smi->interrupt_disabled = 0;
+       new_smi->interrupt_disabled = 1;
        atomic_set(&new_smi->stop_operation, 0);
        new_smi->intf_num = smi_num;
        smi_num++;
@@ -3114,9 +3157,8 @@ static int try_smi_init(struct smi_info *new_smi)
                new_smi->pdev = platform_device_alloc("ipmi_si",
                                                      new_smi->intf_num);
                if (!new_smi->pdev) {
-                       printk(KERN_ERR
-                              "ipmi_si_intf:"
-                              " Unable to allocate platform device\n");
+                       printk(KERN_ERR PFX
+                              "Unable to allocate platform device\n");
                        goto out_err;
                }
                new_smi->dev = &new_smi->pdev->dev;
@@ -3124,9 +3166,8 @@ static int try_smi_init(struct smi_info *new_smi)
 
                rv = platform_device_add(new_smi->pdev);
                if (rv) {
-                       printk(KERN_ERR
-                              "ipmi_si_intf:"
-                              " Unable to register system interface device:"
+                       printk(KERN_ERR PFX
+                              "Unable to register system interface device:"
                               " %d\n",
                               rv);
                        goto out_err;
@@ -3141,9 +3182,8 @@ static int try_smi_init(struct smi_info *new_smi)
                               "bmc",
                               new_smi->slave_addr);
        if (rv) {
-               printk(KERN_ERR
-                      "ipmi_si: Unable to register device: error %d\n",
-                      rv);
+               dev_err(new_smi->dev, "Unable to register device: error %d\n",
+                       rv);
                goto out_err_stop_timer;
        }
 
@@ -3151,9 +3191,7 @@ static int try_smi_init(struct smi_info *new_smi)
                                     type_file_read_proc,
                                     new_smi);
        if (rv) {
-               printk(KERN_ERR
-                      "ipmi_si: Unable to create proc entry: %d\n",
-                      rv);
+               dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
                goto out_err_stop_timer;
        }
 
@@ -3161,9 +3199,7 @@ static int try_smi_init(struct smi_info *new_smi)
                                     stat_file_read_proc,
                                     new_smi);
        if (rv) {
-               printk(KERN_ERR
-                      "ipmi_si: Unable to create proc entry: %d\n",
-                      rv);
+               dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
                goto out_err_stop_timer;
        }
 
@@ -3171,18 +3207,12 @@ static int try_smi_init(struct smi_info *new_smi)
                                     param_read_proc,
                                     new_smi);
        if (rv) {
-               printk(KERN_ERR
-                      "ipmi_si: Unable to create proc entry: %d\n",
-                      rv);
+               dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
                goto out_err_stop_timer;
        }
 
-       list_add_tail(&new_smi->link, &smi_infos);
-
-       mutex_unlock(&smi_infos_lock);
-
-       printk(KERN_INFO "IPMI %s interface initialized\n",
-              si_to_str[new_smi->si_type]);
+       dev_info(new_smi->dev, "IPMI %s interface initialized\n",
+                si_to_str[new_smi->si_type]);
 
        return 0;
 
@@ -3191,11 +3221,17 @@ static int try_smi_init(struct smi_info *new_smi)
        wait_for_timer_and_thread(new_smi);
 
  out_err:
-       if (new_smi->intf)
+       new_smi->interrupt_disabled = 1;
+
+       if (new_smi->intf) {
                ipmi_unregister_smi(new_smi->intf);
+               new_smi->intf = NULL;
+       }
 
-       if (new_smi->irq_cleanup)
+       if (new_smi->irq_cleanup) {
                new_smi->irq_cleanup(new_smi);
+               new_smi->irq_cleanup = NULL;
+       }
 
        /*
         * Wait until we know that we are out of any interrupt
@@ -3208,18 +3244,21 @@ static int try_smi_init(struct smi_info *new_smi)
                if (new_smi->handlers)
                        new_smi->handlers->cleanup(new_smi->si_sm);
                kfree(new_smi->si_sm);
+               new_smi->si_sm = NULL;
        }
-       if (new_smi->addr_source_cleanup)
+       if (new_smi->addr_source_cleanup) {
                new_smi->addr_source_cleanup(new_smi);
-       if (new_smi->io_cleanup)
+               new_smi->addr_source_cleanup = NULL;
+       }
+       if (new_smi->io_cleanup) {
                new_smi->io_cleanup(new_smi);
+               new_smi->io_cleanup = NULL;
+       }
 
-       if (new_smi->dev_registered)
+       if (new_smi->dev_registered) {
                platform_device_unregister(new_smi->pdev);
-
-       kfree(new_smi);
-
-       mutex_unlock(&smi_infos_lock);
+               new_smi->dev_registered = 0;
+       }
 
        return rv;
 }
@@ -3229,6 +3268,8 @@ static __devinit int init_ipmi_si(void)
        int  i;
        char *str;
        int  rv;
+       struct smi_info *e;
+       enum ipmi_addr_src type = SI_INVALID;
 
        if (initialized)
                return 0;
@@ -3237,9 +3278,7 @@ static __devinit int init_ipmi_si(void)
        /* Register the device drivers. */
        rv = driver_register(&ipmi_driver.driver);
        if (rv) {
-               printk(KERN_ERR
-                      "init_ipmi_si: Unable to register driver: %d\n",
-                      rv);
+               printk(KERN_ERR PFX "Unable to register driver: %d\n", rv);
                return rv;
        }
 
@@ -3263,38 +3302,81 @@ static __devinit int init_ipmi_si(void)
 
        hardcode_find_bmc();
 
-#ifdef CONFIG_DMI
-       dmi_find_bmc();
-#endif
+       /* If the user gave us a device, they presumably want us to use it */
+       mutex_lock(&smi_infos_lock);
+       if (!list_empty(&smi_infos)) {
+               mutex_unlock(&smi_infos_lock);
+               return 0;
+       }
+       mutex_unlock(&smi_infos_lock);
 
-#ifdef CONFIG_ACPI
-       spmi_find_bmc();
+#ifdef CONFIG_PCI
+       rv = pci_register_driver(&ipmi_pci_driver);
+       if (rv)
+               printk(KERN_ERR PFX "Unable to register PCI driver: %d\n", rv);
 #endif
+
 #ifdef CONFIG_ACPI
        pnp_register_driver(&ipmi_pnp_driver);
 #endif
 
-#ifdef CONFIG_PCI
-       rv = pci_register_driver(&ipmi_pci_driver);
-       if (rv)
-               printk(KERN_ERR
-                      "init_ipmi_si: Unable to register PCI driver: %d\n",
-                      rv);
+#ifdef CONFIG_DMI
+       dmi_find_bmc();
+#endif
+
+#ifdef CONFIG_ACPI
+       spmi_find_bmc();
 #endif
 
 #ifdef CONFIG_PPC_OF
        of_register_platform_driver(&ipmi_of_platform_driver);
 #endif
 
+       /* We prefer devices with interrupts, but in the case of a machine
+          with multiple BMCs we assume that there will be several instances
+          of a given type so if we succeed in registering a type then also
+          try to register everything else of the same type */
+
+       mutex_lock(&smi_infos_lock);
+       list_for_each_entry(e, &smi_infos, link) {
+               /* Try to register a device if it has an IRQ and we either
+                  haven't successfully registered a device yet or this
+                  device has the same type as one we successfully registered */
+               if (e->irq && (!type || e->addr_source == type)) {
+                       if (!try_smi_init(e)) {
+                               type = e->addr_source;
+                       }
+               }
+       }
+
+       /* type will only have been set if we successfully registered an si */
+       if (type) {
+               mutex_unlock(&smi_infos_lock);
+               return 0;
+       }
+
+       /* Fall back to the preferred device */
+
+       list_for_each_entry(e, &smi_infos, link) {
+               if (!e->irq && (!type || e->addr_source == type)) {
+                       if (!try_smi_init(e)) {
+                               type = e->addr_source;
+                       }
+               }
+       }
+       mutex_unlock(&smi_infos_lock);
+
+       if (type)
+               return 0;
+
        if (si_trydefaults) {
                mutex_lock(&smi_infos_lock);
                if (list_empty(&smi_infos)) {
                        /* No BMC was found, try defaults. */
                        mutex_unlock(&smi_infos_lock);
                        default_find_bmc();
-               } else {
+               } else
                        mutex_unlock(&smi_infos_lock);
-               }
        }
 
        mutex_lock(&smi_infos_lock);
@@ -3308,8 +3390,8 @@ static __devinit int init_ipmi_si(void)
                of_unregister_platform_driver(&ipmi_of_platform_driver);
 #endif
                driver_unregister(&ipmi_driver.driver);
-               printk(KERN_WARNING
-                      "ipmi_si: Unable to find any System Interface(s)\n");
+               printk(KERN_WARNING PFX
+                      "Unable to find any System Interface(s)\n");
                return -ENODEV;
        } else {
                mutex_unlock(&smi_infos_lock);
@@ -3320,7 +3402,7 @@ module_init(init_ipmi_si);
 
 static void cleanup_one_si(struct smi_info *to_clean)
 {
-       int           rv;
+       int           rv = 0;
        unsigned long flags;
 
        if (!to_clean)
@@ -3364,14 +3446,16 @@ static void cleanup_one_si(struct smi_info *to_clean)
                schedule_timeout_uninterruptible(1);
        }
 
-       rv = ipmi_unregister_smi(to_clean->intf);
+       if (to_clean->intf)
+               rv = ipmi_unregister_smi(to_clean->intf);
+
        if (rv) {
-               printk(KERN_ERR
-                      "ipmi_si: Unable to unregister device: errno=%d\n",
+               printk(KERN_ERR PFX "Unable to unregister device: errno=%d\n",
                       rv);
        }
 
-       to_clean->handlers->cleanup(to_clean->si_sm);
+       if (to_clean->handlers)
+               to_clean->handlers->cleanup(to_clean->si_sm);
 
        kfree(to_clean->si_sm);
 
index fdd37543aa79e6d0b159767f791024d4c31e83fb..02abfddce45a192ceccae3d71f3008ba7d329767 100644 (file)
@@ -287,12 +287,10 @@ static int register_device (int minor, struct pp_struct *pp)
        char *name;
        int fl;
 
-       name = kmalloc (strlen (CHRDEV) + 3, GFP_KERNEL);
+       name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor);
        if (name == NULL)
                return -ENOMEM;
 
-       sprintf (name, CHRDEV "%x", minor);
-
        port = parport_find_number (minor);
        if (!port) {
                printk (KERN_WARNING "%s: no associated port!\n", name);
diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c
new file mode 100644 (file)
index 0000000..74f00b5
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * RAM Oops/Panic logger
+ *
+ * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kmsg_dump.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+
+#define RAMOOPS_KERNMSG_HDR "===="
+#define RAMOOPS_HEADER_SIZE   (5 + sizeof(struct timeval))
+
+#define RECORD_SIZE 4096
+
+static ulong mem_address;
+module_param(mem_address, ulong, 0400);
+MODULE_PARM_DESC(mem_address,
+               "start of reserved RAM used to store oops/panic logs");
+
+static ulong mem_size;
+module_param(mem_size, ulong, 0400);
+MODULE_PARM_DESC(mem_size,
+               "size of reserved RAM used to store oops/panic logs");
+
+static int dump_oops = 1;
+module_param(dump_oops, int, 0600);
+MODULE_PARM_DESC(dump_oops,
+               "set to 1 to dump oopses, 0 to only dump panics (default 1)");
+
+static struct ramoops_context {
+       struct kmsg_dumper dump;
+       void *virt_addr;
+       phys_addr_t phys_addr;
+       unsigned long size;
+       int count;
+       int max_count;
+} oops_cxt;
+
+static void ramoops_do_dump(struct kmsg_dumper *dumper,
+               enum kmsg_dump_reason reason, const char *s1, unsigned long l1,
+               const char *s2, unsigned long l2)
+{
+       struct ramoops_context *cxt = container_of(dumper,
+                       struct ramoops_context, dump);
+       unsigned long s1_start, s2_start;
+       unsigned long l1_cpy, l2_cpy;
+       int res;
+       char *buf;
+       struct timeval timestamp;
+
+       /* Only dump oopses if dump_oops is set */
+       if (reason == KMSG_DUMP_OOPS && !dump_oops)
+               return;
+
+       buf = (char *)(cxt->virt_addr + (cxt->count * RECORD_SIZE));
+       memset(buf, '\0', RECORD_SIZE);
+       res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
+       buf += res;
+       do_gettimeofday(&timestamp);
+       res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
+       buf += res;
+
+       l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE));
+       l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE) - l2_cpy);
+
+       s2_start = l2 - l2_cpy;
+       s1_start = l1 - l1_cpy;
+
+       memcpy(buf, s1 + s1_start, l1_cpy);
+       memcpy(buf + l1_cpy, s2 + s2_start, l2_cpy);
+
+       cxt->count = (cxt->count + 1) % cxt->max_count;
+}
+
+static int __init ramoops_init(void)
+{
+       struct ramoops_context *cxt = &oops_cxt;
+       int err = -EINVAL;
+
+       if (!mem_size) {
+               printk(KERN_ERR "ramoops: invalid size specification");
+               goto fail3;
+       }
+
+       rounddown_pow_of_two(mem_size);
+
+       if (mem_size < RECORD_SIZE) {
+               printk(KERN_ERR "ramoops: size too small");
+               goto fail3;
+       }
+
+       cxt->max_count = mem_size / RECORD_SIZE;
+       cxt->count = 0;
+       cxt->size = mem_size;
+       cxt->phys_addr = mem_address;
+
+       if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
+               printk(KERN_ERR "ramoops: request mem region failed");
+               err = -EINVAL;
+               goto fail3;
+       }
+
+       cxt->virt_addr = ioremap(cxt->phys_addr,  cxt->size);
+       if (!cxt->virt_addr) {
+               printk(KERN_ERR "ramoops: ioremap failed");
+               goto fail2;
+       }
+
+       cxt->dump.dump = ramoops_do_dump;
+       err = kmsg_dump_register(&cxt->dump);
+       if (err) {
+               printk(KERN_ERR "ramoops: registering kmsg dumper failed");
+               goto fail1;
+       }
+
+       return 0;
+
+fail1:
+       iounmap(cxt->virt_addr);
+fail2:
+       release_mem_region(cxt->phys_addr, cxt->size);
+fail3:
+       return err;
+}
+
+static void __exit ramoops_exit(void)
+{
+       struct ramoops_context *cxt = &oops_cxt;
+
+       if (kmsg_dump_unregister(&cxt->dump) < 0)
+               printk(KERN_WARNING "ramoops: could not unregister kmsg_dumper");
+
+       iounmap(cxt->virt_addr);
+       release_mem_region(cxt->phys_addr, cxt->size);
+}
+
+
+module_init(ramoops_init);
+module_exit(ramoops_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>");
+MODULE_DESCRIPTION("RAM Oops/Panic logger/driver");
index bd1d1164fec5a49feb20cab71cbfbba51233ed9e..7cdb6ee569cd7ca592bedfea458f0b676ec937af 100644 (file)
@@ -3967,13 +3967,9 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op)
        font.charcount = op->charcount;
        font.height = op->height;
        font.width = op->width;
-       font.data = kmalloc(size, GFP_KERNEL);
-       if (!font.data)
-               return -ENOMEM;
-       if (copy_from_user(font.data, op->data, size)) {
-               kfree(font.data);
-               return -EFAULT;
-       }
+       font.data = memdup_user(op->data, size);
+       if (IS_ERR(font.data))
+               return PTR_ERR(font.data);
        acquire_console_sem();
        if (vc->vc_sw->con_font_set)
                rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
index adc10a2ac5f63b0e1dbd90ca2ca529e9e2a5b15c..996c1bdb5a34379c474d7c1100aabeb419f30996 100644 (file)
@@ -774,7 +774,7 @@ static void i5000_clear_error(struct mem_ctl_info *mci)
 static void i5000_check_error(struct mem_ctl_info *mci)
 {
        struct i5000_error_info info;
-       debugf4("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+       debugf4("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
        i5000_get_error_info(mci, &info);
        i5000_process_error_info(mci, &info, 1);
 }
@@ -1353,8 +1353,8 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
        int num_dimms_per_channel;
        int num_csrows;
 
-       debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
-               __func__,
+       debugf0("MC: %s: %s(), pdev bus %u dev=0x%x fn=0x%x\n",
+               __FILE__, __func__,
                pdev->bus->number,
                PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
@@ -1389,7 +1389,7 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
                return -ENOMEM;
 
        kobject_get(&mci->edac_mci_kobj);
-       debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+       debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
 
        mci->dev = &pdev->dev;  /* record ptr  to the generic device */
 
@@ -1432,8 +1432,8 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
 
        /* add this new MC control structure to EDAC's list of MCs */
        if (edac_mc_add_mc(mci)) {
-               debugf0("MC: " __FILE__
-                       ": %s(): failed edac_mc_add_mc()\n", __func__);
+               debugf0("MC: %s: %s(): failed edac_mc_add_mc()\n",
+                       __FILE__, __func__);
                /* FIXME: perhaps some code should go here that disables error
                 * reporting if we just enabled it
                 */
@@ -1478,7 +1478,7 @@ static int __devinit i5000_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: " __FILE__ ": %s()\n", __func__);
+       debugf0("MC: %s: %s()\n", __FILE__, __func__);
 
        /* wake up device */
        rc = pci_enable_device(pdev);
@@ -1497,7 +1497,7 @@ static void __devexit i5000_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0(__FILE__ ": %s()\n", __func__);
+       debugf0("%s: %s()\n", __FILE__, __func__);
 
        if (i5000_pci)
                edac_pci_release_generic_ctl(i5000_pci);
@@ -1544,7 +1544,7 @@ static int __init i5000_init(void)
 {
        int pci_rc;
 
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       debugf2("MC: %s: %s()\n", __FILE__, __func__);
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -1560,7 +1560,7 @@ static int __init i5000_init(void)
  */
 static void __exit i5000_exit(void)
 {
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       debugf2("MC: %s: %s()\n", __FILE__, __func__);
        pci_unregister_driver(&i5000_driver);
 }
 
index f99d10655ed45cd3132f50a80144166e10aad1f5..010c1d6526f56fe6a33b2685e28ab6592dad8f80 100644 (file)
@@ -694,7 +694,7 @@ static void i5400_clear_error(struct mem_ctl_info *mci)
 static void i5400_check_error(struct mem_ctl_info *mci)
 {
        struct i5400_error_info info;
-       debugf4("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+       debugf4("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
        i5400_get_error_info(mci, &info);
        i5400_process_error_info(mci, &info);
 }
@@ -1227,8 +1227,8 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
        if (dev_idx >= ARRAY_SIZE(i5400_devs))
                return -EINVAL;
 
-       debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
-               __func__,
+       debugf0("MC: %s: %s(), pdev bus %u dev=0x%x fn=0x%x\n",
+               __FILE__, __func__,
                pdev->bus->number,
                PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
@@ -1256,7 +1256,7 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
-       debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+       debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
 
        mci->dev = &pdev->dev;  /* record ptr  to the generic device */
 
@@ -1299,8 +1299,8 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
 
        /* add this new MC control structure to EDAC's list of MCs */
        if (edac_mc_add_mc(mci)) {
-               debugf0("MC: " __FILE__
-                       ": %s(): failed edac_mc_add_mc()\n", __func__);
+               debugf0("MC: %s: %s(): failed edac_mc_add_mc()\n",
+                       __FILE__, __func__);
                /* FIXME: perhaps some code should go here that disables error
                 * reporting if we just enabled it
                 */
@@ -1344,7 +1344,7 @@ static int __devinit i5400_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: " __FILE__ ": %s()\n", __func__);
+       debugf0("MC: %s: %s()\n", __FILE__, __func__);
 
        /* wake up device */
        rc = pci_enable_device(pdev);
@@ -1363,7 +1363,7 @@ static void __devexit i5400_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0(__FILE__ ": %s()\n", __func__);
+       debugf0("%s: %s()\n", __FILE__, __func__);
 
        if (i5400_pci)
                edac_pci_release_generic_ctl(i5400_pci);
@@ -1409,7 +1409,7 @@ static int __init i5400_init(void)
 {
        int pci_rc;
 
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       debugf2("MC: %s: %s()\n", __FILE__, __func__);
 
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
@@ -1425,7 +1425,7 @@ static int __init i5400_init(void)
  */
 static void __exit i5400_exit(void)
 {
-       debugf2("MC: " __FILE__ ": %s()\n", __func__);
+       debugf2("MC: %s: %s()\n", __FILE__, __func__);
        pci_unregister_driver(&i5400_driver);
 }
 
index 2bf2c5051bfe2adc0ec7edc53f57bf2c83dbed77..a2fa1feed724dce86fa29490972a9d8298e4259c 100644 (file)
@@ -178,7 +178,7 @@ static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
 {
        struct i82443bxgx_edacmc_error_info info;
 
-       debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+       debugf1("MC%d: %s: %s()\n", mci->mc_idx, __FILE__, __func__);
        i82443bxgx_edacmc_get_error_info(mci, &info);
        i82443bxgx_edacmc_process_error_info(mci, &info, 1);
 }
@@ -198,13 +198,13 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
        for (index = 0; index < mci->nr_csrows; index++) {
                csrow = &mci->csrows[index];
                pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
-               debugf1("MC%d: " __FILE__ ": %s() Row=%d DRB = %#0x\n",
-                       mci->mc_idx, __func__, index, drbar);
+               debugf1("MC%d: %s: %s() Row=%d DRB = %#0x\n",
+                       mci->mc_idx, __FILE__, __func__, index, drbar);
                row_high_limit = ((u32) drbar << 23);
                /* find the DRAM Chip Select Base address and mask */
-               debugf1("MC%d: " __FILE__ ": %s() Row=%d, "
-                       "Boundry Address=%#0x, Last = %#0x \n",
-                       mci->mc_idx, __func__, index, row_high_limit,
+               debugf1("MC%d: %s: %s() Row=%d, "
+                       "Boundry Address=%#0x, Last = %#0x\n",
+                       mci->mc_idx, __FILE__, __func__, index, row_high_limit,
                        row_high_limit_last);
 
                /* 440GX goes to 2GB, represented with a DRB of 0. */
@@ -237,7 +237,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
        enum mem_type mtype;
        enum edac_type edac_mode;
 
-       debugf0("MC: " __FILE__ ": %s()\n", __func__);
+       debugf0("MC: %s: %s()\n", __FILE__, __func__);
 
        /* Something is really hosed if PCI config space reads from
         * the MC aren't working.
@@ -250,7 +250,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
        if (mci == NULL)
                return -ENOMEM;
 
-       debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+       debugf0("MC: %s: %s(): mci = %p\n", __FILE__, __func__, mci);
        mci->dev = &pdev->dev;
        mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
        mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
@@ -336,7 +336,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
                        __func__);
        }
 
-       debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+       debugf3("MC: %s: %s(): success\n", __FILE__, __func__);
        return 0;
 
 fail:
@@ -352,7 +352,7 @@ static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
 {
        int rc;
 
-       debugf0("MC: " __FILE__ ": %s()\n", __func__);
+       debugf0("MC: %s: %s()\n", __FILE__, __func__);
 
        /* don't need to call pci_enable_device() */
        rc = i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
@@ -367,7 +367,7 @@ static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
 
-       debugf0(__FILE__ ": %s()\n", __func__);
+       debugf0("%s: %s()\n", __FILE__, __func__);
 
        if (i82443bxgx_pci)
                edac_pci_release_generic_ctl(i82443bxgx_pci);
index 5045156c5313b0c59114850f003f17ef46945c36..9dcb30466ec0a22a11092decb65474e7bdcc5191 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
-#include <linux/timer.h>
 #include <linux/workqueue.h>
 
 #include <asm/atomic.h>
@@ -63,7 +62,7 @@ static size_t config_rom_length = 1 + 4 + 1 + 1;
 #define BIB_CRC(v)             ((v) <<  0)
 #define BIB_CRC_LENGTH(v)      ((v) << 16)
 #define BIB_INFO_LENGTH(v)     ((v) << 24)
-
+#define BIB_BUS_NAME           0x31333934 /* "1394" */
 #define BIB_LINK_SPEED(v)      ((v) <<  0)
 #define BIB_GENERATION(v)      ((v) <<  4)
 #define BIB_MAX_ROM(v)         ((v) <<  8)
@@ -73,7 +72,8 @@ static size_t config_rom_length = 1 + 4 + 1 + 1;
 #define BIB_BMC                        ((1) << 28)
 #define BIB_ISC                        ((1) << 29)
 #define BIB_CMC                        ((1) << 30)
-#define BIB_IMC                        ((1) << 31)
+#define BIB_IRMC               ((1) << 31)
+#define NODE_CAPABILITIES      0x0c0083c0 /* per IEEE 1394 clause 8.3.2.6.5.2 */
 
 static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
 {
@@ -91,18 +91,18 @@ static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
 
        config_rom[0] = cpu_to_be32(
                BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0));
-       config_rom[1] = cpu_to_be32(0x31333934);
+       config_rom[1] = cpu_to_be32(BIB_BUS_NAME);
        config_rom[2] = cpu_to_be32(
                BIB_LINK_SPEED(card->link_speed) |
                BIB_GENERATION(card->config_rom_generation++ % 14 + 2) |
                BIB_MAX_ROM(2) |
                BIB_MAX_RECEIVE(card->max_receive) |
-               BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC);
+               BIB_BMC | BIB_ISC | BIB_CMC | BIB_IRMC);
        config_rom[3] = cpu_to_be32(card->guid >> 32);
        config_rom[4] = cpu_to_be32(card->guid);
 
        /* Generate root directory. */
-       config_rom[6] = cpu_to_be32(0x0c0083c0); /* node capabilities */
+       config_rom[6] = cpu_to_be32(NODE_CAPABILITIES);
        i = 7;
        j = 7 + descriptor_count;
 
@@ -407,13 +407,6 @@ static void fw_card_bm_work(struct work_struct *work)
        fw_card_put(card);
 }
 
-static void flush_timer_callback(unsigned long data)
-{
-       struct fw_card *card = (struct fw_card *)data;
-
-       fw_flush_transactions(card);
-}
-
 void fw_card_initialize(struct fw_card *card,
                        const struct fw_card_driver *driver,
                        struct device *device)
@@ -432,8 +425,6 @@ void fw_card_initialize(struct fw_card *card,
        init_completion(&card->done);
        INIT_LIST_HEAD(&card->transaction_list);
        spin_lock_init(&card->lock);
-       setup_timer(&card->flush_timer,
-                   flush_timer_callback, (unsigned long)card);
 
        card->local_node = NULL;
 
@@ -558,7 +549,6 @@ void fw_core_remove_card(struct fw_card *card)
        wait_for_completion(&card->done);
 
        WARN_ON(!list_empty(&card->transaction_list));
-       del_timer_sync(&card->flush_timer);
 }
 EXPORT_SYMBOL(fw_core_remove_card);
 
index 14a34d99eea25554bb123af7c44f44e8d01582a8..5bf106b9d79193138349d6e54adfd65490dfccb8 100644 (file)
@@ -227,7 +227,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
        list_add_tail(&client->link, &device->client_list);
        mutex_unlock(&device->client_list_mutex);
 
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static void queue_event(struct client *client, struct event *event,
@@ -1496,13 +1496,13 @@ static unsigned int fw_device_op_poll(struct file *file, poll_table * pt)
 
 const struct file_operations fw_device_ops = {
        .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
        .open           = fw_device_op_open,
        .read           = fw_device_op_read,
        .unlocked_ioctl = fw_device_op_ioctl,
-       .poll           = fw_device_op_poll,
-       .release        = fw_device_op_release,
        .mmap           = fw_device_op_mmap,
-
+       .release        = fw_device_op_release,
+       .poll           = fw_device_op_poll,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = fw_device_op_compat_ioctl,
 #endif
index 673b03f8b4ecd6cbe1ac577e845350a6bcb7dca8..fdc33ff06dc11c536b080797d1ba4a81482711b0 100644 (file)
@@ -81,7 +81,7 @@ static int close_transaction(struct fw_transaction *transaction,
        spin_lock_irqsave(&card->lock, flags);
        list_for_each_entry(t, &card->transaction_list, link) {
                if (t == transaction) {
-                       list_del(&t->link);
+                       list_del_init(&t->link);
                        card->tlabel_mask &= ~(1ULL << t->tlabel);
                        break;
                }
@@ -89,6 +89,7 @@ static int close_transaction(struct fw_transaction *transaction,
        spin_unlock_irqrestore(&card->lock, flags);
 
        if (&t->link != &card->transaction_list) {
+               del_timer_sync(&t->split_timeout_timer);
                t->callback(card, rcode, NULL, 0, t->callback_data);
                return 0;
        }
@@ -121,6 +122,31 @@ int fw_cancel_transaction(struct fw_card *card,
 }
 EXPORT_SYMBOL(fw_cancel_transaction);
 
+static void split_transaction_timeout_callback(unsigned long data)
+{
+       struct fw_transaction *t = (struct fw_transaction *)data;
+       struct fw_card *card = t->card;
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+       if (list_empty(&t->link)) {
+               spin_unlock_irqrestore(&card->lock, flags);
+               return;
+       }
+       list_del(&t->link);
+       card->tlabel_mask &= ~(1ULL << t->tlabel);
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       card->driver->cancel_packet(card, &t->packet);
+
+       /*
+        * At this point cancel_packet will never call the transaction
+        * callback, since we just took the transaction out of the list.
+        * So do it here.
+        */
+       t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
+}
+
 static void transmit_complete_callback(struct fw_packet *packet,
                                       struct fw_card *card, int status)
 {
@@ -229,6 +255,23 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
        packet->payload_mapped = false;
 }
 
+static int allocate_tlabel(struct fw_card *card)
+{
+       int tlabel;
+
+       tlabel = card->current_tlabel;
+       while (card->tlabel_mask & (1ULL << tlabel)) {
+               tlabel = (tlabel + 1) & 0x3f;
+               if (tlabel == card->current_tlabel)
+                       return -EBUSY;
+       }
+
+       card->current_tlabel = (tlabel + 1) & 0x3f;
+       card->tlabel_mask |= 1ULL << tlabel;
+
+       return tlabel;
+}
+
 /**
  * This function provides low-level access to the IEEE1394 transaction
  * logic.  Most C programs would use either fw_read(), fw_write() or
@@ -276,13 +319,6 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
        unsigned long flags;
        int tlabel;
 
-       /*
-        * Bump the flush timer up 100ms first of all so we
-        * don't race with a flush timer callback.
-        */
-
-       mod_timer(&card->flush_timer, jiffies + DIV_ROUND_UP(HZ, 10));
-
        /*
         * Allocate tlabel from the bitmap and put the transaction on
         * the list while holding the card spinlock.
@@ -290,18 +326,20 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
 
        spin_lock_irqsave(&card->lock, flags);
 
-       tlabel = card->current_tlabel;
-       if (card->tlabel_mask & (1ULL << tlabel)) {
+       tlabel = allocate_tlabel(card);
+       if (tlabel < 0) {
                spin_unlock_irqrestore(&card->lock, flags);
                callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
                return;
        }
 
-       card->current_tlabel = (card->current_tlabel + 1) & 0x3f;
-       card->tlabel_mask |= (1ULL << tlabel);
-
        t->node_id = destination_id;
        t->tlabel = tlabel;
+       t->card = card;
+       setup_timer(&t->split_timeout_timer,
+                   split_transaction_timeout_callback, (unsigned long)t);
+       /* FIXME: start this timer later, relative to t->timestamp */
+       mod_timer(&t->split_timeout_timer, jiffies + DIV_ROUND_UP(HZ, 10));
        t->callback = callback;
        t->callback_data = callback_data;
 
@@ -347,11 +385,13 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
        struct transaction_callback_data d;
        struct fw_transaction t;
 
+       init_timer_on_stack(&t.split_timeout_timer);
        init_completion(&d.done);
        d.payload = payload;
        fw_send_request(card, &t, tcode, destination_id, generation, speed,
                        offset, payload, length, transaction_callback, &d);
        wait_for_completion(&d.done);
+       destroy_timer_on_stack(&t.split_timeout_timer);
 
        return d.rcode;
 }
@@ -394,30 +434,6 @@ void fw_send_phy_config(struct fw_card *card,
        mutex_unlock(&phy_config_mutex);
 }
 
-void fw_flush_transactions(struct fw_card *card)
-{
-       struct fw_transaction *t, *next;
-       struct list_head list;
-       unsigned long flags;
-
-       INIT_LIST_HEAD(&list);
-       spin_lock_irqsave(&card->lock, flags);
-       list_splice_init(&card->transaction_list, &list);
-       card->tlabel_mask = 0;
-       spin_unlock_irqrestore(&card->lock, flags);
-
-       list_for_each_entry_safe(t, next, &list, link) {
-               card->driver->cancel_packet(card, &t->packet);
-
-               /*
-                * At this point cancel_packet will never call the
-                * transaction callback, since we just took all the
-                * transactions out of the list.  So do it here.
-                */
-               t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
-       }
-}
-
 static struct fw_address_handler *lookup_overlapping_address_handler(
        struct list_head *list, unsigned long long offset, size_t length)
 {
@@ -827,8 +843,8 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
        spin_lock_irqsave(&card->lock, flags);
        list_for_each_entry(t, &card->transaction_list, link) {
                if (t->node_id == source && t->tlabel == tlabel) {
-                       list_del(&t->link);
-                       card->tlabel_mask &= ~(1 << t->tlabel);
+                       list_del_init(&t->link);
+                       card->tlabel_mask &= ~(1ULL << t->tlabel);
                        break;
                }
        }
@@ -869,6 +885,8 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
                break;
        }
 
+       del_timer_sync(&t->split_timeout_timer);
+
        /*
         * The response handler may be executed while the request handler
         * is still pending.  Cancel the request handler.
index fb0321300cce4a01b646e77a5f0d040c0f46f25d..0ecfcd95f4c500f62389aa4085c68281b648cc7c 100644 (file)
@@ -27,7 +27,12 @@ struct fw_packet;
 #define PHY_LINK_ACTIVE                0x80
 #define PHY_CONTENDER          0x40
 #define PHY_BUS_RESET          0x40
+#define PHY_EXTENDED_REGISTERS 0xe0
 #define PHY_BUS_SHORT_RESET    0x40
+#define PHY_INT_STATUS_BITS    0x3c
+#define PHY_ENABLE_ACCEL       0x02
+#define PHY_ENABLE_MULTI       0x01
+#define PHY_PAGE_SELECT                0xe0
 
 #define BANDWIDTH_AVAILABLE_INITIAL    4915
 #define BROADCAST_CHANNEL_INITIAL      (1 << 31 | 31)
@@ -215,7 +220,6 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
 void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
 void fw_fill_response(struct fw_packet *response, u32 *request_header,
                      int rcode, void *payload, size_t length);
-void fw_flush_transactions(struct fw_card *card);
 void fw_send_phy_config(struct fw_card *card,
                        int node_id, int generation, int gap_count);
 
index a3b083a7403a20049746c69bd4ad2d716157ef55..9f627e758cfc503eb6a56b51c4f0fdd413ef4b32 100644 (file)
@@ -236,13 +236,15 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
 #define QUIRK_CYCLE_TIMER              1
 #define QUIRK_RESET_PACKET             2
 #define QUIRK_BE_HEADERS               4
+#define QUIRK_NO_1394A                 8
 
 /* In case of multiple matches in ohci_quirks[], only the first one is used. */
 static const struct {
        unsigned short vendor, device, flags;
 } ohci_quirks[] = {
        {PCI_VENDOR_ID_TI,      PCI_DEVICE_ID_TI_TSB12LV22, QUIRK_CYCLE_TIMER |
-                                                           QUIRK_RESET_PACKET},
+                                                           QUIRK_RESET_PACKET |
+                                                           QUIRK_NO_1394A},
        {PCI_VENDOR_ID_TI,      PCI_ANY_ID,     QUIRK_RESET_PACKET},
        {PCI_VENDOR_ID_AL,      PCI_ANY_ID,     QUIRK_CYCLE_TIMER},
        {PCI_VENDOR_ID_NEC,     PCI_ANY_ID,     QUIRK_CYCLE_TIMER},
@@ -257,15 +259,16 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
        ", nonatomic cycle timer = "    __stringify(QUIRK_CYCLE_TIMER)
        ", reset packet generation = "  __stringify(QUIRK_RESET_PACKET)
        ", AR/selfID endianess = "      __stringify(QUIRK_BE_HEADERS)
+       ", no 1394a enhancements = "    __stringify(QUIRK_NO_1394A)
        ")");
 
-#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
-
 #define OHCI_PARAM_DEBUG_AT_AR         1
 #define OHCI_PARAM_DEBUG_SELFIDS       2
 #define OHCI_PARAM_DEBUG_IRQS          4
 #define OHCI_PARAM_DEBUG_BUSRESETS     8 /* only effective before chip init */
 
+#ifdef CONFIG_FIREWIRE_OHCI_DEBUG
+
 static int param_debug;
 module_param_named(debug, param_debug, int, 0644);
 MODULE_PARM_DESC(debug, "Verbose logging (default = 0"
@@ -438,9 +441,10 @@ static void log_ar_at_event(char dir, int speed, u32 *header, int evt)
 
 #else
 
-#define log_irqs(evt)
-#define log_selfids(node_id, generation, self_id_count, sid)
-#define log_ar_at_event(dir, speed, header, evt)
+#define param_debug 0
+static inline void log_irqs(u32 evt) {}
+static inline void log_selfids(int node_id, int generation, int self_id_count, u32 *s) {}
+static inline void log_ar_at_event(char dir, int speed, u32 *header, int evt) {}
 
 #endif /* CONFIG_FIREWIRE_OHCI_DEBUG */
 
@@ -460,27 +464,71 @@ static inline void flush_writes(const struct fw_ohci *ohci)
        reg_read(ohci, OHCI1394_Version);
 }
 
-static int ohci_update_phy_reg(struct fw_card *card, int addr,
-                              int clear_bits, int set_bits)
+static int read_phy_reg(struct fw_ohci *ohci, int addr)
 {
-       struct fw_ohci *ohci = fw_ohci(card);
-       u32 val, old;
+       u32 val;
+       int i;
 
        reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));
-       flush_writes(ohci);
-       msleep(2);
-       val = reg_read(ohci, OHCI1394_PhyControl);
-       if ((val & OHCI1394_PhyControl_ReadDone) == 0) {
-               fw_error("failed to set phy reg bits.\n");
-               return -EBUSY;
+       for (i = 0; i < 10; i++) {
+               val = reg_read(ohci, OHCI1394_PhyControl);
+               if (val & OHCI1394_PhyControl_ReadDone)
+                       return OHCI1394_PhyControl_ReadData(val);
+
+               msleep(1);
        }
+       fw_error("failed to read phy reg\n");
+
+       return -EBUSY;
+}
+
+static int write_phy_reg(const struct fw_ohci *ohci, int addr, u32 val)
+{
+       int i;
 
-       old = OHCI1394_PhyControl_ReadData(val);
-       old = (old & ~clear_bits) | set_bits;
        reg_write(ohci, OHCI1394_PhyControl,
-                 OHCI1394_PhyControl_Write(addr, old));
+                 OHCI1394_PhyControl_Write(addr, val));
+       for (i = 0; i < 100; i++) {
+               val = reg_read(ohci, OHCI1394_PhyControl);
+               if (!(val & OHCI1394_PhyControl_WritePending))
+                       return 0;
 
-       return 0;
+               msleep(1);
+       }
+       fw_error("failed to write phy reg\n");
+
+       return -EBUSY;
+}
+
+static int ohci_update_phy_reg(struct fw_card *card, int addr,
+                              int clear_bits, int set_bits)
+{
+       struct fw_ohci *ohci = fw_ohci(card);
+       int ret;
+
+       ret = read_phy_reg(ohci, addr);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * The interrupt status bits are cleared by writing a one bit.
+        * Avoid clearing them unless explicitly requested in set_bits.
+        */
+       if (addr == 5)
+               clear_bits |= PHY_INT_STATUS_BITS;
+
+       return write_phy_reg(ohci, addr, (ret & ~clear_bits) | set_bits);
+}
+
+static int read_paged_phy_reg(struct fw_ohci *ohci, int page, int addr)
+{
+       int ret;
+
+       ret = ohci_update_phy_reg(&ohci->card, 7, PHY_PAGE_SELECT, page << 5);
+       if (ret < 0)
+               return ret;
+
+       return read_phy_reg(ohci, addr);
 }
 
 static int ar_context_add_page(struct ar_context *ctx)
@@ -1495,13 +1543,64 @@ static void copy_config_rom(__be32 *dest, const __be32 *src, size_t length)
                memset(&dest[length], 0, CONFIG_ROM_SIZE - size);
 }
 
+static int configure_1394a_enhancements(struct fw_ohci *ohci)
+{
+       bool enable_1394a;
+       int ret, clear, set, offset;
+
+       /* Check if the driver should configure link and PHY. */
+       if (!(reg_read(ohci, OHCI1394_HCControlSet) &
+             OHCI1394_HCControl_programPhyEnable))
+               return 0;
+
+       /* Paranoia: check whether the PHY supports 1394a, too. */
+       enable_1394a = false;
+       ret = read_phy_reg(ohci, 2);
+       if (ret < 0)
+               return ret;
+       if ((ret & PHY_EXTENDED_REGISTERS) == PHY_EXTENDED_REGISTERS) {
+               ret = read_paged_phy_reg(ohci, 1, 8);
+               if (ret < 0)
+                       return ret;
+               if (ret >= 1)
+                       enable_1394a = true;
+       }
+
+       if (ohci->quirks & QUIRK_NO_1394A)
+               enable_1394a = false;
+
+       /* Configure PHY and link consistently. */
+       if (enable_1394a) {
+               clear = 0;
+               set = PHY_ENABLE_ACCEL | PHY_ENABLE_MULTI;
+       } else {
+               clear = PHY_ENABLE_ACCEL | PHY_ENABLE_MULTI;
+               set = 0;
+       }
+       ret = ohci_update_phy_reg(&ohci->card, 5, clear, set);
+       if (ret < 0)
+               return ret;
+
+       if (enable_1394a)
+               offset = OHCI1394_HCControlSet;
+       else
+               offset = OHCI1394_HCControlClear;
+       reg_write(ohci, offset, OHCI1394_HCControl_aPhyEnhanceEnable);
+
+       /* Clean up: configuration has been taken care of. */
+       reg_write(ohci, OHCI1394_HCControlClear,
+                 OHCI1394_HCControl_programPhyEnable);
+
+       return 0;
+}
+
 static int ohci_enable(struct fw_card *card,
                       const __be32 *config_rom, size_t length)
 {
        struct fw_ohci *ohci = fw_ohci(card);
        struct pci_dev *dev = to_pci_dev(card->device);
        u32 lps;
-       int i;
+       int i, ret;
 
        if (software_reset(ohci)) {
                fw_error("Failed to reset ohci card.\n");
@@ -1565,10 +1664,14 @@ static int ohci_enable(struct fw_card *card,
        if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS)
                reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
 
+       ret = configure_1394a_enhancements(ohci);
+       if (ret < 0)
+               return ret;
+
        /* Activate link_on bit and contender bit in our self ID packets.*/
-       if (ohci_update_phy_reg(card, 4, 0,
-                               PHY_LINK_ACTIVE | PHY_CONTENDER) < 0)
-               return -EIO;
+       ret = ohci_update_phy_reg(card, 4, 0, PHY_LINK_ACTIVE | PHY_CONTENDER);
+       if (ret < 0)
+               return ret;
 
        /*
         * When the link is not yet enabled, the atomic config rom
@@ -2304,7 +2407,7 @@ static const struct fw_card_driver ohci_driver = {
 };
 
 #ifdef CONFIG_PPC_PMAC
-static void ohci_pmac_on(struct pci_dev *dev)
+static void pmac_ohci_on(struct pci_dev *dev)
 {
        if (machine_is(powermac)) {
                struct device_node *ofn = pci_device_to_OF_node(dev);
@@ -2316,7 +2419,7 @@ static void ohci_pmac_on(struct pci_dev *dev)
        }
 }
 
-static void ohci_pmac_off(struct pci_dev *dev)
+static void pmac_ohci_off(struct pci_dev *dev)
 {
        if (machine_is(powermac)) {
                struct device_node *ofn = pci_device_to_OF_node(dev);
@@ -2328,15 +2431,15 @@ static void ohci_pmac_off(struct pci_dev *dev)
        }
 }
 #else
-#define ohci_pmac_on(dev)
-#define ohci_pmac_off(dev)
+static inline void pmac_ohci_on(struct pci_dev *dev) {}
+static inline void pmac_ohci_off(struct pci_dev *dev) {}
 #endif /* CONFIG_PPC_PMAC */
 
 static int __devinit pci_probe(struct pci_dev *dev,
                               const struct pci_device_id *ent)
 {
        struct fw_ohci *ohci;
-       u32 bus_options, max_receive, link_speed, version;
+       u32 bus_options, max_receive, link_speed, version, link_enh;
        u64 guid;
        int i, err, n_ir, n_it;
        size_t size;
@@ -2349,7 +2452,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
 
        fw_card_initialize(&ohci->card, &ohci_driver, &dev->dev);
 
-       ohci_pmac_on(dev);
+       pmac_ohci_on(dev);
 
        err = pci_enable_device(dev);
        if (err) {
@@ -2389,6 +2492,23 @@ static int __devinit pci_probe(struct pci_dev *dev,
        if (param_quirks)
                ohci->quirks = param_quirks;
 
+       /* TI OHCI-Lynx and compatible: set recommended configuration bits. */
+       if (dev->vendor == PCI_VENDOR_ID_TI) {
+               pci_read_config_dword(dev, PCI_CFG_TI_LinkEnh, &link_enh);
+
+               /* adjust latency of ATx FIFO: use 1.7 KB threshold */
+               link_enh &= ~TI_LinkEnh_atx_thresh_mask;
+               link_enh |= TI_LinkEnh_atx_thresh_1_7K;
+
+               /* use priority arbitration for asynchronous responses */
+               link_enh |= TI_LinkEnh_enab_unfair;
+
+               /* required for aPhyEnhanceEnable to work */
+               link_enh |= TI_LinkEnh_enab_accel;
+
+               pci_write_config_dword(dev, PCI_CFG_TI_LinkEnh, link_enh);
+       }
+
        ar_context_init(&ohci->ar_request_ctx, ohci,
                        OHCI1394_AsReqRcvContextControlSet);
 
@@ -2466,7 +2586,7 @@ static int __devinit pci_probe(struct pci_dev *dev,
        pci_disable_device(dev);
  fail_free:
        kfree(&ohci->card);
-       ohci_pmac_off(dev);
+       pmac_ohci_off(dev);
  fail:
        if (err == -ENOMEM)
                fw_error("Out of memory\n");
@@ -2509,7 +2629,7 @@ static void pci_remove(struct pci_dev *dev)
        pci_release_region(dev, 0);
        pci_disable_device(dev);
        kfree(&ohci->card);
-       ohci_pmac_off(dev);
+       pmac_ohci_off(dev);
 
        fw_notify("Removed fw-ohci device.\n");
 }
@@ -2530,7 +2650,7 @@ static int pci_suspend(struct pci_dev *dev, pm_message_t state)
        err = pci_set_power_state(dev, pci_choose_state(dev, state));
        if (err)
                fw_error("pci_set_power_state failed with %d\n", err);
-       ohci_pmac_off(dev);
+       pmac_ohci_off(dev);
 
        return 0;
 }
@@ -2540,7 +2660,7 @@ static int pci_resume(struct pci_dev *dev)
        struct fw_ohci *ohci = pci_get_drvdata(dev);
        int err;
 
-       ohci_pmac_on(dev);
+       pmac_ohci_on(dev);
        pci_set_power_state(dev, PCI_D0);
        pci_restore_state(dev);
        err = pci_enable_device(dev);
index ba492d85c516260c33339c953296408e23437e16..3bc9a5d744ebf2eb8a48d93db7f4a179c361d978 100644 (file)
@@ -67,7 +67,7 @@
 #define   OHCI1394_PhyControl_ReadDone         0x80000000
 #define   OHCI1394_PhyControl_ReadData(r)      (((r) & 0x00ff0000) >> 16)
 #define   OHCI1394_PhyControl_Write(addr, data)        (((addr) << 8) | (data) | 0x00004000)
-#define   OHCI1394_PhyControl_WriteDone                0x00004000
+#define   OHCI1394_PhyControl_WritePending     0x00004000
 #define OHCI1394_IsochronousCycleTimer        0x0F0
 #define OHCI1394_AsReqFilterHiSet             0x100
 #define OHCI1394_AsReqFilterHiClear           0x104
 
 #define OHCI1394_phy_tcode             0xe
 
+/* TI extensions */
+
+#define PCI_CFG_TI_LinkEnh             0xf4
+#define  TI_LinkEnh_enab_accel         0x00000002
+#define  TI_LinkEnh_enab_unfair                0x00000080
+#define  TI_LinkEnh_atx_thresh_mask    0x00003000
+#define  TI_LinkEnh_atx_thresh_1_7K    0x00001000
+
 #endif /* _FIREWIRE_OHCI_H */
index fee678f74a191909723ef669187528015f313780..4fd0f276df5a5656d9b4d2970ce1f2e202f1de86 100644 (file)
@@ -139,6 +139,13 @@ config GPIO_MAX732X
          Board setup code must specify the model to use, and the start
          number for these GPIOs.
 
+config GPIO_MAX732X_IRQ
+       bool "Interrupt controller support for MAX732x"
+       depends on GPIO_MAX732X=y && GENERIC_HARDIRQS
+       help
+         Say yes here to enable the max732x to be used as an interrupt
+         controller. It requires the driver to be built in the kernel.
+
 config GPIO_PCA953X
        tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports"
        depends on I2C
@@ -264,10 +271,10 @@ config GPIO_BT8XX
          If unsure, say N.
 
 config GPIO_LANGWELL
-       bool "Intel Moorestown Platform Langwell GPIO support"
+       bool "Intel Langwell/Penwell GPIO support"
        depends on PCI
        help
-         Say Y here to support Intel Moorestown platform GPIO.
+         Say Y here to support Intel Langwell/Penwell GPIO.
 
 config GPIO_TIMBERDALE
        bool "Support for timberdale GPIO IP"
index 0c3c498f2260632124ecac5ffcc2f5f81773e0d2..f73a1555e49d7d92fad5da024c4face448a8e114 100644 (file)
@@ -197,7 +197,7 @@ static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val)
        return 0;
 }
 
-static char *cs5535_gpio_names[] = {
+static const char * const cs5535_gpio_names[] = {
        "GPIO0", "GPIO1", "GPIO2", "GPIO3",
        "GPIO4", "GPIO5", "GPIO6", "GPIO7",
        "GPIO8", "GPIO9", "GPIO10", "GPIO11",
index cae1b8c5b08cbb7051b1e7ac67809cab5cb4e6bb..3ca36542e3385b0c62a33b703e637fac31884c93 100644 (file)
@@ -722,7 +722,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
        unsigned long           flags;
        struct gpio_desc        *desc;
        int                     status = -EINVAL;
-       char                    *ioname = NULL;
+       const char              *ioname = NULL;
 
        /* can't export until sysfs is available ... */
        if (!gpio_class.p) {
@@ -753,7 +753,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
                struct device   *dev;
 
                dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-                               desc, ioname ? ioname : "gpio%d", gpio);
+                               desc, ioname ? ioname : "gpio%u", gpio);
                if (!IS_ERR(dev)) {
                        status = sysfs_create_group(&dev->kobj,
                                                &gpio_attr_group);
@@ -1106,7 +1106,7 @@ unlock:
 fail:
        /* failures here can mean systems won't boot... */
        if (status)
-               pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n",
+               pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
                        chip->base, chip->base + chip->ngpio - 1,
                        chip->label ? : "generic");
        return status;
@@ -1447,6 +1447,49 @@ fail:
 }
 EXPORT_SYMBOL_GPL(gpio_direction_output);
 
+/**
+ * gpio_set_debounce - sets @debounce time for a @gpio
+ * @gpio: the gpio to set debounce time
+ * @debounce: debounce time is microseconds
+ */
+int gpio_set_debounce(unsigned gpio, unsigned debounce)
+{
+       unsigned long           flags;
+       struct gpio_chip        *chip;
+       struct gpio_desc        *desc = &gpio_desc[gpio];
+       int                     status = -EINVAL;
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       if (!gpio_is_valid(gpio))
+               goto fail;
+       chip = desc->chip;
+       if (!chip || !chip->set || !chip->set_debounce)
+               goto fail;
+       gpio -= chip->base;
+       if (gpio >= chip->ngpio)
+               goto fail;
+       status = gpio_ensure_requested(desc, gpio);
+       if (status < 0)
+               goto fail;
+
+       /* now we know the gpio is valid and chip won't vanish */
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
+       might_sleep_if(extra_checks && chip->can_sleep);
+
+       return chip->set_debounce(chip, gpio, debounce);
+
+fail:
+       spin_unlock_irqrestore(&gpio_lock, flags);
+       if (status)
+               pr_debug("%s: gpio-%d status %d\n",
+                       __func__, gpio, status);
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(gpio_set_debounce);
 
 /* I/O calls are only valid after configuration completed; the relevant
  * "is this a valid GPIO" error checks should already have been done.
index 41a9388f2fde03917455e77a9d18149ba3f292dc..48fc43c4bdd11fc2849a2273fcdf10e98267cc91 100644 (file)
@@ -217,7 +217,10 @@ gpiochip_add_err:
 static void __exit it8761e_gpio_exit(void)
 {
        if (gpio_ba) {
-               gpiochip_remove(&it8761e_gpio_chip);
+               int ret = gpiochip_remove(&it8761e_gpio_chip);
+
+               WARN(ret, "%s(): gpiochip_remove() failed, ret=%d\n",
+                               __func__, ret);
 
                release_region(gpio_ba, GPIO_IOSIZE);
                gpio_ba = 0;
index 00c3a14127af0059b08206fd49eabf07f8ed4cd9..8383a8d7f9945dee14f15fb6b4ba3c08a3885fe6 100644 (file)
@@ -17,6 +17,7 @@
 
 /* Supports:
  * Moorestown platform Langwell chip.
+ * Medfield platform Penwell chip.
  */
 
 #include <linux/module.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
 
-struct lnw_gpio_register {
-       u32     GPLR[2];
-       u32     GPDR[2];
-       u32     GPSR[2];
-       u32     GPCR[2];
-       u32     GRER[2];
-       u32     GFER[2];
-       u32     GEDR[2];
+/*
+ * Langwell chip has 64 pins and thus there are 2 32bit registers to control
+ * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit
+ * registers to control them, so we only define the order here instead of a
+ * structure, to get a bit offset for a pin (use GPDR as an example):
+ *
+ * nreg = ngpio / 32;
+ * reg = offset / 32;
+ * bit = offset % 32;
+ * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4;
+ *
+ * so the bit of reg_addr is to control pin offset's GPDR feature
+*/
+
+enum GPIO_REG {
+       GPLR = 0,       /* pin level read-only */
+       GPDR,           /* pin direction */
+       GPSR,           /* pin set */
+       GPCR,           /* pin clear */
+       GRER,           /* rising edge detect */
+       GFER,           /* falling edge detect */
+       GEDR,           /* edge detect result */
 };
 
 struct lnw_gpio {
        struct gpio_chip                chip;
-       struct lnw_gpio_register        *reg_base;
+       void                            *reg_base;
        spinlock_t                      lock;
        unsigned                        irq_base;
 };
 
-static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
+static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
+                       enum GPIO_REG reg_type)
 {
        struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
+       unsigned nreg = chip->ngpio / 32;
        u8 reg = offset / 32;
-       void __iomem *gplr;
+       void __iomem *ptr;
+
+       ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
+       return ptr;
+}
+
+static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       void __iomem *gplr = gpio_reg(chip, offset, GPLR);
 
-       gplr = (void __iomem *)(&lnw->reg_base->GPLR[reg]);
        return readl(gplr) & BIT(offset % 32);
 }
 
 static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-       struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
-       u8 reg = offset / 32;
        void __iomem *gpsr, *gpcr;
 
        if (value) {
-               gpsr = (void __iomem *)(&lnw->reg_base->GPSR[reg]);
+               gpsr = gpio_reg(chip, offset, GPSR);
                writel(BIT(offset % 32), gpsr);
        } else {
-               gpcr = (void __iomem *)(&lnw->reg_base->GPCR[reg]);
+               gpcr = gpio_reg(chip, offset, GPCR);
                writel(BIT(offset % 32), gpcr);
        }
 }
@@ -76,12 +98,10 @@ static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
-       u8 reg = offset / 32;
+       void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
        u32 value;
        unsigned long flags;
-       void __iomem *gpdr;
 
-       gpdr = (void __iomem *)(&lnw->reg_base->GPDR[reg]);
        spin_lock_irqsave(&lnw->lock, flags);
        value = readl(gpdr);
        value &= ~BIT(offset % 32);
@@ -94,12 +114,10 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip,
                        unsigned offset, int value)
 {
        struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
-       u8 reg = offset / 32;
+       void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
        unsigned long flags;
-       void __iomem *gpdr;
 
        lnw_gpio_set(chip, offset, value);
-       gpdr = (void __iomem *)(&lnw->reg_base->GPDR[reg]);
        spin_lock_irqsave(&lnw->lock, flags);
        value = readl(gpdr);
        value |= BIT(offset % 32);;
@@ -118,11 +136,10 @@ static int lnw_irq_type(unsigned irq, unsigned type)
 {
        struct lnw_gpio *lnw = get_irq_chip_data(irq);
        u32 gpio = irq - lnw->irq_base;
-       u8 reg = gpio / 32;
        unsigned long flags;
        u32 value;
-       void __iomem *grer = (void __iomem *)(&lnw->reg_base->GRER[reg]);
-       void __iomem *gfer = (void __iomem *)(&lnw->reg_base->GFER[reg]);
+       void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER);
+       void __iomem *gfer = gpio_reg(&lnw->chip, gpio, GFER);
 
        if (gpio >= lnw->chip.ngpio)
                return -EINVAL;
@@ -158,8 +175,10 @@ static struct irq_chip lnw_irqchip = {
        .set_type       = lnw_irq_type,
 };
 
-static struct pci_device_id lnw_gpio_ids[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f) },
+static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = {   /* pin number */
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
@@ -167,17 +186,17 @@ MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
 static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
 {
        struct lnw_gpio *lnw = (struct lnw_gpio *)get_irq_data(irq);
-       u32 reg, gpio;
+       u32 base, gpio;
        void __iomem *gedr;
        u32 gedr_v;
 
        /* check GPIO controller to check which pin triggered the interrupt */
-       for (reg = 0; reg < lnw->chip.ngpio / 32; reg++) {
-               gedr = (void __iomem *)(&lnw->reg_base->GEDR[reg]);
+       for (base = 0; base < lnw->chip.ngpio; base += 32) {
+               gedr = gpio_reg(&lnw->chip, base, GEDR);
                gedr_v = readl(gedr);
                if (!gedr_v)
                        continue;
-               for (gpio = reg*32; gpio < reg*32+32; gpio++)
+               for (gpio = base; gpio < base + 32; gpio++)
                        if (gedr_v & BIT(gpio % 32)) {
                                pr_debug("pin %d triggered\n", gpio);
                                generic_handle_irq(lnw->irq_base + gpio);
@@ -245,7 +264,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
        lnw->chip.set = lnw_gpio_set;
        lnw->chip.to_irq = lnw_gpio_to_irq;
        lnw->chip.base = gpio_base;
-       lnw->chip.ngpio = 64;
+       lnw->chip.ngpio = id->driver_data;
        lnw->chip.can_sleep = 0;
        pci_set_drvdata(pdev, lnw);
        retval = gpiochip_add(&lnw->chip);
index f7868243af899a46e69f3cb52064bb06d85bab86..9cad60f9e9620f249bf1c01f38346455476405bb 100644 (file)
@@ -17,7 +17,8 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/gpio.h>
-
+#include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/i2c.h>
 #include <linux/i2c/max732x.h>
 
@@ -31,7 +32,8 @@
  *   - Open Drain I/O
  *
  * designated by 'O', 'I' and 'P' individually according to MAXIM's
- * datasheets.
+ * datasheets. 'I' and 'P' ports are interrupt capables, some with
+ * a dedicated interrupt mask.
  *
  * There are two groups of I/O ports, each group usually includes
  * up to 8 I/O ports, and is accessed by a specific I2C address:
@@ -44,7 +46,8 @@
  *
  * Within each group of ports, there are five known combinations of
  * I/O ports: 4I4O, 4P4O, 8I, 8P, 8O, see the definitions below for
- * the detailed organization of these ports.
+ * the detailed organization of these ports. Only Goup A is interrupt
+ * capable.
  *
  * GPIO numbers start from 'gpio_base + 0' to 'gpio_base + 8/16',
  * and GPIOs from GROUP_A are numbered before those from GROUP_B
 #define GROUP_A(x)     ((x) & 0xffff)  /* I2C Addr: 0b'110xxxx */
 #define GROUP_B(x)     ((x) << 16)     /* I2C Addr: 0b'101xxxx */
 
+#define INT_NONE       0x0     /* No interrupt capability */
+#define INT_NO_MASK    0x1     /* Has interrupts, no mask */
+#define INT_INDEP_MASK 0x2     /* Has interrupts, independent mask */
+#define INT_MERGED_MASK 0x3    /* Has interrupts, merged mask */
+
+#define INT_CAPS(x)    (((uint64_t)(x)) << 32)
+
+enum {
+       MAX7319,
+       MAX7320,
+       MAX7321,
+       MAX7322,
+       MAX7323,
+       MAX7324,
+       MAX7325,
+       MAX7326,
+       MAX7327,
+};
+
+static uint64_t max732x_features[] = {
+       [MAX7319] = GROUP_A(IO_8I) | INT_CAPS(INT_MERGED_MASK),
+       [MAX7320] = GROUP_B(IO_8O),
+       [MAX7321] = GROUP_A(IO_8P) | INT_CAPS(INT_NO_MASK),
+       [MAX7322] = GROUP_A(IO_4I4O) | INT_CAPS(INT_MERGED_MASK),
+       [MAX7323] = GROUP_A(IO_4P4O) | INT_CAPS(INT_INDEP_MASK),
+       [MAX7324] = GROUP_A(IO_8I) | GROUP_B(IO_8O) | INT_CAPS(INT_MERGED_MASK),
+       [MAX7325] = GROUP_A(IO_8P) | GROUP_B(IO_8O) | INT_CAPS(INT_NO_MASK),
+       [MAX7326] = GROUP_A(IO_4I4O) | GROUP_B(IO_8O) | INT_CAPS(INT_MERGED_MASK),
+       [MAX7327] = GROUP_A(IO_4P4O) | GROUP_B(IO_8O) | INT_CAPS(INT_NO_MASK),
+};
+
 static const struct i2c_device_id max732x_id[] = {
-       { "max7319", GROUP_A(IO_8I) },
-       { "max7320", GROUP_B(IO_8O) },
-       { "max7321", GROUP_A(IO_8P) },
-       { "max7322", GROUP_A(IO_4I4O) },
-       { "max7323", GROUP_A(IO_4P4O) },
-       { "max7324", GROUP_A(IO_8I) | GROUP_B(IO_8O) },
-       { "max7325", GROUP_A(IO_8P) | GROUP_B(IO_8O) },
-       { "max7326", GROUP_A(IO_4I4O) | GROUP_B(IO_8O) },
-       { "max7327", GROUP_A(IO_4P4O) | GROUP_B(IO_8O) },
+       { "max7319", MAX7319 },
+       { "max7320", MAX7320 },
+       { "max7321", MAX7321 },
+       { "max7322", MAX7322 },
+       { "max7323", MAX7323 },
+       { "max7324", MAX7324 },
+       { "max7325", MAX7325 },
+       { "max7326", MAX7326 },
+       { "max7327", MAX7327 },
        { },
 };
 MODULE_DEVICE_TABLE(i2c, max732x_id);
@@ -96,9 +130,19 @@ struct max732x_chip {
 
        struct mutex    lock;
        uint8_t         reg_out[2];
+
+#ifdef CONFIG_GPIO_MAX732X_IRQ
+       struct mutex    irq_lock;
+       int             irq_base;
+       uint8_t         irq_mask;
+       uint8_t         irq_mask_cur;
+       uint8_t         irq_trig_raise;
+       uint8_t         irq_trig_fall;
+       uint8_t         irq_features;
+#endif
 };
 
-static int max732x_write(struct max732x_chip *chip, int group_a, uint8_t val)
+static int max732x_writeb(struct max732x_chip *chip, int group_a, uint8_t val)
 {
        struct i2c_client *client;
        int ret;
@@ -113,7 +157,7 @@ static int max732x_write(struct max732x_chip *chip, int group_a, uint8_t val)
        return 0;
 }
 
-static int max732x_read(struct max732x_chip *chip, int group_a, uint8_t *val)
+static int max732x_readb(struct max732x_chip *chip, int group_a, uint8_t *val)
 {
        struct i2c_client *client;
        int ret;
@@ -142,7 +186,7 @@ static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 
        chip = container_of(gc, struct max732x_chip, gpio_chip);
 
-       ret = max732x_read(chip, is_group_a(chip, off), &reg_val);
+       ret = max732x_readb(chip, is_group_a(chip, off), &reg_val);
        if (ret < 0)
                return 0;
 
@@ -162,7 +206,7 @@ static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
        reg_out = (off > 7) ? chip->reg_out[1] : chip->reg_out[0];
        reg_out = (val) ? reg_out | mask : reg_out & ~mask;
 
-       ret = max732x_write(chip, is_group_a(chip, off), reg_out);
+       ret = max732x_writeb(chip, is_group_a(chip, off), reg_out);
        if (ret < 0)
                goto out;
 
@@ -188,6 +232,13 @@ static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
                return -EACCES;
        }
 
+       /*
+        * Open-drain pins must be set to high impedance (which is
+        * equivalent to output-high) to be turned into an input.
+        */
+       if ((mask & chip->dir_output))
+               max732x_gpio_set_value(gc, off, 1);
+
        return 0;
 }
 
@@ -209,12 +260,278 @@ static int max732x_gpio_direction_output(struct gpio_chip *gc,
        return 0;
 }
 
+#ifdef CONFIG_GPIO_MAX732X_IRQ
+static int max732x_writew(struct max732x_chip *chip, uint16_t val)
+{
+       int ret;
+
+       val = cpu_to_le16(val);
+
+       ret = i2c_master_send(chip->client_group_a, (char *)&val, 2);
+       if (ret < 0) {
+               dev_err(&chip->client_group_a->dev, "failed writing\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int max732x_readw(struct max732x_chip *chip, uint16_t *val)
+{
+       int ret;
+
+       ret = i2c_master_recv(chip->client_group_a, (char *)val, 2);
+       if (ret < 0) {
+               dev_err(&chip->client_group_a->dev, "failed reading\n");
+               return ret;
+       }
+
+       *val = le16_to_cpu(*val);
+       return 0;
+}
+
+static void max732x_irq_update_mask(struct max732x_chip *chip)
+{
+       uint16_t msg;
+
+       if (chip->irq_mask == chip->irq_mask_cur)
+               return;
+
+       chip->irq_mask = chip->irq_mask_cur;
+
+       if (chip->irq_features == INT_NO_MASK)
+               return;
+
+       mutex_lock(&chip->lock);
+
+       switch (chip->irq_features) {
+       case INT_INDEP_MASK:
+               msg = (chip->irq_mask << 8) | chip->reg_out[0];
+               max732x_writew(chip, msg);
+               break;
+
+       case INT_MERGED_MASK:
+               msg = chip->irq_mask | chip->reg_out[0];
+               max732x_writeb(chip, 1, (uint8_t)msg);
+               break;
+       }
+
+       mutex_unlock(&chip->lock);
+}
+
+static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
+{
+       struct max732x_chip *chip;
+
+       chip = container_of(gc, struct max732x_chip, gpio_chip);
+       return chip->irq_base + off;
+}
+
+static void max732x_irq_mask(unsigned int irq)
+{
+       struct max732x_chip *chip = get_irq_chip_data(irq);
+
+       chip->irq_mask_cur &= ~(1 << (irq - chip->irq_base));
+}
+
+static void max732x_irq_unmask(unsigned int irq)
+{
+       struct max732x_chip *chip = get_irq_chip_data(irq);
+
+       chip->irq_mask_cur |= 1 << (irq - chip->irq_base);
+}
+
+static void max732x_irq_bus_lock(unsigned int irq)
+{
+       struct max732x_chip *chip = get_irq_chip_data(irq);
+
+       mutex_lock(&chip->irq_lock);
+       chip->irq_mask_cur = chip->irq_mask;
+}
+
+static void max732x_irq_bus_sync_unlock(unsigned int irq)
+{
+       struct max732x_chip *chip = get_irq_chip_data(irq);
+
+       max732x_irq_update_mask(chip);
+       mutex_unlock(&chip->irq_lock);
+}
+
+static int max732x_irq_set_type(unsigned int irq, unsigned int type)
+{
+       struct max732x_chip *chip = get_irq_chip_data(irq);
+       uint16_t off = irq - chip->irq_base;
+       uint16_t mask = 1 << off;
+
+       if (!(mask & chip->dir_input)) {
+               dev_dbg(&chip->client->dev, "%s port %d is output only\n",
+                       chip->client->name, off);
+               return -EACCES;
+       }
+
+       if (!(type & IRQ_TYPE_EDGE_BOTH)) {
+               dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
+                       irq, type);
+               return -EINVAL;
+       }
+
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               chip->irq_trig_fall |= mask;
+       else
+               chip->irq_trig_fall &= ~mask;
+
+       if (type & IRQ_TYPE_EDGE_RISING)
+               chip->irq_trig_raise |= mask;
+       else
+               chip->irq_trig_raise &= ~mask;
+
+       return max732x_gpio_direction_input(&chip->gpio_chip, off);
+}
+
+static struct irq_chip max732x_irq_chip = {
+       .name                   = "max732x",
+       .mask                   = max732x_irq_mask,
+       .unmask                 = max732x_irq_unmask,
+       .bus_lock               = max732x_irq_bus_lock,
+       .bus_sync_unlock        = max732x_irq_bus_sync_unlock,
+       .set_type               = max732x_irq_set_type,
+};
+
+static uint8_t max732x_irq_pending(struct max732x_chip *chip)
+{
+       uint8_t cur_stat;
+       uint8_t old_stat;
+       uint8_t trigger;
+       uint8_t pending;
+       uint16_t status;
+       int ret;
+
+       ret = max732x_readw(chip, &status);
+       if (ret)
+               return 0;
+
+       trigger = status >> 8;
+       trigger &= chip->irq_mask;
+
+       if (!trigger)
+               return 0;
+
+       cur_stat = status & 0xFF;
+       cur_stat &= chip->irq_mask;
+
+       old_stat = cur_stat ^ trigger;
+
+       pending = (old_stat & chip->irq_trig_fall) |
+                 (cur_stat & chip->irq_trig_raise);
+       pending &= trigger;
+
+       return pending;
+}
+
+static irqreturn_t max732x_irq_handler(int irq, void *devid)
+{
+       struct max732x_chip *chip = devid;
+       uint8_t pending;
+       uint8_t level;
+
+       pending = max732x_irq_pending(chip);
+
+       if (!pending)
+               return IRQ_HANDLED;
+
+       do {
+               level = __ffs(pending);
+               handle_nested_irq(level + chip->irq_base);
+
+               pending &= ~(1 << level);
+       } while (pending);
+
+       return IRQ_HANDLED;
+}
+
+static int max732x_irq_setup(struct max732x_chip *chip,
+                            const struct i2c_device_id *id)
+{
+       struct i2c_client *client = chip->client;
+       struct max732x_platform_data *pdata = client->dev.platform_data;
+       int has_irq = max732x_features[id->driver_data] >> 32;
+       int ret;
+
+       if (pdata->irq_base && has_irq != INT_NONE) {
+               int lvl;
+
+               chip->irq_base = pdata->irq_base;
+               chip->irq_features = has_irq;
+               mutex_init(&chip->irq_lock);
+
+               for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) {
+                       int irq = lvl + chip->irq_base;
+
+                       if (!(chip->dir_input & (1 << lvl)))
+                               continue;
+
+                       set_irq_chip_data(irq, chip);
+                       set_irq_chip_and_handler(irq, &max732x_irq_chip,
+                                                handle_edge_irq);
+                       set_irq_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+                       set_irq_flags(irq, IRQF_VALID);
+#else
+                       set_irq_noprobe(irq);
+#endif
+               }
+
+               ret = request_threaded_irq(client->irq,
+                                          NULL,
+                                          max732x_irq_handler,
+                                          IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                          dev_name(&client->dev), chip);
+               if (ret) {
+                       dev_err(&client->dev, "failed to request irq %d\n",
+                               client->irq);
+                       goto out_failed;
+               }
+
+               chip->gpio_chip.to_irq = max732x_gpio_to_irq;
+       }
+
+       return 0;
+
+out_failed:
+       chip->irq_base = 0;
+       return ret;
+}
+
+static void max732x_irq_teardown(struct max732x_chip *chip)
+{
+       if (chip->irq_base)
+               free_irq(chip->client->irq, chip);
+}
+#else /* CONFIG_GPIO_MAX732X_IRQ */
+static int max732x_irq_setup(struct max732x_chip *chip,
+                            const struct i2c_device_id *id)
+{
+       struct i2c_client *client = chip->client;
+       struct max732x_platform_data *pdata = client->dev.platform_data;
+       int has_irq = max732x_features[id->driver_data] >> 32;
+
+       if (pdata->irq_base && has_irq != INT_NONE)
+               dev_warn(&client->dev, "interrupt support not compiled in\n");
+
+       return 0;
+}
+
+static void max732x_irq_teardown(struct max732x_chip *chip)
+{
+}
+#endif
+
 static int __devinit max732x_setup_gpio(struct max732x_chip *chip,
                                        const struct i2c_device_id *id,
                                        unsigned gpio_start)
 {
        struct gpio_chip *gc = &chip->gpio_chip;
-       uint32_t id_data = id->driver_data;
+       uint32_t id_data = (uint32_t)max732x_features[id->driver_data];
        int i, port = 0;
 
        for (i = 0; i < 16; i++, id_data >>= 2) {
@@ -285,14 +602,14 @@ static int __devinit max732x_probe(struct i2c_client *client,
        switch (client->addr & 0x70) {
        case 0x60:
                chip->client_group_a = client;
-               if (nr_port > 7) {
+               if (nr_port > 8) {
                        c = i2c_new_dummy(client->adapter, addr_b);
                        chip->client_group_b = chip->client_dummy = c;
                }
                break;
        case 0x50:
                chip->client_group_b = client;
-               if (nr_port > 7) {
+               if (nr_port > 8) {
                        c = i2c_new_dummy(client->adapter, addr_a);
                        chip->client_group_a = chip->client_dummy = c;
                }
@@ -306,9 +623,13 @@ static int __devinit max732x_probe(struct i2c_client *client,
 
        mutex_init(&chip->lock);
 
-       max732x_read(chip, is_group_a(chip, 0), &chip->reg_out[0]);
-       if (nr_port > 7)
-               max732x_read(chip, is_group_a(chip, 8), &chip->reg_out[1]);
+       max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]);
+       if (nr_port > 8)
+               max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]);
+
+       ret = max732x_irq_setup(chip, id);
+       if (ret)
+               goto out_failed;
 
        ret = gpiochip_add(&chip->gpio_chip);
        if (ret)
@@ -325,6 +646,7 @@ static int __devinit max732x_probe(struct i2c_client *client,
        return 0;
 
 out_failed:
+       max732x_irq_teardown(chip);
        kfree(chip);
        return ret;
 }
@@ -352,6 +674,8 @@ static int __devexit max732x_remove(struct i2c_client *client)
                return ret;
        }
 
+       max732x_irq_teardown(chip);
+
        /* unregister any dummy i2c_client */
        if (chip->client_dummy)
                i2c_unregister_device(chip->client_dummy);
index f156ab3bb6ed24921d6d202e7020fe985f64d43d..a2b12aa1f2b93920b55b255efbf60ad037a4c0d0 100644 (file)
@@ -73,7 +73,7 @@ struct pca953x_chip {
        struct i2c_client *client;
        struct pca953x_platform_data *dyn_pdata;
        struct gpio_chip gpio_chip;
-       char **names;
+       const char *const *names;
 };
 
 static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
index 105701a1f05be48e87c9862a80a907437e03863d..ee568c8fcbd01db804dc071be08a1da4b5ee6e87 100644 (file)
@@ -164,7 +164,7 @@ static int pl061_irq_type(unsigned irq, unsigned trigger)
        unsigned long flags;
        u8 gpiois, gpioibe, gpioiev;
 
-       if (offset < 0 || offset > PL061_GPIO_NR)
+       if (offset < 0 || offset >= PL061_GPIO_NR)
                return -EINVAL;
 
        spin_lock_irqsave(&chip->irq_lock, flags);
index f569ae88ab384c60d09929aeebac1983d3fcf100..c1981861bbbdb418ab58f9c9400e6c41a9430216 100644 (file)
@@ -147,7 +147,10 @@ drm_edid_block_valid(u8 *raw_edid)
                csum += raw_edid[i];
        if (csum) {
                DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum);
-               goto bad;
+
+               /* allow CEA to slide through, switches mangle this */
+               if (raw_edid[0] != 0x02)
+                       goto bad;
        }
 
        /* per-block-type checks */
index 7e663a79829f6768dfbd9c517122032faca8bb5a..266b0ff441af37b75ee555360bdcd68ce1cd881f 100644 (file)
@@ -241,7 +241,8 @@ nouveau_connector_detect(struct drm_connector *connector)
        if (nv_encoder && nv_connector->native_mode) {
                unsigned status = connector_status_connected;
 
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI_BUTTON) || \
+       (defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
                if (!nouveau_ignorelid && !acpi_lid_open())
                        status = connector_status_unknown;
 #endif
index 0616c96e4b67834f9de49511d85c93614e0bf9ea..704a25d04ac92c75a20fe4f019a808c91ccd7304 100644 (file)
@@ -253,7 +253,11 @@ nv40_graph_init(struct drm_device *dev)
 
        if (!dev_priv->engine.graph.ctxprog) {
                struct nouveau_grctx ctx = {};
-               uint32_t cp[256];
+               uint32_t *cp;
+
+               cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL);
+               if (!cp)
+                       return -ENOMEM;
 
                ctx.dev = dev;
                ctx.mode = NOUVEAU_GRCTX_PROG;
@@ -265,6 +269,8 @@ nv40_graph_init(struct drm_device *dev)
                nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
                for (i = 0; i < ctx.ctxprog_len; i++)
                        nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
+
+               kfree(cp);
        }
 
        /* No context present currently */
index 03dd6c41dc192f272f6499d3bfea03a4556e7db9..f3f2827017ef39603bae514432f875a51472eec1 100644 (file)
@@ -707,6 +707,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                break;
        case ATOM_DCPLL:
        case ATOM_PPLL_INVALID:
+       default:
                pll = &rdev->clock.dcpll;
                break;
        }
index 66a37fb75839dc11262f291a8488796efb7e373d..669feb689bfcdc6df0f8536493c4defc5bd0e42a 100644 (file)
@@ -576,6 +576,7 @@ typedef int (*radeon_packet3_check_t)(struct radeon_cs_parser *p,
  */
 int radeon_agp_init(struct radeon_device *rdev);
 void radeon_agp_resume(struct radeon_device *rdev);
+void radeon_agp_suspend(struct radeon_device *rdev);
 void radeon_agp_fini(struct radeon_device *rdev);
 
 
index 28e473f1f56fd688c339c169be1a1cbf5f11aaad..f40dfb77f9b12cfa75c90c83ec608714f15ae423 100644 (file)
@@ -270,3 +270,8 @@ void radeon_agp_fini(struct radeon_device *rdev)
        }
 #endif
 }
+
+void radeon_agp_suspend(struct radeon_device *rdev)
+{
+       radeon_agp_fini(rdev);
+}
index 6e733fdc334991ce9828dfe40e482b2e2cb9b85b..24ea683f7cf53ec5bd2a2958a0a86d95a5185624 100644 (file)
@@ -680,10 +680,18 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
        uint8_t dac;
        union atom_supported_devices *supported_devices;
        int i, j, max_device;
-       struct bios_connector bios_connectors[ATOM_MAX_SUPPORTED_DEVICE];
+       struct bios_connector *bios_connectors;
+       size_t bc_size = sizeof(*bios_connectors) * ATOM_MAX_SUPPORTED_DEVICE;
 
-       if (!atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset))
+       bios_connectors = kzalloc(bc_size, GFP_KERNEL);
+       if (!bios_connectors)
+               return false;
+
+       if (!atom_parse_data_header(ctx, index, &size, &frev, &crev,
+                                   &data_offset)) {
+               kfree(bios_connectors);
                return false;
+       }
 
        supported_devices =
            (union atom_supported_devices *)(ctx->bios + data_offset);
@@ -851,6 +859,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
 
        radeon_link_encoder_connector(dev);
 
+       kfree(bios_connectors);
        return true;
 }
 
index a20b612ffe75caf03425db39ddea73b9e7219057..fdc3fdf78acb3b45dc025ae6598942d032b99bf8 100644 (file)
@@ -754,6 +754,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
        /* evict remaining vram memory */
        radeon_bo_evict_vram(rdev);
 
+       radeon_agp_suspend(rdev);
+
        pci_save_state(dev->pdev);
        if (state.event == PM_EVENT_SUSPEND) {
                /* Shut down the device */
index 76ba59b9fea1bd37595c3e3a7cfc30a2c8e8a06c..132278fa624042e84e1f44ff947808c0b7df79ac 100644 (file)
@@ -347,6 +347,14 @@ config HID_QUANTA
        ---help---
        Support for Quanta Optical Touch dual-touch panels.
 
+config HID_ROCCAT
+       tristate "Roccat special event support"
+       depends on USB_HID
+       ---help---
+       Support for Roccat special events.
+       Say Y here if you have a Roccat mouse or keyboard and want OSD or
+       macro execution support.
+
 config HID_ROCCAT_KONE
        tristate "Roccat Kone Mouse support"
        depends on USB_HID
index 22e47eaeea322ffd4e64c329e0e7be6139e9321b..987fa062736708ee99ed5181c5c5d26302231a7f 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_HID_QUANTA)      += hid-quanta.o
 obj-$(CONFIG_HID_PANTHERLORD)  += hid-pl.o
 obj-$(CONFIG_HID_PETALYNX)     += hid-petalynx.o
 obj-$(CONFIG_HID_PICOLCD)      += hid-picolcd.o
+obj-$(CONFIG_HID_ROCCAT)       += hid-roccat.o
 obj-$(CONFIG_HID_ROCCAT_KONE)  += hid-roccat-kone.o
 obj-$(CONFIG_HID_SAMSUNG)      += hid-samsung.o
 obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
index e10e314d38cc8e620e2bc75ee3a3a3899d0e837b..aa0f7dcabcd78bcbee6c019d680d93cf9e400ad0 100644 (file)
@@ -1301,6 +1301,7 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
index 56f314fbd4f9e337027fe9f890171fa026e2ece2..c94026768570b7b03f976882b4bbf7044637943b 100644 (file)
@@ -811,7 +811,7 @@ static const char *relatives[REL_MAX + 1] = {
        [REL_WHEEL] = "Wheel",          [REL_MISC] = "Misc",
 };
 
-static const char *absolutes[ABS_MAX + 1] = {
+static const char *absolutes[ABS_CNT] = {
        [ABS_X] = "X",                  [ABS_Y] = "Y",
        [ABS_Z] = "Z",                  [ABS_RX] = "Rx",
        [ABS_RY] = "Ry",                [ABS_RZ] = "Rz",
index 62416e6baecaf7611e9d536e64ac84e5d98bbad9..3975e039c3ddbedfb4e7246b3b00004ba8c70ddd 100644 (file)
@@ -73,6 +73,7 @@ static int gyration_event(struct hid_device *hdev, struct hid_field *field,
 static const struct hid_device_id gyration_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, gyration_devices);
index 9776896cc4fc2eab0f654ffaa7ec96593c89d8ea..6af77ed0b555b595792af1c355ec2d1992559858 100644 (file)
 #define USB_VENDOR_ID_GYRATION         0x0c16
 #define USB_DEVICE_ID_GYRATION_REMOTE  0x0002
 #define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003
+#define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008
 
 #define USB_VENDOR_ID_HAPP             0x078b
 #define USB_DEVICE_ID_UGCI_DRIVING     0x0010
index 66e694054ba270c90fef0cb7a98a5c1f69c7ec2d..17f2dc04f883d0eb9462444a816d50ebf9b50b41 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include "hid-ids.h"
+#include "hid-roccat.h"
 #include "hid-roccat-kone.h"
 
 static void kone_set_settings_checksum(struct kone_settings *settings)
@@ -263,7 +264,7 @@ static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
        return 0;
 }
 
-static ssize_t kone_sysfs_read_settings(struct kobject *kobj,
+static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        struct device *dev = container_of(kobj, struct device, kobj);
@@ -287,7 +288,7 @@ static ssize_t kone_sysfs_read_settings(struct kobject *kobj,
  * This function keeps values in kone_device up to date and assumes that in
  * case of error the old data is still valid
  */
-static ssize_t kone_sysfs_write_settings(struct kobject *kobj,
+static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        struct device *dev = container_of(kobj, struct device, kobj);
@@ -342,31 +343,31 @@ static ssize_t kone_sysfs_read_profilex(struct kobject *kobj,
        return count;
 }
 
-static ssize_t kone_sysfs_read_profile1(struct kobject *kobj,
+static ssize_t kone_sysfs_read_profile1(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 1);
 }
 
-static ssize_t kone_sysfs_read_profile2(struct kobject *kobj,
+static ssize_t kone_sysfs_read_profile2(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 2);
 }
 
-static ssize_t kone_sysfs_read_profile3(struct kobject *kobj,
+static ssize_t kone_sysfs_read_profile3(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 3);
 }
 
-static ssize_t kone_sysfs_read_profile4(struct kobject *kobj,
+static ssize_t kone_sysfs_read_profile4(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 4);
 }
 
-static ssize_t kone_sysfs_read_profile5(struct kobject *kobj,
+static ssize_t kone_sysfs_read_profile5(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 5);
@@ -404,31 +405,31 @@ static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
        return sizeof(struct kone_profile);
 }
 
-static ssize_t kone_sysfs_write_profile1(struct kobject *kobj,
+static ssize_t kone_sysfs_write_profile1(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 1);
 }
 
-static ssize_t kone_sysfs_write_profile2(struct kobject *kobj,
+static ssize_t kone_sysfs_write_profile2(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 2);
 }
 
-static ssize_t kone_sysfs_write_profile3(struct kobject *kobj,
+static ssize_t kone_sysfs_write_profile3(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 3);
 }
 
-static ssize_t kone_sysfs_write_profile4(struct kobject *kobj,
+static ssize_t kone_sysfs_write_profile4(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 4);
 }
 
-static ssize_t kone_sysfs_write_profile5(struct kobject *kobj,
+static ssize_t kone_sysfs_write_profile5(struct file *fp, struct kobject *kobj,
                struct bin_attribute *attr, char *buf,
                loff_t off, size_t count) {
        return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 5);
@@ -849,6 +850,16 @@ static int kone_init_specials(struct hid_device *hdev)
                                        "couldn't init struct kone_device\n");
                        goto exit_free;
                }
+
+               retval = roccat_connect(hdev);
+               if (retval < 0) {
+                       dev_err(&hdev->dev, "couldn't init char dev\n");
+                       /* be tolerant about not getting chrdev */
+               } else {
+                       kone->roccat_claimed = 1;
+                       kone->chrdev_minor = retval;
+               }
+
                retval = kone_create_sysfs_attributes(intf);
                if (retval) {
                        dev_err(&hdev->dev, "cannot create sysfs files\n");
@@ -868,10 +879,14 @@ exit_free:
 static void kone_remove_specials(struct hid_device *hdev)
 {
        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+       struct kone_device *kone;
 
        if (intf->cur_altsetting->desc.bInterfaceProtocol
                        == USB_INTERFACE_PROTOCOL_MOUSE) {
                kone_remove_sysfs_attributes(intf);
+               kone = hid_get_drvdata(hdev);
+               if (kone->roccat_claimed)
+                       roccat_disconnect(kone->chrdev_minor);
                kfree(hid_get_drvdata(hdev));
        }
 }
@@ -930,6 +945,37 @@ static void kone_keep_values_up_to_date(struct kone_device *kone,
        }
 }
 
+static void kone_report_to_chrdev(struct kone_device const *kone,
+               struct kone_mouse_event const *event)
+{
+       struct kone_roccat_report roccat_report;
+
+       switch (event->event) {
+       case kone_mouse_event_switch_profile:
+       case kone_mouse_event_switch_dpi:
+       case kone_mouse_event_osd_profile:
+       case kone_mouse_event_osd_dpi:
+               roccat_report.event = event->event;
+               roccat_report.value = event->value;
+               roccat_report.key = 0;
+               roccat_report_event(kone->chrdev_minor,
+                               (uint8_t *)&roccat_report,
+                               sizeof(struct kone_roccat_report));
+               break;
+       case kone_mouse_event_call_overlong_macro:
+               if (event->value == kone_keystroke_action_press) {
+                       roccat_report.event = kone_mouse_event_call_overlong_macro;
+                       roccat_report.value = kone->actual_profile;
+                       roccat_report.key = event->macro_key;
+                       roccat_report_event(kone->chrdev_minor,
+                                       (uint8_t *)&roccat_report,
+                                       sizeof(struct kone_roccat_report));
+               }
+               break;
+       }
+
+}
+
 /*
  * Is called for keyboard- and mousepart.
  * Only mousepart gets informations about special events in its extended event
@@ -958,6 +1004,9 @@ static int kone_raw_event(struct hid_device *hdev, struct hid_report *report,
 
        kone_keep_values_up_to_date(kone, event);
 
+       if (kone->roccat_claimed)
+               kone_report_to_chrdev(kone, event);
+
        return 0; /* always do further processing */
 }
 
index b413b10a7f8a853f611119af1e9f465f1f08d893..003e6f81c195d6ed1b1cb0cf2184a774db290481 100644 (file)
@@ -189,6 +189,12 @@ enum kone_commands {
        kone_command_firmware = 0xe5a
 };
 
+struct kone_roccat_report {
+       uint8_t event;
+       uint8_t value; /* holds dpi or profile value */
+       uint8_t key; /* macro key on overlong macro execution */
+};
+
 #pragma pack(pop)
 
 struct kone_device {
@@ -219,6 +225,9 @@ struct kone_device {
         * so it's read only once
         */
        int firmware_version;
+
+       int roccat_claimed;
+       int chrdev_minor;
 };
 
 #endif
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
new file mode 100644 (file)
index 0000000..e05d48e
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Roccat driver for Linux
+ *
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Module roccat is a char device used to report special events of roccat
+ * hardware to userland. These events include requests for on-screen-display of
+ * profile or dpi settings or requests for execution of macro sequences that are
+ * not stored in device. The information in these events depends on hid device
+ * implementation and contains data that is not available in a single hid event
+ * or else hidraw could have been used.
+ * It is inspired by hidraw, but uses only one circular buffer for all readers.
+ */
+
+#include <linux/cdev.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+
+#include "hid-roccat.h"
+
+#define ROCCAT_FIRST_MINOR 0
+#define ROCCAT_MAX_DEVICES 8
+
+/* should be a power of 2 for performance reason */
+#define ROCCAT_CBUF_SIZE 16
+
+struct roccat_report {
+       uint8_t *value;
+       int len;
+};
+
+struct roccat_device {
+       unsigned int minor;
+       int open;
+       int exist;
+       wait_queue_head_t wait;
+       struct device *dev;
+       struct hid_device *hid;
+       struct list_head readers;
+       /* protects modifications of readers list */
+       struct mutex readers_lock;
+
+       /*
+        * circular_buffer has one writer and multiple readers with their own
+        * read pointers
+        */
+       struct roccat_report cbuf[ROCCAT_CBUF_SIZE];
+       int cbuf_end;
+       struct mutex cbuf_lock;
+};
+
+struct roccat_reader {
+       struct list_head node;
+       struct roccat_device *device;
+       int cbuf_start;
+};
+
+static int roccat_major;
+static struct class *roccat_class;
+static struct cdev roccat_cdev;
+
+static struct roccat_device *devices[ROCCAT_MAX_DEVICES];
+/* protects modifications of devices array */
+static DEFINE_MUTEX(devices_lock);
+
+static ssize_t roccat_read(struct file *file, char __user *buffer,
+               size_t count, loff_t *ppos)
+{
+       struct roccat_reader *reader = file->private_data;
+       struct roccat_device *device = reader->device;
+       struct roccat_report *report;
+       ssize_t retval = 0, len;
+       DECLARE_WAITQUEUE(wait, current);
+
+       mutex_lock(&device->cbuf_lock);
+
+       /* no data? */
+       if (reader->cbuf_start == device->cbuf_end) {
+               add_wait_queue(&device->wait, &wait);
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               /* wait for data */
+               while (reader->cbuf_start == device->cbuf_end) {
+                       if (file->f_flags & O_NONBLOCK) {
+                               retval = -EAGAIN;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               retval = -ERESTARTSYS;
+                               break;
+                       }
+                       if (!device->exist) {
+                               retval = -EIO;
+                               break;
+                       }
+
+                       mutex_unlock(&device->cbuf_lock);
+                       schedule();
+                       mutex_lock(&device->cbuf_lock);
+                       set_current_state(TASK_INTERRUPTIBLE);
+               }
+
+               set_current_state(TASK_RUNNING);
+               remove_wait_queue(&device->wait, &wait);
+       }
+
+       /* here we either have data or a reason to return if retval is set */
+       if (retval)
+               goto exit_unlock;
+
+       report = &device->cbuf[reader->cbuf_start];
+       /*
+        * If report is larger than requested amount of data, rest of report
+        * is lost!
+        */
+       len = report->len > count ? count : report->len;
+
+       if (copy_to_user(buffer, report->value, len)) {
+               retval = -EFAULT;
+               goto exit_unlock;
+       }
+       retval += len;
+       reader->cbuf_start = (reader->cbuf_start + 1) % ROCCAT_CBUF_SIZE;
+
+exit_unlock:
+       mutex_unlock(&device->cbuf_lock);
+       return retval;
+}
+
+static unsigned int roccat_poll(struct file *file, poll_table *wait)
+{
+       struct roccat_reader *reader = file->private_data;
+       poll_wait(file, &reader->device->wait, wait);
+       if (reader->cbuf_start != reader->device->cbuf_end)
+               return POLLIN | POLLRDNORM;
+       if (!reader->device->exist)
+               return POLLERR | POLLHUP;
+       return 0;
+}
+
+static int roccat_open(struct inode *inode, struct file *file)
+{
+       unsigned int minor = iminor(inode);
+       struct roccat_reader *reader;
+       struct roccat_device *device;
+       int error = 0;
+
+       reader = kzalloc(sizeof(struct roccat_reader), GFP_KERNEL);
+       if (!reader)
+               return -ENOMEM;
+
+       mutex_lock(&devices_lock);
+
+       device = devices[minor];
+
+       mutex_lock(&device->readers_lock);
+
+       if (!device) {
+               printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
+                               minor);
+               error = -ENODEV;
+               goto exit_unlock;
+       }
+
+       if (!device->open++) {
+               /* power on device on adding first reader */
+               if (device->hid->ll_driver->power) {
+                       error = device->hid->ll_driver->power(device->hid,
+                                       PM_HINT_FULLON);
+                       if (error < 0) {
+                               --device->open;
+                               goto exit_unlock;
+                       }
+               }
+               error = device->hid->ll_driver->open(device->hid);
+               if (error < 0) {
+                       if (device->hid->ll_driver->power)
+                               device->hid->ll_driver->power(device->hid,
+                                               PM_HINT_NORMAL);
+                       --device->open;
+                       goto exit_unlock;
+               }
+       }
+
+       reader->device = device;
+       /* new reader doesn't get old events */
+       reader->cbuf_start = device->cbuf_end;
+
+       list_add_tail(&reader->node, &device->readers);
+       file->private_data = reader;
+
+exit_unlock:
+       mutex_unlock(&device->readers_lock);
+       mutex_unlock(&devices_lock);
+       return error;
+}
+
+static int roccat_release(struct inode *inode, struct file *file)
+{
+       unsigned int minor = iminor(inode);
+       struct roccat_reader *reader = file->private_data;
+       struct roccat_device *device;
+
+       mutex_lock(&devices_lock);
+
+       device = devices[minor];
+       if (!device) {
+               mutex_unlock(&devices_lock);
+               printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
+                               minor);
+               return -ENODEV;
+       }
+
+       mutex_lock(&device->readers_lock);
+       list_del(&reader->node);
+       mutex_unlock(&device->readers_lock);
+       kfree(reader);
+
+       if (!--device->open) {
+               /* removing last reader */
+               if (device->exist) {
+                       if (device->hid->ll_driver->power)
+                               device->hid->ll_driver->power(device->hid,
+                                               PM_HINT_NORMAL);
+                       device->hid->ll_driver->close(device->hid);
+               } else {
+                       kfree(device);
+               }
+       }
+
+       mutex_unlock(&devices_lock);
+
+       return 0;
+}
+
+/*
+ * roccat_report_event() - output data to readers
+ * @minor: minor device number returned by roccat_connect()
+ * @data: pointer to data
+ * @len: size of data
+ *
+ * Return value is zero on success, a negative error code on failure.
+ *
+ * This is called from interrupt handler.
+ */
+int roccat_report_event(int minor, u8 const *data, int len)
+{
+       struct roccat_device *device;
+       struct roccat_reader *reader;
+       struct roccat_report *report;
+       uint8_t *new_value;
+
+       new_value = kmemdup(data, len, GFP_ATOMIC);
+       if (!new_value)
+               return -ENOMEM;
+
+       device = devices[minor];
+
+       report = &device->cbuf[device->cbuf_end];
+
+       /* passing NULL is safe */
+       kfree(report->value);
+
+       report->value = new_value;
+       report->len = len;
+       device->cbuf_end = (device->cbuf_end + 1) % ROCCAT_CBUF_SIZE;
+
+       list_for_each_entry(reader, &device->readers, node) {
+               /*
+                * As we already inserted one element, the buffer can't be
+                * empty. If start and end are equal, buffer is full and we
+                * increase start, so that slow reader misses one event, but
+                * gets the newer ones in the right order.
+                */
+               if (reader->cbuf_start == device->cbuf_end)
+                       reader->cbuf_start = (reader->cbuf_start + 1) % ROCCAT_CBUF_SIZE;
+       }
+
+       wake_up_interruptible(&device->wait);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(roccat_report_event);
+
+/*
+ * roccat_connect() - create a char device for special event output
+ * @hid: the hid device the char device should be connected to.
+ *
+ * Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
+ * success, a negative error code on failure.
+ */
+int roccat_connect(struct hid_device *hid)
+{
+       unsigned int minor;
+       struct roccat_device *device;
+       int temp;
+
+       device = kzalloc(sizeof(struct roccat_device), GFP_KERNEL);
+       if (!device)
+               return -ENOMEM;
+
+       mutex_lock(&devices_lock);
+
+       for (minor = 0; minor < ROCCAT_MAX_DEVICES; ++minor) {
+               if (devices[minor])
+                       continue;
+               break;
+       }
+
+       if (minor < ROCCAT_MAX_DEVICES) {
+               devices[minor] = device;
+       } else {
+               mutex_unlock(&devices_lock);
+               kfree(device);
+               return -EINVAL;
+       }
+
+       device->dev = device_create(roccat_class, &hid->dev,
+                       MKDEV(roccat_major, minor), NULL,
+                       "%s%s%d", "roccat", hid->driver->name, minor);
+
+       if (IS_ERR(device->dev)) {
+               devices[minor] = NULL;
+               mutex_unlock(&devices_lock);
+               temp = PTR_ERR(device->dev);
+               kfree(device);
+               return temp;
+       }
+
+       mutex_unlock(&devices_lock);
+
+       init_waitqueue_head(&device->wait);
+       INIT_LIST_HEAD(&device->readers);
+       mutex_init(&device->readers_lock);
+       mutex_init(&device->cbuf_lock);
+       device->minor = minor;
+       device->hid = hid;
+       device->exist = 1;
+       device->cbuf_end = 0;
+
+       return minor;
+}
+EXPORT_SYMBOL_GPL(roccat_connect);
+
+/* roccat_disconnect() - remove char device from hid device
+ * @minor: the minor device number returned by roccat_connect()
+ */
+void roccat_disconnect(int minor)
+{
+       struct roccat_device *device;
+
+       mutex_lock(&devices_lock);
+       device = devices[minor];
+       devices[minor] = NULL;
+       mutex_unlock(&devices_lock);
+
+       device->exist = 0; /* TODO exist maybe not needed */
+
+       device_destroy(roccat_class, MKDEV(roccat_major, minor));
+
+       if (device->open) {
+               device->hid->ll_driver->close(device->hid);
+               wake_up_interruptible(&device->wait);
+       } else {
+               kfree(device);
+       }
+}
+EXPORT_SYMBOL_GPL(roccat_disconnect);
+
+static const struct file_operations roccat_ops = {
+       .owner = THIS_MODULE,
+       .read = roccat_read,
+       .poll = roccat_poll,
+       .open = roccat_open,
+       .release = roccat_release,
+};
+
+static int __init roccat_init(void)
+{
+       int retval;
+       dev_t dev_id;
+
+       retval = alloc_chrdev_region(&dev_id, ROCCAT_FIRST_MINOR,
+                       ROCCAT_MAX_DEVICES, "roccat");
+
+       roccat_major = MAJOR(dev_id);
+
+       if (retval < 0) {
+               printk(KERN_WARNING "roccat: can't get major number\n");
+               return retval;
+       }
+
+       roccat_class = class_create(THIS_MODULE, "roccat");
+       if (IS_ERR(roccat_class)) {
+               retval = PTR_ERR(roccat_class);
+               unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
+               return retval;
+       }
+
+       cdev_init(&roccat_cdev, &roccat_ops);
+       cdev_add(&roccat_cdev, dev_id, ROCCAT_MAX_DEVICES);
+
+       return 0;
+}
+
+static void __exit roccat_exit(void)
+{
+       dev_t dev_id = MKDEV(roccat_major, 0);
+
+       cdev_del(&roccat_cdev);
+       class_destroy(roccat_class);
+       unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
+}
+
+module_init(roccat_init);
+module_exit(roccat_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat char device");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat.h b/drivers/hid/hid-roccat.h
new file mode 100644 (file)
index 0000000..d8aae0c
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __HID_ROCCAT_H
+#define __HID_ROCCAT_H
+
+/*
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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/hid.h>
+#include <linux/types.h>
+
+#if defined(CONFIG_HID_ROCCAT) || defined (CONFIG_HID_ROCCAT_MODULE)
+int roccat_connect(struct hid_device *hid);
+void roccat_disconnect(int minor);
+int roccat_report_event(int minor, u8 const *data, int len);
+#else
+static inline int roccat_connect(struct hid_device *hid) { return -1; }
+static inline void roccat_disconnect(int minor) {}
+static inline int roccat_report_event(int minor, u8 const *data, int len)
+{
+       return 0;
+}
+#endif
+
+#endif
index b9e517de6a82c778f1ded3a2d63e5c78a727adb2..3feaa26410be9b26eb30d4d52768324d3cff0294 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/zorro.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 
 #include <asm/setup.h>
 #include <asm/amigahw.h>
 #include <asm/amigayle.h>
 
 
-    /*
-     *  Bases of the IDE interfaces
-     */
-
-#define GAYLE_BASE_4000        0xdd2020        /* A4000/A4000T */
-#define GAYLE_BASE_1200        0xda0000        /* A1200/A600 and E-Matrix 530 */
-
-#define GAYLE_IDEREG_SIZE      0x2000
-
     /*
      *  Offsets from one of the above bases
      */
@@ -68,20 +60,20 @@ MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
 
 static int gayle_test_irq(ide_hwif_t *hwif)
 {
-    unsigned char ch;
+       unsigned char ch;
 
-    ch = z_readb(hwif->io_ports.irq_addr);
-    if (!(ch & GAYLE_IRQ_IDE))
-       return 0;
-    return 1;
+       ch = z_readb(hwif->io_ports.irq_addr);
+       if (!(ch & GAYLE_IRQ_IDE))
+               return 0;
+       return 1;
 }
 
 static void gayle_a1200_clear_irq(ide_drive_t *drive)
 {
-    ide_hwif_t *hwif = drive->hwif;
+       ide_hwif_t *hwif = drive->hwif;
 
-    (void)z_readb(hwif->io_ports.status_addr);
-    z_writeb(0x7c, hwif->io_ports.irq_addr);
+       (void)z_readb(hwif->io_ports.status_addr);
+       z_writeb(0x7c, hwif->io_ports.irq_addr);
 }
 
 static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base,
@@ -122,64 +114,89 @@ static const struct ide_port_info gayle_port_info = {
      *  Probe for a Gayle IDE interface (and optionally for an IDE doubler)
      */
 
-static int __init gayle_init(void)
+static int __init amiga_gayle_ide_probe(struct platform_device *pdev)
 {
-    unsigned long phys_base, res_start, res_n;
-    unsigned long base, ctrlport, irqport;
-    int a4000, i, rc;
-    struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS];
-    struct ide_port_info d = gayle_port_info;
-
-    if (!MACH_IS_AMIGA)
-       return -ENODEV;
-
-    if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE))
-       goto found;
-
-#ifdef CONFIG_ZORRO
-    if (zorro_find_device(ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE,
-                         NULL))
-       goto found;
-#endif
-    return -ENODEV;
-
-found:
-       printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n",
-                        a4000 ? 4000 : 1200,
-                        ide_doubler ? ", IDE doubler" : "");
-
-       if (a4000) {
-           phys_base = GAYLE_BASE_4000;
-           irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_4000);
-           d.port_ops = &gayle_a4000_port_ops;
-       } else {
-           phys_base = GAYLE_BASE_1200;
-           irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_1200);
-           d.port_ops = &gayle_a1200_port_ops;
+       struct resource *res;
+       struct gayle_ide_platform_data *pdata;
+       unsigned long base, ctrlport, irqport;
+       unsigned int i;
+       int error;
+       struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS];
+       struct ide_port_info d = gayle_port_info;
+       struct ide_host *host;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       if (!request_mem_region(res->start, resource_size(res), "IDE"))
+               return -EBUSY;
+
+       pdata = pdev->dev.platform_data;
+       pr_info("ide: Gayle IDE controller (A%u style%s)\n",
+               pdata->explicit_ack ? 1200 : 4000,
+               ide_doubler ? ", IDE doubler" : "");
+
+       base = (unsigned long)ZTWO_VADDR(pdata->base);
+       ctrlport = 0;
+       irqport = (unsigned long)ZTWO_VADDR(pdata->irqport);
+       if (pdata->explicit_ack)
+               d.port_ops = &gayle_a1200_port_ops;
+       else
+               d.port_ops = &gayle_a4000_port_ops;
+
+       for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++, base += GAYLE_NEXT_PORT) {
+               if (GAYLE_HAS_CONTROL_REG)
+                       ctrlport = base + GAYLE_CONTROL;
+
+               gayle_setup_ports(&hw[i], base, ctrlport, irqport);
+               hws[i] = &hw[i];
        }
 
-       res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1);
-       res_n = GAYLE_IDEREG_SIZE;
+       error = ide_host_add(&d, hws, i, &host);
+       if (error)
+               goto out;
 
-       if (!request_mem_region(res_start, res_n, "IDE"))
-               return -EBUSY;
+       platform_set_drvdata(pdev, host);
+       return 0;
 
-    for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) {
-       base = (unsigned long)ZTWO_VADDR(phys_base + i * GAYLE_NEXT_PORT);
-       ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0;
+out:
+       release_mem_region(res->start, resource_size(res));
+       return error;
+}
+
+static int __exit amiga_gayle_ide_remove(struct platform_device *pdev)
+{
+       struct ide_host *host = platform_get_drvdata(pdev);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       ide_host_remove(host);
+       release_mem_region(res->start, resource_size(res));
+       return 0;
+}
 
-       gayle_setup_ports(&hw[i], base, ctrlport, irqport);
+static struct platform_driver amiga_gayle_ide_driver = {
+       .remove = __exit_p(amiga_gayle_ide_remove),
+       .driver   = {
+               .name   = "amiga-gayle-ide",
+               .owner  = THIS_MODULE,
+       },
+};
 
-       hws[i] = &hw[i];
-    }
+static int __init amiga_gayle_ide_init(void)
+{
+       return platform_driver_probe(&amiga_gayle_ide_driver,
+                                    amiga_gayle_ide_probe);
+}
 
-    rc = ide_host_add(&d, hws, i, NULL);
-    if (rc)
-       release_mem_region(res_start, res_n);
+module_init(amiga_gayle_ide_init);
 
-    return rc;
+static void __exit amiga_gayle_ide_exit(void)
+{
+       platform_driver_unregister(&amiga_gayle_ide_driver);
 }
 
-module_init(gayle_init);
+module_exit(amiga_gayle_ide_exit);
 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:amiga-gayle-ide");
index 9fd4a0d3206e9ee552d661df3be939f84122570d..adaefabc40e961257aa2ac1b24f34318316a2799 100644 (file)
@@ -1824,7 +1824,7 @@ static int dv1394_open(struct inode *inode, struct file *file)
               "and will not be available in the new firewire driver stack. "
               "Try libraw1394 based programs instead.\n", current->comm);
 
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 
@@ -2153,17 +2153,18 @@ static struct cdev dv1394_cdev;
 static const struct file_operations dv1394_fops=
 {
        .owner =        THIS_MODULE,
-       .poll =         dv1394_poll,
+       .poll =         dv1394_poll,
        .unlocked_ioctl = dv1394_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl = dv1394_compat_ioctl,
 #endif
        .mmap =         dv1394_mmap,
        .open =         dv1394_open,
-       .write =        dv1394_write,
-       .read =         dv1394_read,
+       .write =        dv1394_write,
+       .read =         dv1394_read,
        .release =      dv1394_release,
-       .fasync =       dv1394_fasync,
+       .fasync =       dv1394_fasync,
+       .llseek =       no_llseek,
 };
 
 
index 8aa56ac07e2920d371a5af41eca7f09c8b752380..b563d5e9fa2e5a7ea163390eb72c4e1a384505c1 100644 (file)
@@ -2834,7 +2834,7 @@ static int raw1394_open(struct inode *inode, struct file *file)
 
        file->private_data = fi;
 
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static int raw1394_release(struct inode *inode, struct file *file)
@@ -3035,6 +3035,7 @@ static const struct file_operations raw1394_fops = {
        .poll = raw1394_poll,
        .open = raw1394_open,
        .release = raw1394_release,
+       .llseek = no_llseek,
 };
 
 static int __init init_raw1394(void)
index 949064a05675cbb766cded13fc2bba78a680ad49..a42bd6893bcf978a0dfddb83e54299c3039ed439 100644 (file)
@@ -1239,7 +1239,7 @@ static int video1394_open(struct inode *inode, struct file *file)
        ctx->current_ctx = NULL;
        file->private_data = ctx;
 
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static int video1394_release(struct inode *inode, struct file *file)
@@ -1287,7 +1287,8 @@ static const struct file_operations video1394_fops=
        .poll =         video1394_poll,
        .mmap =         video1394_mmap,
        .open =         video1394_open,
-       .release =      video1394_release
+       .release =      video1394_release,
+       .llseek =       no_llseek,
 };
 
 /*** HOTPLUG STUFF **********************************************************/
index 07cae552cafba60be9efb413b210d6e1ae767243..e571e60ecb880ca5f899d6b66466d9345f0dc9c4 100644 (file)
@@ -847,7 +847,7 @@ static int __cpuinit comp_pool_callback(struct notifier_block *nfb,
                ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
                if (!create_comp_task(pool, cpu)) {
                        ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
                }
                break;
        case CPU_UP_CANCELED:
index 423e0e6031ab5010e542555b10bc539683efaae6..34157bb97ed6440695dcafb072ca3f8419cb5d0b 100644 (file)
@@ -47,15 +47,15 @@ struct joydev {
        struct mutex mutex;
        struct device dev;
 
-       struct js_corr corr[ABS_MAX + 1];
+       struct js_corr corr[ABS_CNT];
        struct JS_DATA_SAVE_TYPE glue;
        int nabs;
        int nkey;
        __u16 keymap[KEY_MAX - BTN_MISC + 1];
        __u16 keypam[KEY_MAX - BTN_MISC + 1];
-       __u8 absmap[ABS_MAX + 1];
-       __u8 abspam[ABS_MAX + 1];
-       __s16 abs[ABS_MAX + 1];
+       __u8 absmap[ABS_CNT];
+       __u8 abspam[ABS_CNT];
+       __s16 abs[ABS_CNT];
 };
 
 struct joydev_client {
@@ -826,7 +826,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
        joydev->handle.handler = handler;
        joydev->handle.private = joydev;
 
-       for (i = 0; i < ABS_MAX + 1; i++)
+       for (i = 0; i < ABS_CNT; i++)
                if (test_bit(i, dev->absbit)) {
                        joydev->absmap[i] = joydev->nabs;
                        joydev->abspam[joydev->nabs] = i;
index 35149ec455a9fa3770a33ae2e1c61e2d6fb06a02..79172af164f25a5ccd913f32225dcd5e60c22760 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/keyboard.h>
+#include <linux/platform_device.h>
 
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
@@ -154,10 +155,9 @@ static const char *amikbd_messages[8] = {
        [7] = KERN_WARNING "amikbd: keyboard interrupt\n"
 };
 
-static struct input_dev *amikbd_dev;
-
-static irqreturn_t amikbd_interrupt(int irq, void *dummy)
+static irqreturn_t amikbd_interrupt(int irq, void *data)
 {
+       struct input_dev *dev = data;
        unsigned char scancode, down;
 
        scancode = ~ciaa.sdr;           /* get and invert scancode (keyboard is active low) */
@@ -170,47 +170,42 @@ static irqreturn_t amikbd_interrupt(int irq, void *dummy)
 
        if (scancode < 0x78) {          /* scancodes < 0x78 are keys */
                if (scancode == 98) {   /* CapsLock is a toggle switch key on Amiga */
-                       input_report_key(amikbd_dev, scancode, 1);
-                       input_report_key(amikbd_dev, scancode, 0);
+                       input_report_key(dev, scancode, 1);
+                       input_report_key(dev, scancode, 0);
                } else {
-                       input_report_key(amikbd_dev, scancode, down);
+                       input_report_key(dev, scancode, down);
                }
 
-               input_sync(amikbd_dev);
+               input_sync(dev);
        } else                          /* scancodes >= 0x78 are error codes */
                printk(amikbd_messages[scancode - 0x78]);
 
        return IRQ_HANDLED;
 }
 
-static int __init amikbd_init(void)
+static int __init amikbd_probe(struct platform_device *pdev)
 {
+       struct input_dev *dev;
        int i, j, err;
 
-       if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
-               return -ENODEV;
-
-       if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
-               return -EBUSY;
-
-       amikbd_dev = input_allocate_device();
-       if (!amikbd_dev) {
-               printk(KERN_ERR "amikbd: not enough memory for input device\n");
-               err = -ENOMEM;
-               goto fail1;
+       dev = input_allocate_device();
+       if (!dev) {
+               dev_err(&pdev->dev, "Not enough memory for input device\n");
+               return -ENOMEM;
        }
 
-       amikbd_dev->name = "Amiga Keyboard";
-       amikbd_dev->phys = "amikbd/input0";
-       amikbd_dev->id.bustype = BUS_AMIGA;
-       amikbd_dev->id.vendor = 0x0001;
-       amikbd_dev->id.product = 0x0001;
-       amikbd_dev->id.version = 0x0100;
+       dev->name = pdev->name;
+       dev->phys = "amikbd/input0";
+       dev->id.bustype = BUS_AMIGA;
+       dev->id.vendor = 0x0001;
+       dev->id.product = 0x0001;
+       dev->id.version = 0x0100;
+       dev->dev.parent = &pdev->dev;
 
-       amikbd_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+       dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
 
        for (i = 0; i < 0x78; i++)
-               set_bit(i, amikbd_dev->keybit);
+               set_bit(i, dev->keybit);
 
        for (i = 0; i < MAX_NR_KEYMAPS; i++) {
                static u_short temp_map[NR_KEYS] __initdata;
@@ -229,30 +224,54 @@ static int __init amikbd_init(void)
                memcpy(key_maps[i], temp_map, sizeof(temp_map));
        }
        ciaa.cra &= ~0x41;       /* serial data in, turn off TA */
-       if (request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd",
-                       amikbd_interrupt)) {
-               err = -EBUSY;
+       err = request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd",
+                         dev);
+       if (err)
                goto fail2;
-       }
 
-       err = input_register_device(amikbd_dev);
+       err = input_register_device(dev);
        if (err)
                goto fail3;
 
+       platform_set_drvdata(pdev, dev);
+
        return 0;
 
- fail3:        free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt);
- fail2:        input_free_device(amikbd_dev);
- fail1:        release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100);
+ fail3:        free_irq(IRQ_AMIGA_CIAA_SP, dev);
+ fail2:        input_free_device(dev);
        return err;
 }
 
-static void __exit amikbd_exit(void)
+static int __exit amikbd_remove(struct platform_device *pdev)
+{
+       struct input_dev *dev = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       free_irq(IRQ_AMIGA_CIAA_SP, dev);
+       input_unregister_device(dev);
+       return 0;
+}
+
+static struct platform_driver amikbd_driver = {
+       .remove = __exit_p(amikbd_remove),
+       .driver   = {
+               .name   = "amiga-keyboard",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init amikbd_init(void)
 {
-       free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt);
-       input_unregister_device(amikbd_dev);
-       release_mem_region(CIAA_PHYSADDR - 1 + 0xb00, 0x100);
+       return platform_driver_probe(&amikbd_driver, amikbd_probe);
 }
 
 module_init(amikbd_init);
+
+static void __exit amikbd_exit(void)
+{
+       platform_driver_unregister(&amikbd_driver);
+}
+
 module_exit(amikbd_exit);
+
+MODULE_ALIAS("platform:amiga-keyboard");
index 48cdabec372a0b8e6344749deebef3bb7876db44..c44b9eafc556e48c114780e0dc7ed6af1e144cda 100644 (file)
@@ -80,6 +80,16 @@ config INPUT_M68K_BEEP
        tristate "M68k Beeper support"
        depends on M68K
 
+config INPUT_MAX8925_ONKEY
+       tristate "MAX8925 ONKEY support"
+       depends on MFD_MAX8925
+       help
+         Support the ONKEY of MAX8925 PMICs as an input device
+         reporting power button status.
+
+         To compile this driver as a module, choose M here: the module
+         will be called max8925_onkey.
+
 config INPUT_APANEL
        tristate "Fujitsu Lifebook Application Panel buttons"
        depends on X86 && I2C && LEDS_CLASS
index f9f577031e0688d93554f0796ebc83ddc280ff51..71fe57d8023ff834284afc91ad57fcd08c97606e 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_HP_SDC_RTC)              += hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_IXP4XX_BEEPER)      += ixp4xx-beeper.o
 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)     += keyspan_remote.o
 obj-$(CONFIG_INPUT_M68K_BEEP)          += m68kspkr.o
+obj-$(CONFIG_INPUT_MAX8925_ONKEY)      += max8925_onkey.o
 obj-$(CONFIG_INPUT_PCAP)               += pcap_keys.o
 obj-$(CONFIG_INPUT_PCF50633_PMU)       += pcf50633-input.o
 obj-$(CONFIG_INPUT_PCF8574)            += pcf8574_keypad.o
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c
new file mode 100644 (file)
index 0000000..80af446
--- /dev/null
@@ -0,0 +1,148 @@
+/**
+ * max8925_onkey.c - MAX8925 ONKEY driver
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ *      Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max8925.h>
+#include <linux/slab.h>
+
+#define HARDRESET_EN           (1 << 7)
+#define PWREN_EN               (1 << 7)
+
+struct max8925_onkey_info {
+       struct input_dev        *idev;
+       struct i2c_client       *i2c;
+       int                     irq;
+};
+
+/*
+ * MAX8925 gives us an interrupt when ONKEY is held for 3 seconds.
+ * max8925_set_bits() operates I2C bus and may sleep. So implement
+ * it in thread IRQ handler.
+ */
+static irqreturn_t max8925_onkey_handler(int irq, void *data)
+{
+       struct max8925_onkey_info *info = data;
+
+       input_report_key(info->idev, KEY_POWER, 1);
+       input_sync(info->idev);
+
+       /* Enable hardreset to halt if system isn't shutdown on time */
+       max8925_set_bits(info->i2c, MAX8925_SYSENSEL,
+                        HARDRESET_EN, HARDRESET_EN);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit max8925_onkey_probe(struct platform_device *pdev)
+{
+       struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
+       struct max8925_onkey_info *info;
+       int error;
+
+       info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->i2c = chip->i2c;
+       info->irq = chip->irq_base + MAX8925_IRQ_GPM_SW_3SEC;
+
+       info->idev = input_allocate_device();
+       if (!info->idev) {
+               dev_err(chip->dev, "Failed to allocate input dev\n");
+               error = -ENOMEM;
+               goto out_input;
+       }
+
+       info->idev->name = "max8925_on";
+       info->idev->phys = "max8925_on/input0";
+       info->idev->id.bustype = BUS_I2C;
+       info->idev->dev.parent = &pdev->dev;
+       info->idev->evbit[0] = BIT_MASK(EV_KEY);
+       info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+
+       error = request_threaded_irq(info->irq, NULL, max8925_onkey_handler,
+                                    IRQF_ONESHOT, "onkey", info);
+       if (error < 0) {
+               dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+                       info->irq, error);
+               goto out_irq;
+       }
+
+       error = input_register_device(info->idev);
+       if (error) {
+               dev_err(chip->dev, "Can't register input device: %d\n", error);
+               goto out;
+       }
+
+       platform_set_drvdata(pdev, info);
+
+       return 0;
+
+out:
+       free_irq(info->irq, info);
+out_irq:
+       input_free_device(info->idev);
+out_input:
+       kfree(info);
+       return error;
+}
+
+static int __devexit max8925_onkey_remove(struct platform_device *pdev)
+{
+       struct max8925_onkey_info *info = platform_get_drvdata(pdev);
+
+       free_irq(info->irq, info);
+       input_unregister_device(info->idev);
+       kfree(info);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver max8925_onkey_driver = {
+       .driver         = {
+               .name   = "max8925-onkey",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = max8925_onkey_probe,
+       .remove         = __devexit_p(max8925_onkey_remove),
+};
+
+static int __init max8925_onkey_init(void)
+{
+       return platform_driver_register(&max8925_onkey_driver);
+}
+module_init(max8925_onkey_init);
+
+static void __exit max8925_onkey_exit(void)
+{
+       platform_driver_unregister(&max8925_onkey_driver);
+}
+module_exit(max8925_onkey_exit);
+
+MODULE_DESCRIPTION("Maxim MAX8925 ONKEY driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
index fee9eac8e04ab830fbfb4fab89ef79b10138187a..4f9b2afc24e820d75b819555f7f667f94bd73f69 100644 (file)
@@ -90,8 +90,8 @@ static void vibra_disable(struct vibra_info *info)
        twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
                         (reg & ~TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
 
-       twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER);
        twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL);
+       twl4030_codec_disable_resource(TWL4030_CODEC_RES_POWER);
 
        info->enabled = false;
 }
index 1477466076ad1764989f82387cc737fd453181ab..b71eb55f2dbc97dafd4a769fc61f346e69a5e0af 100644 (file)
@@ -300,7 +300,7 @@ static int uinput_validate_absbits(struct input_dev *dev)
        unsigned int cnt;
        int retval = 0;
 
-       for (cnt = 0; cnt < ABS_MAX + 1; cnt++) {
+       for (cnt = 0; cnt < ABS_CNT; cnt++) {
                if (!test_bit(cnt, dev->absbit))
                        continue;
 
@@ -387,7 +387,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
        dev->id.product = user_dev->id.product;
        dev->id.version = user_dev->id.version;
 
-       size = sizeof(int) * (ABS_MAX + 1);
+       size = sizeof(int) * ABS_CNT;
        memcpy(dev->absmax, user_dev->absmax, size);
        memcpy(dev->absmin, user_dev->absmin, size);
        memcpy(dev->absfuzz, user_dev->absfuzz, size);
index a185ac78a42ca441a193229f2bd04ccf7cfd8079..ff5f61a0fd3ad1eb071e600e5e37fb15fb4ca61a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
 
 #include <asm/irq.h>
 #include <asm/setup.h>
@@ -34,10 +35,10 @@ MODULE_DESCRIPTION("Amiga mouse driver");
 MODULE_LICENSE("GPL");
 
 static int amimouse_lastx, amimouse_lasty;
-static struct input_dev *amimouse_dev;
 
-static irqreturn_t amimouse_interrupt(int irq, void *dummy)
+static irqreturn_t amimouse_interrupt(int irq, void *data)
 {
+       struct input_dev *dev = data;
        unsigned short joy0dat, potgor;
        int nx, ny, dx, dy;
 
@@ -59,14 +60,14 @@ static irqreturn_t amimouse_interrupt(int irq, void *dummy)
 
        potgor = amiga_custom.potgor;
 
-       input_report_rel(amimouse_dev, REL_X, dx);
-       input_report_rel(amimouse_dev, REL_Y, dy);
+       input_report_rel(dev, REL_X, dx);
+       input_report_rel(dev, REL_Y, dy);
 
-       input_report_key(amimouse_dev, BTN_LEFT,   ciaa.pra & 0x40);
-       input_report_key(amimouse_dev, BTN_MIDDLE, potgor & 0x0100);
-       input_report_key(amimouse_dev, BTN_RIGHT,  potgor & 0x0400);
+       input_report_key(dev, BTN_LEFT,   ciaa.pra & 0x40);
+       input_report_key(dev, BTN_MIDDLE, potgor & 0x0100);
+       input_report_key(dev, BTN_RIGHT,  potgor & 0x0400);
 
-       input_sync(amimouse_dev);
+       input_sync(dev);
 
        return IRQ_HANDLED;
 }
@@ -74,63 +75,90 @@ static irqreturn_t amimouse_interrupt(int irq, void *dummy)
 static int amimouse_open(struct input_dev *dev)
 {
        unsigned short joy0dat;
+       int error;
 
        joy0dat = amiga_custom.joy0dat;
 
        amimouse_lastx = joy0dat & 0xff;
        amimouse_lasty = joy0dat >> 8;
 
-       if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
-                printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
-                return -EBUSY;
-        }
+       error = request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse",
+                           dev);
+       if (error)
+               dev_err(&dev->dev, "Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
 
-        return 0;
+       return error;
 }
 
 static void amimouse_close(struct input_dev *dev)
 {
-       free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
+       free_irq(IRQ_AMIGA_VERTB, dev);
 }
 
-static int __init amimouse_init(void)
+static int __init amimouse_probe(struct platform_device *pdev)
 {
        int err;
+       struct input_dev *dev;
 
-       if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
-               return -ENODEV;
-
-       amimouse_dev = input_allocate_device();
-       if (!amimouse_dev)
+       dev = input_allocate_device();
+       if (!dev)
                return -ENOMEM;
 
-       amimouse_dev->name = "Amiga mouse";
-       amimouse_dev->phys = "amimouse/input0";
-       amimouse_dev->id.bustype = BUS_AMIGA;
-       amimouse_dev->id.vendor = 0x0001;
-       amimouse_dev->id.product = 0x0002;
-       amimouse_dev->id.version = 0x0100;
+       dev->name = pdev->name;
+       dev->phys = "amimouse/input0";
+       dev->id.bustype = BUS_AMIGA;
+       dev->id.vendor = 0x0001;
+       dev->id.product = 0x0002;
+       dev->id.version = 0x0100;
 
-       amimouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
-       amimouse_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
-       amimouse_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
+       dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+       dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+       dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
                BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
-       amimouse_dev->open = amimouse_open;
-       amimouse_dev->close = amimouse_close;
+       dev->open = amimouse_open;
+       dev->close = amimouse_close;
+       dev->dev.parent = &pdev->dev;
 
-       err = input_register_device(amimouse_dev);
+       err = input_register_device(dev);
        if (err) {
-               input_free_device(amimouse_dev);
+               input_free_device(dev);
                return err;
        }
 
+       platform_set_drvdata(pdev, dev);
+
        return 0;
 }
 
-static void __exit amimouse_exit(void)
+static int __exit amimouse_remove(struct platform_device *pdev)
 {
-        input_unregister_device(amimouse_dev);
+       struct input_dev *dev = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       input_unregister_device(dev);
+       return 0;
+}
+
+static struct platform_driver amimouse_driver = {
+       .remove = __exit_p(amimouse_remove),
+       .driver   = {
+               .name   = "amiga-mouse",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init amimouse_init(void)
+{
+       return platform_driver_probe(&amimouse_driver, amimouse_probe);
 }
 
 module_init(amimouse_init);
+
+static void __exit amimouse_exit(void)
+{
+       platform_driver_unregister(&amimouse_driver);
+}
+
 module_exit(amimouse_exit);
+
+MODULE_ALIAS("platform:amiga-mouse");
index 532279cda0e4989de8aa45e3791f920d5c82c92b..634f6f6b9b1349a27bcca9a056ca27a1b5151abc 100644 (file)
@@ -1163,8 +1163,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
        ts->reg = regulator_get(&spi->dev, "vcc");
        if (IS_ERR(ts->reg)) {
-               dev_err(&spi->dev, "unable to get regulator: %ld\n",
-                       PTR_ERR(ts->reg));
+               err = PTR_ERR(ts->reg);
+               dev_err(&spi->dev, "unable to get regulator: %ld\n", err);
                goto err_free_gpio;
        }
 
index e0b7c834111d37467b1b6454828f5ad071ddcae9..ac5d0f9b0cb14bac59636f3ae01315a517070567 100644 (file)
@@ -413,6 +413,8 @@ static struct dev_pm_ops s3c_ts_pmops = {
 #endif
 
 static struct platform_device_id s3cts_driver_ids[] = {
+       { "s3c2410-ts", 0 },
+       { "s3c2440-ts", 0 },
        { "s3c64xx-ts", FEAT_PEN_IRQ },
        { }
 };
index 29a8bbf3f086d658d6ab7b36c9c126532695640a..567d57215c28e14bbe78621d1add3b2d1204ff2f 100644 (file)
@@ -857,6 +857,11 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
        if ((pkt[0] & 0xe0) != 0xe0)
                return 0;
 
+       if (be16_to_cpu(packet->data_len) > 0xff)
+               packet->data_len = cpu_to_be16(be16_to_cpu(packet->data_len) - 0x100);
+       if (be16_to_cpu(packet->x_len) > 0xff)
+               packet->x_len = cpu_to_be16(be16_to_cpu(packet->x_len) - 0x80);
+
        /* send ACK */
        ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
 
@@ -1112,7 +1117,7 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
 
 #ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
        [DEVTYPE_NEXIO] = {
-               .rept_size      = 128,
+               .rept_size      = 1024,
                .irq_always     = true,
                .read_data      = nexio_read_data,
                .init           = nexio_init,
index c3243c913ec033b570c04678c6408efa8e13a694..81048b8ed8ad97b7890f631155c77264c35fd98d 100644 (file)
@@ -98,8 +98,6 @@ mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off)
        if (*debug & DEBUG_TIMER)
                printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__,
                        filep, buf, (int)count, off);
-       if (*off != filep->f_pos)
-               return -ESPIPE;
 
        if (list_empty(&dev->expired) && (dev->work == 0)) {
                if (filep->f_flags & O_NONBLOCK)
index 9ea17d6c799bac62fa348a043469246f5ef6dbb6..d2c0f94fa37d7a708b1c6854e7be3b1d3b60162f 100644 (file)
@@ -4645,7 +4645,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
                        kfree(percpu->scribble);
                        pr_err("%s: failed memory allocation for cpu%ld\n",
                               __func__, cpu);
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
                }
                break;
        case CPU_DEAD:
index d33693c133689522e5ca74e8de41c8aaa7c42066..c4b117f5fb70959df600a2153ac7d961a692488c 100644 (file)
@@ -186,14 +186,9 @@ static int i2o_cfg_parms(unsigned long arg, unsigned int type)
        if (!dev)
                return -ENXIO;
 
-       ops = kmalloc(kcmd.oplen, GFP_KERNEL);
-       if (!ops)
-               return -ENOMEM;
-
-       if (copy_from_user(ops, kcmd.opbuf, kcmd.oplen)) {
-               kfree(ops);
-               return -EFAULT;
-       }
+       ops = memdup_user(kcmd.opbuf, kcmd.oplen);
+       if (IS_ERR(ops))
+               return PTR_ERR(ops);
 
        /*
         * It's possible to have a _very_ large table
index 31a991161f0a0f984ab73354d1281ccf8aa4943b..5bfb2a2041b8a8f4854fbaf7351e8a1739ea5db0 100644 (file)
@@ -75,6 +75,9 @@ enum ctype {
        UNALIGNED_LOAD_STORE_WRITE,
        OVERWRITE_ALLOCATION,
        WRITE_AFTER_FREE,
+       SOFTLOCKUP,
+       HARDLOCKUP,
+       HUNG_TASK,
 };
 
 static char* cp_name[] = {
@@ -99,6 +102,9 @@ static char* cp_type[] = {
        "UNALIGNED_LOAD_STORE_WRITE",
        "OVERWRITE_ALLOCATION",
        "WRITE_AFTER_FREE",
+       "SOFTLOCKUP",
+       "HARDLOCKUP",
+       "HUNG_TASK",
 };
 
 static struct jprobe lkdtm;
@@ -320,6 +326,20 @@ static void lkdtm_do_action(enum ctype which)
                memset(data, 0x78, len);
                break;
        }
+       case SOFTLOCKUP:
+               preempt_disable();
+               for (;;)
+                       cpu_relax();
+               break;
+       case HARDLOCKUP:
+               local_irq_disable();
+               for (;;)
+                       cpu_relax();
+               break;
+       case HUNG_TASK:
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule();
+               break;
        case NONE:
        default:
                break;
index 3168ebd616b2aefe0646514171e7c3d553a70fcc..569e94da844cd3f1ffe022f8e4885752096bdec4 100644 (file)
@@ -1252,9 +1252,8 @@ EXPORT_SYMBOL(mmc_card_can_sleep);
 /**
  *     mmc_suspend_host - suspend a host
  *     @host: mmc host
- *     @state: suspend mode (PM_SUSPEND_xxx)
  */
-int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
+int mmc_suspend_host(struct mmc_host *host)
 {
        int err = 0;
 
index 0d96080d44b098431af53b15764c0f8e6fdd1e81..63772e7e7608c5f2d1c8229b5978e1c55fd0b796 100644 (file)
@@ -79,8 +79,6 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
         * we cannot use the retries field in mmc_command.
         */
        for (i = 0;i <= retries;i++) {
-               memset(&mrq, 0, sizeof(struct mmc_request));
-
                err = mmc_app_cmd(host, card);
                if (err) {
                        /* no point in retrying; no APP commands allowed */
index ff27c8c713554024dd0b2530cda395dd2d296b94..0f687cdeb064ac917d778a35f9bc5c756f1da89e 100644 (file)
@@ -405,6 +405,36 @@ void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret)
 }
 EXPORT_SYMBOL_GPL(sdio_writeb);
 
+/**
+ *     sdio_writeb_readb - write and read a byte from SDIO function
+ *     @func: SDIO function to access
+ *     @write_byte: byte to write
+ *     @addr: address to write to
+ *     @err_ret: optional status value from transfer
+ *
+ *     Performs a RAW (Read after Write) operation as defined by SDIO spec -
+ *     single byte is written to address space of a given SDIO function and
+ *     response is read back from the same address, both using single request.
+ *     If there is a problem with the operation, 0xff is returned and
+ *     @err_ret will contain the error code.
+ */
+u8 sdio_writeb_readb(struct sdio_func *func, u8 write_byte,
+       unsigned int addr, int *err_ret)
+{
+       int ret;
+       u8 val;
+
+       ret = mmc_io_rw_direct(func->card, 1, func->num, addr,
+                       write_byte, &val);
+       if (err_ret)
+               *err_ret = ret;
+       if (ret)
+               val = 0xff;
+
+       return val;
+}
+EXPORT_SYMBOL_GPL(sdio_writeb_readb);
+
 /**
  *     sdio_memcpy_fromio - read a chunk of memory from a SDIO function
  *     @func: SDIO function to access
index 2e13b94769fdce2747590ce8f2da89d6a58eff79..e171e77f6129d8b80829099fabe0bdd1a8e25f71 100644 (file)
@@ -136,6 +136,18 @@ config MMC_SDHCI_S3C
 
          If unsure, say N.
 
+config MMC_SDHCI_SPEAR
+       tristate "SDHCI support on ST SPEAr platform"
+       depends on MMC_SDHCI && PLAT_SPEAR
+       help
+         This selects the Secure Digital Host Controller Interface (SDHCI)
+         often referrered to as the HSMMC block in some of the ST SPEAR range
+         of SoC
+
+         If you have a controller with this interface, say Y or M here.
+
+         If unsure, say N.
+
 config MMC_SDHCI_S3C_DMA
        bool "DMA support on S3C SDHCI"
        depends on MMC_SDHCI_S3C && EXPERIMENTAL
@@ -412,3 +424,11 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
        depends on SDH_BFIN
        help
          If you say yes here SD-Cards may work on the EZkit.
+
+config MMC_SH_MMCIF
+       tristate "SuperH Internal MMCIF support"
+       depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE)
+       help
+         This selects the MMC Host Interface controler (MMCIF).
+
+         This driver supports MMCIF in sh7724/sh7757/sh7372.
index f4803977dfceb2b8f71d4514e0af8c115c923aee..e30c2ee488942c711713647e731d888af5619d64 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_MMC_SDHCI)               += sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)    += sdhci-pci.o
 obj-$(CONFIG_MMC_SDHCI_PLTFM)  += sdhci-pltfm.o
 obj-$(CONFIG_MMC_SDHCI_S3C)    += sdhci-s3c.o
+obj-$(CONFIG_MMC_SDHCI_SPEAR)  += sdhci-spear.o
 obj-$(CONFIG_MMC_WBSD)         += wbsd.o
 obj-$(CONFIG_MMC_AU1X)         += au1xmmc.o
 obj-$(CONFIG_MMC_OMAP)         += omap.o
@@ -34,6 +35,7 @@ obj-$(CONFIG_MMC_TMIO)                += tmio_mmc.o
 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_SH_MMCIF)     += sh_mmcif.o
 
 obj-$(CONFIG_MMC_SDHCI_OF)     += sdhci-of.o
 sdhci-of-y                             := sdhci-of-core.o
index 336d9f553f3e85ae6240b5a22c83ae0eb33fe3b0..5f3a599ead07bbdfae11f7abc0198285e743db81 100644 (file)
@@ -1157,7 +1157,7 @@ static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
                enable_irq_wake(host->board->det_pin);
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
 
        return ret;
 }
index df0e8a88d85ffec1f725fe25b48239f1a6c0fd57..95ef864ad8f9f13e73bbb04c64f966e02a772672 100644 (file)
@@ -173,6 +173,7 @@ struct atmel_mci {
  * @mmc: The mmc_host representing this slot.
  * @host: The MMC controller this slot is using.
  * @sdc_reg: Value of SDCR to be written before using this slot.
+ * @sdio_irq: SDIO irq mask for this slot.
  * @mrq: mmc_request currently being processed or waiting to be
  *     processed, or NULL when the slot is idle.
  * @queue_node: List node for placing this node in the @queue list of
@@ -191,6 +192,7 @@ struct atmel_mci_slot {
        struct atmel_mci        *host;
 
        u32                     sdc_reg;
+       u32                     sdio_irq;
 
        struct mmc_request      *mrq;
        struct list_head        queue_node;
@@ -792,7 +794,7 @@ static void atmci_start_request(struct atmel_mci *host,
        mci_writel(host, SDCR, slot->sdc_reg);
 
        iflags = mci_readl(host, IMR);
-       if (iflags)
+       if (iflags & ~(MCI_SDIOIRQA | MCI_SDIOIRQB))
                dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
                                iflags);
 
@@ -952,10 +954,21 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                if (mci_has_rwproof())
                        host->mode_reg |= (MCI_MR_WRPROOF | MCI_MR_RDPROOF);
 
-               if (list_empty(&host->queue))
+               if (atmci_is_mci2()) {
+                       /* setup High Speed mode in relation with card capacity */
+                       if (ios->timing == MMC_TIMING_SD_HS)
+                               host->cfg_reg |= MCI_CFG_HSMODE;
+                       else
+                               host->cfg_reg &= ~MCI_CFG_HSMODE;
+               }
+
+               if (list_empty(&host->queue)) {
                        mci_writel(host, MR, host->mode_reg);
-               else
+                       if (atmci_is_mci2())
+                               mci_writel(host, CFG, host->cfg_reg);
+               } else {
                        host->need_clock_update = true;
+               }
 
                spin_unlock_bh(&host->lock);
        } else {
@@ -1030,11 +1043,23 @@ static int atmci_get_cd(struct mmc_host *mmc)
        return present;
 }
 
+static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       struct atmel_mci_slot   *slot = mmc_priv(mmc);
+       struct atmel_mci        *host = slot->host;
+
+       if (enable)
+               mci_writel(host, IER, slot->sdio_irq);
+       else
+               mci_writel(host, IDR, slot->sdio_irq);
+}
+
 static const struct mmc_host_ops atmci_ops = {
        .request        = atmci_request,
        .set_ios        = atmci_set_ios,
        .get_ro         = atmci_get_ro,
        .get_cd         = atmci_get_cd,
+       .enable_sdio_irq = atmci_enable_sdio_irq,
 };
 
 /* Called with host->lock held */
@@ -1052,8 +1077,11 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
         * necessary if set_ios() is called when a different slot is
         * busy transfering data.
         */
-       if (host->need_clock_update)
+       if (host->need_clock_update) {
                mci_writel(host, MR, host->mode_reg);
+               if (atmci_is_mci2())
+                       mci_writel(host, CFG, host->cfg_reg);
+       }
 
        host->cur_slot->mrq = NULL;
        host->mrq = NULL;
@@ -1483,6 +1511,19 @@ static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
        tasklet_schedule(&host->tasklet);
 }
 
+static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
+{
+       int     i;
+
+       for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+               struct atmel_mci_slot *slot = host->slot[i];
+               if (slot && (status & slot->sdio_irq)) {
+                       mmc_signal_sdio_irq(slot->mmc);
+               }
+       }
+}
+
+
 static irqreturn_t atmci_interrupt(int irq, void *dev_id)
 {
        struct atmel_mci        *host = dev_id;
@@ -1522,6 +1563,10 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
 
                if (pending & MCI_CMDRDY)
                        atmci_cmd_interrupt(host, status);
+
+               if (pending & (MCI_SDIOIRQA | MCI_SDIOIRQB))
+                       atmci_sdio_interrupt(host, status);
+
        } while (pass_count++ < 5);
 
        return pass_count ? IRQ_HANDLED : IRQ_NONE;
@@ -1544,7 +1589,7 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
 
 static int __init atmci_init_slot(struct atmel_mci *host,
                struct mci_slot_pdata *slot_data, unsigned int id,
-               u32 sdc_reg)
+               u32 sdc_reg, u32 sdio_irq)
 {
        struct mmc_host                 *mmc;
        struct atmel_mci_slot           *slot;
@@ -1560,11 +1605,16 @@ static int __init atmci_init_slot(struct atmel_mci *host,
        slot->wp_pin = slot_data->wp_pin;
        slot->detect_is_active_high = slot_data->detect_is_active_high;
        slot->sdc_reg = sdc_reg;
+       slot->sdio_irq = sdio_irq;
 
        mmc->ops = &atmci_ops;
        mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
        mmc->f_max = host->bus_hz / 2;
        mmc->ocr_avail  = MMC_VDD_32_33 | MMC_VDD_33_34;
+       if (sdio_irq)
+               mmc->caps |= MMC_CAP_SDIO_IRQ;
+       if (atmci_is_mci2())
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
        if (slot_data->bus_width >= 4)
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 
@@ -1753,13 +1803,13 @@ static int __init atmci_probe(struct platform_device *pdev)
        ret = -ENODEV;
        if (pdata->slot[0].bus_width) {
                ret = atmci_init_slot(host, &pdata->slot[0],
-                               0, MCI_SDCSEL_SLOT_A);
+                               0, MCI_SDCSEL_SLOT_A, MCI_SDIOIRQA);
                if (!ret)
                        nr_slots++;
        }
        if (pdata->slot[1].bus_width) {
                ret = atmci_init_slot(host, &pdata->slot[1],
-                               1, MCI_SDCSEL_SLOT_B);
+                               1, MCI_SDCSEL_SLOT_B, MCI_SDIOIRQB);
                if (!ret)
                        nr_slots++;
        }
index f5834449400e0b06d6cd4d60f85c9ce4d303705a..c8da5d30a861b5b7a294945f59aae0d80968c128 100644 (file)
@@ -1142,7 +1142,7 @@ static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state)
        struct au1xmmc_host *host = platform_get_drvdata(pdev);
        int ret;
 
-       ret = mmc_suspend_host(host->mmc, state);
+       ret = mmc_suspend_host(host->mmc);
        if (ret)
                return ret;
 
index 6919e844072c9dbf683359764ea6fe55a763906b..4b0e677d7295091dbd4772054a8c06e20a4d3184 100644 (file)
@@ -576,7 +576,7 @@ static int sdh_suspend(struct platform_device *dev, pm_message_t state)
        int ret = 0;
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
 
        bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() & ~PWR_ON);
        peripheral_free_list(drv_data->pin_req);
index 92a324f7417c3eb0a710a19fcd47b1f792b067f7..ca3bdc831900be8b0f39457a495081534907c3b5 100644 (file)
@@ -675,7 +675,7 @@ static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state)
        struct mmc_host *mmc = cb710_slot_to_mmc(slot);
        int err;
 
-       err = mmc_suspend_host(mmc, state);
+       err = mmc_suspend_host(mmc);
        if (err)
                return err;
 
index 3bd0ba294e9de667a56c2abf3915f77d43ad8b1b..33d9f1b00862f805aca98acf72c497d91239be02 100644 (file)
 
 /*
  * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
- * and we handle up to NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
+ * and we handle up to MAX_NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
  * for drivers with max_hw_segs == 1, making the segments bigger (64KB)
- * than the page or two that's otherwise typical.  NR_SG == 16 gives at
- * least the same throughput boost, using EDMA transfer linkage instead
- * of spending CPU time copying pages.
+ * than the page or two that's otherwise typical. nr_sg (passed from
+ * platform data) == 16 gives at least the same throughput boost, using
+ * EDMA transfer linkage instead of spending CPU time copying pages.
  */
 #define MAX_CCNT       ((1 << 16) - 1)
 
-#define NR_SG          16
+#define MAX_NR_SG      16
 
 static unsigned rw_threshold = 32;
 module_param(rw_threshold, uint, S_IRUGO);
@@ -171,6 +171,7 @@ struct mmc_davinci_host {
 #define DAVINCI_MMC_DATADIR_READ       1
 #define DAVINCI_MMC_DATADIR_WRITE      2
        unsigned char data_dir;
+       unsigned char suspended;
 
        /* buffer is used during PIO of one scatterlist segment, and
         * is updated along with buffer_bytes_left.  bytes_left applies
@@ -192,7 +193,7 @@ struct mmc_davinci_host {
        struct edmacc_param     tx_template;
        struct edmacc_param     rx_template;
        unsigned                n_link;
-       u32                     links[NR_SG - 1];
+       u32                     links[MAX_NR_SG - 1];
 
        /* For PIO we walk scatterlists one segment at a time. */
        unsigned int            sg_len;
@@ -202,6 +203,8 @@ struct mmc_davinci_host {
        u8 version;
        /* for ns in one cycle calculation */
        unsigned ns_in_one_cycle;
+       /* Number of sg segments */
+       u8 nr_sg;
 #ifdef CONFIG_CPU_FREQ
        struct notifier_block   freq_transition;
 #endif
@@ -568,6 +571,7 @@ davinci_release_dma_channels(struct mmc_davinci_host *host)
 
 static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
 {
+       u32 link_size;
        int r, i;
 
        /* Acquire master DMA write channel */
@@ -593,7 +597,8 @@ static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
        /* Allocate parameter RAM slots, which will later be bound to a
         * channel as needed to handle a scatterlist.
         */
-       for (i = 0; i < ARRAY_SIZE(host->links); i++) {
+       link_size = min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links));
+       for (i = 0; i < link_size; i++) {
                r = edma_alloc_slot(EDMA_CTLR(host->txdma), EDMA_SLOT_ANY);
                if (r < 0) {
                        dev_dbg(mmc_dev(host->mmc), "dma PaRAM alloc --> %d\n",
@@ -905,19 +910,26 @@ static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
        }
 }
 
-static void
-davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data)
+static inline void mmc_davinci_reset_ctrl(struct mmc_davinci_host *host,
+                                                               int val)
 {
        u32 temp;
 
-       /* reset command and data state machines */
        temp = readl(host->base + DAVINCI_MMCCTL);
-       writel(temp | MMCCTL_CMDRST | MMCCTL_DATRST,
-               host->base + DAVINCI_MMCCTL);
+       if (val)        /* reset */
+               temp |= MMCCTL_CMDRST | MMCCTL_DATRST;
+       else            /* enable */
+               temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST);
 
-       temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST);
-       udelay(10);
        writel(temp, host->base + DAVINCI_MMCCTL);
+       udelay(10);
+}
+
+static void
+davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data)
+{
+       mmc_davinci_reset_ctrl(host, 1);
+       mmc_davinci_reset_ctrl(host, 0);
 }
 
 static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
@@ -1121,15 +1133,8 @@ static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host)
 #endif
 static void __init init_mmcsd_host(struct mmc_davinci_host *host)
 {
-       /* DAT line portion is diabled and in reset state */
-       writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_DATRST,
-               host->base + DAVINCI_MMCCTL);
-
-       /* CMD line portion is diabled and in reset state */
-       writel(readl(host->base + DAVINCI_MMCCTL) | MMCCTL_CMDRST,
-               host->base + DAVINCI_MMCCTL);
 
-       udelay(10);
+       mmc_davinci_reset_ctrl(host, 1);
 
        writel(0, host->base + DAVINCI_MMCCLK);
        writel(MMCCLK_CLKEN, host->base + DAVINCI_MMCCLK);
@@ -1137,12 +1142,7 @@ static void __init init_mmcsd_host(struct mmc_davinci_host *host)
        writel(0x1FFF, host->base + DAVINCI_MMCTOR);
        writel(0xFFFF, host->base + DAVINCI_MMCTOD);
 
-       writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_DATRST,
-               host->base + DAVINCI_MMCCTL);
-       writel(readl(host->base + DAVINCI_MMCCTL) & ~MMCCTL_CMDRST,
-               host->base + DAVINCI_MMCCTL);
-
-       udelay(10);
+       mmc_davinci_reset_ctrl(host, 0);
 }
 
 static int __init davinci_mmcsd_probe(struct platform_device *pdev)
@@ -1202,6 +1202,12 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
 
        init_mmcsd_host(host);
 
+       if (pdata->nr_sg)
+               host->nr_sg = pdata->nr_sg - 1;
+
+       if (host->nr_sg > MAX_NR_SG || !host->nr_sg)
+               host->nr_sg = MAX_NR_SG;
+
        host->use_dma = use_dma;
        host->irq = irq;
 
@@ -1327,32 +1333,65 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int davinci_mmcsd_suspend(struct platform_device *pdev, pm_message_t msg)
+static int davinci_mmcsd_suspend(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+       int ret;
 
-       return mmc_suspend_host(host->mmc, msg);
+       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;
 }
 
-static int davinci_mmcsd_resume(struct platform_device *pdev)
+static int davinci_mmcsd_resume(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
        struct mmc_davinci_host *host = platform_get_drvdata(pdev);
+       int ret;
+
+       if (!host->suspended)
+               return 0;
 
-       return mmc_resume_host(host->mmc);
+       clk_enable(host->clk);
+       mmc_host_enable(host->mmc);
+
+       mmc_davinci_reset_ctrl(host, 0);
+       ret = mmc_resume_host(host->mmc);
+       if (!ret)
+               host->suspended = 0;
+
+       return ret;
 }
+
+static const struct dev_pm_ops davinci_mmcsd_pm = {
+       .suspend        = davinci_mmcsd_suspend,
+       .resume         = davinci_mmcsd_resume,
+};
+
+#define davinci_mmcsd_pm_ops (&davinci_mmcsd_pm)
 #else
-#define davinci_mmcsd_suspend  NULL
-#define davinci_mmcsd_resume   NULL
+#define davinci_mmcsd_pm_ops NULL
 #endif
 
 static struct platform_driver davinci_mmcsd_driver = {
        .driver         = {
                .name   = "davinci_mmc",
                .owner  = THIS_MODULE,
+               .pm     = davinci_mmcsd_pm_ops,
        },
        .remove         = __exit_p(davinci_mmcsd_remove),
-       .suspend        = davinci_mmcsd_suspend,
-       .resume         = davinci_mmcsd_resume,
 };
 
 static int __init davinci_mmcsd_init(void)
index bf98d7cc928aa3e605c81bbe488bf248ebdd2c86..9a68ff4353a2e83878fce5429afe9351140daf57 100644 (file)
@@ -1115,7 +1115,7 @@ static int imxmci_suspend(struct platform_device *dev, pm_message_t state)
        int ret = 0;
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
 
        return ret;
 }
index ff115d92088811fbe544220cd9800da07f58cd4b..4917af96bae1d0be7472e32bf13784ec5ffb4412 100644 (file)
@@ -824,7 +824,7 @@ static int mmci_suspend(struct amba_device *dev, pm_message_t state)
        if (mmc) {
                struct mmci_host *host = mmc_priv(mmc);
 
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
                if (ret == 0)
                        writel(0, host->base + MMCIMASK0);
        }
index 61f1d27fed3fe7b1b510c7cfc7d49883b8ad581a..24e09454e52238c87c6b00dfdaee00196f4ac6eb 100644 (file)
@@ -1327,7 +1327,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
                        disable_irq(host->stat_irq);
 
                if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
-                       rc = mmc_suspend_host(mmc, state);
+                       rc = mmc_suspend_host(mmc);
                if (!rc)
                        msmsdcc_writel(host, 0, MMCIMASK0);
                if (host->clks_on)
index 34e23489811ae74ea14594f1af1cb84f7a6e6b58..366eefa77c5a4b96f2a1c8ce9f822ff053aecb1c 100644 (file)
@@ -865,7 +865,7 @@ static int mvsd_suspend(struct platform_device *dev, pm_message_t state)
        int ret = 0;
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
 
        return ret;
 }
index ec18e3b603427093f6945049771e508e3320f199..d9d4a72e0ec792d42386d21afcf327fa5b59f69c 100644 (file)
@@ -932,7 +932,7 @@ static int mxcmci_suspend(struct platform_device *dev, pm_message_t state)
        int ret = 0;
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, state);
+               ret = mmc_suspend_host(mmc);
 
        return ret;
 }
index 84d280406341f1bf071e07430e6118766cea87c5..2b281680e3206da99f9e991d69f12c5edef92754 100644 (file)
 #include <plat/fpga.h>
 
 #define        OMAP_MMC_REG_CMD        0x00
-#define        OMAP_MMC_REG_ARGL       0x04
-#define        OMAP_MMC_REG_ARGH       0x08
-#define        OMAP_MMC_REG_CON        0x0c
-#define        OMAP_MMC_REG_STAT       0x10
-#define        OMAP_MMC_REG_IE         0x14
-#define        OMAP_MMC_REG_CTO        0x18
-#define        OMAP_MMC_REG_DTO        0x1c
-#define        OMAP_MMC_REG_DATA       0x20
-#define        OMAP_MMC_REG_BLEN       0x24
-#define        OMAP_MMC_REG_NBLK       0x28
-#define        OMAP_MMC_REG_BUF        0x2c
-#define OMAP_MMC_REG_SDIO      0x34
-#define        OMAP_MMC_REG_REV        0x3c
-#define        OMAP_MMC_REG_RSP0       0x40
-#define        OMAP_MMC_REG_RSP1       0x44
-#define        OMAP_MMC_REG_RSP2       0x48
-#define        OMAP_MMC_REG_RSP3       0x4c
-#define        OMAP_MMC_REG_RSP4       0x50
-#define        OMAP_MMC_REG_RSP5       0x54
-#define        OMAP_MMC_REG_RSP6       0x58
-#define        OMAP_MMC_REG_RSP7       0x5c
-#define        OMAP_MMC_REG_IOSR       0x60
-#define        OMAP_MMC_REG_SYSC       0x64
-#define        OMAP_MMC_REG_SYSS       0x68
+#define        OMAP_MMC_REG_ARGL       0x01
+#define        OMAP_MMC_REG_ARGH       0x02
+#define        OMAP_MMC_REG_CON        0x03
+#define        OMAP_MMC_REG_STAT       0x04
+#define        OMAP_MMC_REG_IE         0x05
+#define        OMAP_MMC_REG_CTO        0x06
+#define        OMAP_MMC_REG_DTO        0x07
+#define        OMAP_MMC_REG_DATA       0x08
+#define        OMAP_MMC_REG_BLEN       0x09
+#define        OMAP_MMC_REG_NBLK       0x0a
+#define        OMAP_MMC_REG_BUF        0x0b
+#define        OMAP_MMC_REG_SDIO       0x0d
+#define        OMAP_MMC_REG_REV        0x0f
+#define        OMAP_MMC_REG_RSP0       0x10
+#define        OMAP_MMC_REG_RSP1       0x11
+#define        OMAP_MMC_REG_RSP2       0x12
+#define        OMAP_MMC_REG_RSP3       0x13
+#define        OMAP_MMC_REG_RSP4       0x14
+#define        OMAP_MMC_REG_RSP5       0x15
+#define        OMAP_MMC_REG_RSP6       0x16
+#define        OMAP_MMC_REG_RSP7       0x17
+#define        OMAP_MMC_REG_IOSR       0x18
+#define        OMAP_MMC_REG_SYSC       0x19
+#define        OMAP_MMC_REG_SYSS       0x1a
 
 #define        OMAP_MMC_STAT_CARD_ERR          (1 << 14)
 #define        OMAP_MMC_STAT_CARD_IRQ          (1 << 13)
@@ -78,8 +78,9 @@
 #define        OMAP_MMC_STAT_CARD_BUSY         (1 <<  2)
 #define        OMAP_MMC_STAT_END_OF_CMD        (1 <<  0)
 
-#define OMAP_MMC_READ(host, reg)       __raw_readw((host)->virt_base + OMAP_MMC_REG_##reg)
-#define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG_##reg)
+#define OMAP_MMC_REG(host, reg)                (OMAP_MMC_REG_##reg << (host)->reg_shift)
+#define OMAP_MMC_READ(host, reg)       __raw_readw((host)->virt_base + OMAP_MMC_REG(host, reg))
+#define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG(host, reg))
 
 /*
  * Command types
@@ -133,6 +134,7 @@ struct mmc_omap_host {
        int                     irq;
        unsigned char           bus_mode;
        unsigned char           hw_bus_mode;
+       unsigned int            reg_shift;
 
        struct work_struct      cmd_abort_work;
        unsigned                abort:1;
@@ -680,9 +682,9 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
        host->data->bytes_xfered += n;
 
        if (write) {
-               __raw_writesw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
+               __raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n);
        } else {
-               __raw_readsw(host->virt_base + OMAP_MMC_REG_DATA, host->buffer, n);
+               __raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n);
        }
 }
 
@@ -900,7 +902,7 @@ mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
        int dst_port = 0;
        int sync_dev = 0;
 
-       data_addr = host->phys_base + OMAP_MMC_REG_DATA;
+       data_addr = host->phys_base + OMAP_MMC_REG(host, DATA);
        frame = data->blksz;
        count = sg_dma_len(sg);
 
@@ -1493,6 +1495,8 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
                }
        }
 
+       host->reg_shift = (cpu_is_omap7xx() ? 1 : 2);
+
        return 0;
 
 err_plat_cleanup:
@@ -1557,7 +1561,7 @@ static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg)
                struct mmc_omap_slot *slot;
 
                slot = host->slots[i];
-               ret = mmc_suspend_host(slot->mmc, mesg);
+               ret = mmc_suspend_host(slot->mmc);
                if (ret < 0) {
                        while (--i >= 0) {
                                slot = host->slots[i];
index e9caf694c59e200e57eed9cc1cc29847139cf9b4..b032828c61263028963bd412a7455546d5e86ce7 100644 (file)
@@ -157,12 +157,10 @@ struct omap_hsmmc_host {
         */
        struct  regulator       *vcc;
        struct  regulator       *vcc_aux;
-       struct  semaphore       sem;
        struct  work_struct     mmc_carddetect_work;
        void    __iomem         *base;
        resource_size_t         mapbase;
        spinlock_t              irq_lock; /* Prevent races with irq handler */
-       unsigned long           flags;
        unsigned int            id;
        unsigned int            dma_len;
        unsigned int            dma_sg_idx;
@@ -183,6 +181,7 @@ struct omap_hsmmc_host {
        int                     protect_card;
        int                     reqs_blocked;
        int                     use_reg;
+       int                     req_in_progress;
 
        struct  omap_mmc_platform_data  *pdata;
 };
@@ -524,6 +523,27 @@ static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
                dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
 }
 
+static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host)
+{
+       unsigned int irq_mask;
+
+       if (host->use_dma)
+               irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE);
+       else
+               irq_mask = INT_EN_MASK;
+
+       OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+       OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
+       OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
+}
+
+static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
+{
+       OMAP_HSMMC_WRITE(host->base, ISE, 0);
+       OMAP_HSMMC_WRITE(host->base, IE, 0);
+       OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
+}
+
 #ifdef CONFIG_PM
 
 /*
@@ -592,9 +612,7 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
                && time_before(jiffies, timeout))
                ;
 
-       OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
-       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
-       OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+       omap_hsmmc_disable_irq(host);
 
        /* Do not initialize card-specific things if the power is off */
        if (host->power_mode == MMC_POWER_OFF)
@@ -697,6 +715,8 @@ static void send_init_stream(struct omap_hsmmc_host *host)
                return;
 
        disable_irq(host->irq);
+
+       OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
        OMAP_HSMMC_WRITE(host->base, CON,
                OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
        OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
@@ -762,17 +782,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
                mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
        host->cmd = cmd;
 
-       /*
-        * Clear status bits and enable interrupts
-        */
-       OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
-       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
-
-       if (host->use_dma)
-               OMAP_HSMMC_WRITE(host->base, IE,
-                                INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE));
-       else
-               OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+       omap_hsmmc_enable_irq(host);
 
        host->response_busy = 0;
        if (cmd->flags & MMC_RSP_PRESENT) {
@@ -806,13 +816,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
        if (host->use_dma)
                cmdreg |= DMA_EN;
 
-       /*
-        * In an interrupt context (i.e. STOP command), the spinlock is unlocked
-        * by the interrupt handler, otherwise (i.e. for a new request) it is
-        * unlocked here.
-        */
-       if (!in_interrupt())
-               spin_unlock_irqrestore(&host->irq_lock, host->flags);
+       host->req_in_progress = 1;
 
        OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
        OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
@@ -827,6 +831,23 @@ omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
                return DMA_FROM_DEVICE;
 }
 
+static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq)
+{
+       int dma_ch;
+
+       spin_lock(&host->irq_lock);
+       host->req_in_progress = 0;
+       dma_ch = host->dma_ch;
+       spin_unlock(&host->irq_lock);
+
+       omap_hsmmc_disable_irq(host);
+       /* Do not complete the request if DMA is still in progress */
+       if (mrq->data && host->use_dma && dma_ch != -1)
+               return;
+       host->mrq = NULL;
+       mmc_request_done(host->mmc, mrq);
+}
+
 /*
  * Notify the transfer complete to MMC core
  */
@@ -843,25 +864,19 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
                        return;
                }
 
-               host->mrq = NULL;
-               mmc_request_done(host->mmc, mrq);
+               omap_hsmmc_request_done(host, mrq);
                return;
        }
 
        host->data = NULL;
 
-       if (host->use_dma && host->dma_ch != -1)
-               dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
-                       omap_hsmmc_get_dma_dir(host, data));
-
        if (!data->error)
                data->bytes_xfered += data->blocks * (data->blksz);
        else
                data->bytes_xfered = 0;
 
        if (!data->stop) {
-               host->mrq = NULL;
-               mmc_request_done(host->mmc, data->mrq);
+               omap_hsmmc_request_done(host, data->mrq);
                return;
        }
        omap_hsmmc_start_command(host, data->stop, NULL);
@@ -887,10 +902,8 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
                        cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
                }
        }
-       if ((host->data == NULL && !host->response_busy) || cmd->error) {
-               host->mrq = NULL;
-               mmc_request_done(host->mmc, cmd->mrq);
-       }
+       if ((host->data == NULL && !host->response_busy) || cmd->error)
+               omap_hsmmc_request_done(host, cmd->mrq);
 }
 
 /*
@@ -898,14 +911,19 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
  */
 static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
 {
+       int dma_ch;
+
        host->data->error = errno;
 
-       if (host->use_dma && host->dma_ch != -1) {
+       spin_lock(&host->irq_lock);
+       dma_ch = host->dma_ch;
+       host->dma_ch = -1;
+       spin_unlock(&host->irq_lock);
+
+       if (host->use_dma && dma_ch != -1) {
                dma_unmap_sg(mmc_dev(host->mmc), host->data->sg, host->dma_len,
                        omap_hsmmc_get_dma_dir(host, host->data));
-               omap_free_dma(host->dma_ch);
-               host->dma_ch = -1;
-               up(&host->sem);
+               omap_free_dma(dma_ch);
        }
        host->data = NULL;
 }
@@ -967,28 +985,21 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
                        __func__);
 }
 
-/*
- * MMC controller IRQ handler
- */
-static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
+static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 {
-       struct omap_hsmmc_host *host = dev_id;
        struct mmc_data *data;
-       int end_cmd = 0, end_trans = 0, status;
-
-       spin_lock(&host->irq_lock);
-
-       if (host->mrq == NULL) {
-               OMAP_HSMMC_WRITE(host->base, STAT,
-                       OMAP_HSMMC_READ(host->base, STAT));
-               /* Flush posted write */
-               OMAP_HSMMC_READ(host->base, STAT);
-               spin_unlock(&host->irq_lock);
-               return IRQ_HANDLED;
+       int end_cmd = 0, end_trans = 0;
+
+       if (!host->req_in_progress) {
+               do {
+                       OMAP_HSMMC_WRITE(host->base, STAT, status);
+                       /* Flush posted write */
+                       status = OMAP_HSMMC_READ(host->base, STAT);
+               } while (status & INT_EN_MASK);
+               return;
        }
 
        data = host->data;
-       status = OMAP_HSMMC_READ(host->base, STAT);
        dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
 
        if (status & ERR) {
@@ -1041,15 +1052,27 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
        }
 
        OMAP_HSMMC_WRITE(host->base, STAT, status);
-       /* Flush posted write */
-       OMAP_HSMMC_READ(host->base, STAT);
 
        if (end_cmd || ((status & CC) && host->cmd))
                omap_hsmmc_cmd_done(host, host->cmd);
        if ((end_trans || (status & TC)) && host->mrq)
                omap_hsmmc_xfer_done(host, data);
+}
 
-       spin_unlock(&host->irq_lock);
+/*
+ * MMC controller IRQ handler
+ */
+static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
+{
+       struct omap_hsmmc_host *host = dev_id;
+       int status;
+
+       status = OMAP_HSMMC_READ(host->base, STAT);
+       do {
+               omap_hsmmc_do_irq(host, status);
+               /* Flush posted write */
+               status = OMAP_HSMMC_READ(host->base, STAT);
+       } while (status & INT_EN_MASK);
 
        return IRQ_HANDLED;
 }
@@ -1244,31 +1267,47 @@ static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host,
 /*
  * DMA call back function
  */
-static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *data)
+static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
 {
-       struct omap_hsmmc_host *host = data;
+       struct omap_hsmmc_host *host = cb_data;
+       struct mmc_data *data = host->mrq->data;
+       int dma_ch, req_in_progress;
 
        if (ch_status & OMAP2_DMA_MISALIGNED_ERR_IRQ)
                dev_dbg(mmc_dev(host->mmc), "MISALIGNED_ADRS_ERR\n");
 
-       if (host->dma_ch < 0)
+       spin_lock(&host->irq_lock);
+       if (host->dma_ch < 0) {
+               spin_unlock(&host->irq_lock);
                return;
+       }
 
        host->dma_sg_idx++;
        if (host->dma_sg_idx < host->dma_len) {
                /* Fire up the next transfer. */
-               omap_hsmmc_config_dma_params(host, host->data,
-                                          host->data->sg + host->dma_sg_idx);
+               omap_hsmmc_config_dma_params(host, data,
+                                          data->sg + host->dma_sg_idx);
+               spin_unlock(&host->irq_lock);
                return;
        }
 
-       omap_free_dma(host->dma_ch);
+       dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
+               omap_hsmmc_get_dma_dir(host, data));
+
+       req_in_progress = host->req_in_progress;
+       dma_ch = host->dma_ch;
        host->dma_ch = -1;
-       /*
-        * DMA Callback: run in interrupt context.
-        * mutex_unlock will throw a kernel warning if used.
-        */
-       up(&host->sem);
+       spin_unlock(&host->irq_lock);
+
+       omap_free_dma(dma_ch);
+
+       /* If DMA has finished after TC, complete the request */
+       if (!req_in_progress) {
+               struct mmc_request *mrq = host->mrq;
+
+               host->mrq = NULL;
+               mmc_request_done(host->mmc, mrq);
+       }
 }
 
 /*
@@ -1277,7 +1316,7 @@ static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *data)
 static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
                                        struct mmc_request *req)
 {
-       int dma_ch = 0, ret = 0, err = 1, i;
+       int dma_ch = 0, ret = 0, i;
        struct mmc_data *data = req->data;
 
        /* Sanity check: all the SG entries must be aligned by block size. */
@@ -1294,23 +1333,7 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
                 */
                return -EINVAL;
 
-       /*
-        * If for some reason the DMA transfer is still active,
-        * we wait for timeout period and free the dma
-        */
-       if (host->dma_ch != -1) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(100);
-               if (down_trylock(&host->sem)) {
-                       omap_free_dma(host->dma_ch);
-                       host->dma_ch = -1;
-                       up(&host->sem);
-                       return err;
-               }
-       } else {
-               if (down_trylock(&host->sem))
-                       return err;
-       }
+       BUG_ON(host->dma_ch != -1);
 
        ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data),
                               "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch);
@@ -1410,37 +1433,27 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
        struct omap_hsmmc_host *host = mmc_priv(mmc);
        int err;
 
-       /*
-        * Prevent races with the interrupt handler because of unexpected
-        * interrupts, but not if we are already in interrupt context i.e.
-        * retries.
-        */
-       if (!in_interrupt()) {
-               spin_lock_irqsave(&host->irq_lock, host->flags);
-               /*
-                * Protect the card from I/O if there is a possibility
-                * it can be removed.
-                */
-               if (host->protect_card) {
-                       if (host->reqs_blocked < 3) {
-                               /*
-                                * Ensure the controller is left in a consistent
-                                * state by resetting the command and data state
-                                * machines.
-                                */
-                               omap_hsmmc_reset_controller_fsm(host, SRD);
-                               omap_hsmmc_reset_controller_fsm(host, SRC);
-                               host->reqs_blocked += 1;
-                       }
-                       req->cmd->error = -EBADF;
-                       if (req->data)
-                               req->data->error = -EBADF;
-                       spin_unlock_irqrestore(&host->irq_lock, host->flags);
-                       mmc_request_done(mmc, req);
-                       return;
-               } else if (host->reqs_blocked)
-                       host->reqs_blocked = 0;
-       }
+       BUG_ON(host->req_in_progress);
+       BUG_ON(host->dma_ch != -1);
+       if (host->protect_card) {
+               if (host->reqs_blocked < 3) {
+                       /*
+                        * Ensure the controller is left in a consistent
+                        * state by resetting the command and data state
+                        * machines.
+                        */
+                       omap_hsmmc_reset_controller_fsm(host, SRD);
+                       omap_hsmmc_reset_controller_fsm(host, SRC);
+                       host->reqs_blocked += 1;
+               }
+               req->cmd->error = -EBADF;
+               if (req->data)
+                       req->data->error = -EBADF;
+               req->cmd->retries = 0;
+               mmc_request_done(mmc, req);
+               return;
+       } else if (host->reqs_blocked)
+               host->reqs_blocked = 0;
        WARN_ON(host->mrq != NULL);
        host->mrq = req;
        err = omap_hsmmc_prepare_data(host, req);
@@ -1449,8 +1462,6 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
                if (req->data)
                        req->data->error = err;
                host->mrq = NULL;
-               if (!in_interrupt())
-                       spin_unlock_irqrestore(&host->irq_lock, host->flags);
                mmc_request_done(mmc, req);
                return;
        }
@@ -2019,7 +2030,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
        mmc->f_min      = 400000;
        mmc->f_max      = 52000000;
 
-       sema_init(&host->sem, 1);
        spin_lock_init(&host->irq_lock);
 
        host->iclk = clk_get(&pdev->dev, "ick");
@@ -2162,8 +2172,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
                }
        }
 
-       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
-       OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
+       omap_hsmmc_disable_irq(host);
 
        mmc_host_lazy_disable(host->mmc);
 
@@ -2258,10 +2267,12 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int omap_hsmmc_suspend(struct platform_device *pdev, pm_message_t state)
+static int omap_hsmmc_suspend(struct device *dev)
 {
        int ret = 0;
+       struct platform_device *pdev = to_platform_device(dev);
        struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
+       pm_message_t state = PMSG_SUSPEND; /* unused by MMC core */
 
        if (host && host->suspended)
                return 0;
@@ -2281,12 +2292,9 @@ static int omap_hsmmc_suspend(struct platform_device *pdev, pm_message_t state)
                }
                cancel_work_sync(&host->mmc_carddetect_work);
                mmc_host_enable(host->mmc);
-               ret = mmc_suspend_host(host->mmc, state);
+               ret = mmc_suspend_host(host->mmc);
                if (ret == 0) {
-                       OMAP_HSMMC_WRITE(host->base, ISE, 0);
-                       OMAP_HSMMC_WRITE(host->base, IE, 0);
-
-
+                       omap_hsmmc_disable_irq(host);
                        OMAP_HSMMC_WRITE(host->base, HCTL,
                                OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
                        mmc_host_disable(host->mmc);
@@ -2310,9 +2318,10 @@ static int omap_hsmmc_suspend(struct platform_device *pdev, pm_message_t state)
 }
 
 /* Routine to resume the MMC device */
-static int omap_hsmmc_resume(struct platform_device *pdev)
+static int omap_hsmmc_resume(struct device *dev)
 {
        int ret = 0;
+       struct platform_device *pdev = to_platform_device(dev);
        struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
 
        if (host && !host->suspended)
@@ -2363,13 +2372,17 @@ clk_en_err:
 #define omap_hsmmc_resume              NULL
 #endif
 
-static struct platform_driver omap_hsmmc_driver = {
-       .remove         = omap_hsmmc_remove,
+static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
        .suspend        = omap_hsmmc_suspend,
        .resume         = omap_hsmmc_resume,
+};
+
+static struct platform_driver omap_hsmmc_driver = {
+       .remove         = omap_hsmmc_remove,
        .driver         = {
                .name = DRIVER_NAME,
                .owner = THIS_MODULE,
+               .pm = &omap_hsmmc_dev_pm_ops,
        },
 };
 
index e4f00e70a749db8fb88aefc6ac580df99b4769ff..0a4e43f371408733f43ba9fae73be7647222b5b6 100644 (file)
@@ -813,7 +813,7 @@ static int pxamci_suspend(struct device *dev)
        int ret = 0;
 
        if (mmc)
-               ret = mmc_suspend_host(mmc, PMSG_SUSPEND);
+               ret = mmc_suspend_host(mmc);
 
        return ret;
 }
index 2fdf7689ae6c3a2bdb2c876f0299b2c7e9009edf..2e16e0a90a5e1a5d8d3d7487727baa39d701b8fb 100644 (file)
@@ -1881,9 +1881,8 @@ MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids);
 static int s3cmci_suspend(struct device *dev)
 {
        struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev));
-       struct pm_message event = { PM_EVENT_SUSPEND };
 
-       return mmc_suspend_host(mmc, event);
+       return mmc_suspend_host(mmc);
 }
 
 static int s3cmci_resume(struct device *dev)
index 7802a543d8fcec497e451b5072510d4c58163c53..a2e9820cd42f75e9de5942eb4ef7c0f37cbc0db5 100644 (file)
@@ -89,7 +89,7 @@ static int sdhci_of_suspend(struct of_device *ofdev, pm_message_t state)
 {
        struct sdhci_host *host = dev_get_drvdata(&ofdev->dev);
 
-       return mmc_suspend_host(host->mmc, state);
+       return mmc_suspend_host(host->mmc);
 }
 
 static int sdhci_of_resume(struct of_device *ofdev)
index d5b11a17e64805c7e5e8531d192afdd0230a1805..c8623de13af33d1b44cc701b1a52eb4ea13dda26 100644 (file)
@@ -129,12 +129,12 @@ struct sdhci_of_data sdhci_esdhc = {
                  SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
                  SDHCI_QUIRK_NO_CARD_NO_RESET,
        .ops = {
-               .readl = sdhci_be32bs_readl,
-               .readw = esdhc_readw,
-               .readb = sdhci_be32bs_readb,
-               .writel = sdhci_be32bs_writel,
-               .writew = esdhc_writew,
-               .writeb = esdhc_writeb,
+               .read_l = sdhci_be32bs_readl,
+               .read_w = esdhc_readw,
+               .read_b = sdhci_be32bs_readb,
+               .write_l = sdhci_be32bs_writel,
+               .write_w = esdhc_writew,
+               .write_b = esdhc_writeb,
                .set_clock = esdhc_set_clock,
                .enable_dma = esdhc_enable_dma,
                .get_max_clock = esdhc_get_max_clock,
index 35117f3ed7576fe79a5e6f9263fdcc951f806d7e..68ddb7546ae238e2064efe320baeadca698f1922 100644 (file)
@@ -55,11 +55,11 @@ struct sdhci_of_data sdhci_hlwd = {
        .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
                  SDHCI_QUIRK_32BIT_DMA_SIZE,
        .ops = {
-               .readl = sdhci_be32bs_readl,
-               .readw = sdhci_be32bs_readw,
-               .readb = sdhci_be32bs_readb,
-               .writel = sdhci_hlwd_writel,
-               .writew = sdhci_hlwd_writew,
-               .writeb = sdhci_hlwd_writeb,
+               .read_l = sdhci_be32bs_readl,
+               .read_w = sdhci_be32bs_readw,
+               .read_b = sdhci_be32bs_readb,
+               .write_l = sdhci_hlwd_writel,
+               .write_w = sdhci_hlwd_writew,
+               .write_b = sdhci_hlwd_writeb,
        },
 };
index 6701af629c30e3b8c0fb86c606f546cddf7519b7..65483fdea45b56ba431bd5a37a3891bdeed708c8 100644 (file)
@@ -628,7 +628,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
        host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot));
        if (IS_ERR(host)) {
                dev_err(&pdev->dev, "cannot allocate host\n");
-               return ERR_PTR(PTR_ERR(host));
+               return ERR_CAST(host);
        }
 
        slot = sdhci_priv(host);
index 297f40ae6ad5623f2695c16c4a5db4886931b791..b6ee0d71969898257cf625b6b21cc37b3426a9f6 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mmc/host.h>
 
 #include <linux/io.h>
+#include <linux/sdhci-pltfm.h>
 
 #include "sdhci.h"
 
@@ -49,19 +50,18 @@ static struct sdhci_ops sdhci_pltfm_ops = {
 
 static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
 {
+       struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
        struct sdhci_host *host;
        struct resource *iomem;
        int ret;
 
-       BUG_ON(pdev == NULL);
-
        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!iomem) {
                ret = -ENOMEM;
                goto err;
        }
 
-       if (resource_size(iomem) != 0x100)
+       if (resource_size(iomem) < 0x100)
                dev_err(&pdev->dev, "Invalid iomem size. You may "
                        "experience problems.\n");
 
@@ -76,7 +76,12 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
        }
 
        host->hw_name = "platform";
-       host->ops = &sdhci_pltfm_ops;
+       if (pdata && pdata->ops)
+               host->ops = pdata->ops;
+       else
+               host->ops = &sdhci_pltfm_ops;
+       if (pdata)
+               host->quirks = pdata->quirks;
        host->irq = platform_get_irq(pdev, 0);
 
        if (!request_mem_region(iomem->start, resource_size(iomem),
@@ -93,6 +98,12 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
                goto err_remap;
        }
 
+       if (pdata && pdata->init) {
+               ret = pdata->init(host);
+               if (ret)
+                       goto err_plat_init;
+       }
+
        ret = sdhci_add_host(host);
        if (ret)
                goto err_add_host;
@@ -102,6 +113,9 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
        return 0;
 
 err_add_host:
+       if (pdata && pdata->exit)
+               pdata->exit(host);
+err_plat_init:
        iounmap(host->ioaddr);
 err_remap:
        release_mem_region(iomem->start, resource_size(iomem));
@@ -114,6 +128,7 @@ err:
 
 static int __devexit sdhci_pltfm_remove(struct platform_device *pdev)
 {
+       struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
        struct sdhci_host *host = platform_get_drvdata(pdev);
        struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        int dead;
@@ -125,6 +140,8 @@ static int __devexit sdhci_pltfm_remove(struct platform_device *pdev)
                dead = 1;
 
        sdhci_remove_host(host, dead);
+       if (pdata && pdata->exit)
+               pdata->exit(host);
        iounmap(host->ioaddr);
        release_mem_region(iomem->start, resource_size(iomem));
        sdhci_free_host(host);
@@ -165,4 +182,3 @@ MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver");
 MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:sdhci");
-
index 2136794c0cfaf66fed55c5433f8e4bc574e19604..af217924a76eb94511fddf7789d5d1a458a2c21b 100644 (file)
@@ -317,12 +317,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        host->irq = irq;
 
        /* Setup quirks for the controller */
-
-       /* Currently with ADMA enabled we are getting some length
-        * interrupts that are not being dealt with, do disable
-        * ADMA until this is sorted out. */
-       host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
-       host->quirks |= SDHCI_QUIRK_32BIT_ADMA_SIZE;
+       host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
 
 #ifndef CONFIG_MMC_SDHCI_S3C_DMA
 
@@ -330,9 +325,6 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
         * support as well. */
        host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
 
-       /* PIO currently has problems with multi-block IO */
-       host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK;
-
 #endif /* CONFIG_MMC_SDHCI_S3C_DMA */
 
        /* It seems we do not get an DATA transfer complete on non-busy
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
new file mode 100644 (file)
index 0000000..d70c54c
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * drivers/mmc/host/sdhci-spear.c
+ *
+ * Support of SDHCI platform devices for spear soc family
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Viresh Kumar<viresh.kumar@st.com>
+ *
+ * Inspired by sdhci-pltfm.c
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdhci-spear.h>
+#include <linux/io.h>
+#include "sdhci.h"
+
+struct spear_sdhci {
+       struct clk *clk;
+       struct sdhci_plat_data *data;
+};
+
+/* sdhci ops */
+static struct sdhci_ops sdhci_pltfm_ops = {
+       /* Nothing to do for now. */
+};
+
+/* gpio card detection interrupt handler */
+static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id)
+{
+       struct platform_device *pdev = dev_id;
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev);
+       unsigned long gpio_irq_type;
+       int val;
+
+       val = gpio_get_value(sdhci->data->card_int_gpio);
+
+       /* val == 1 -> card removed, val == 0 -> card inserted */
+       /* if card removed - set irq for low level, else vice versa */
+       gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH;
+       set_irq_type(irq, gpio_irq_type);
+
+       if (sdhci->data->card_power_gpio >= 0) {
+               if (!sdhci->data->power_always_enb) {
+                       /* if card inserted, give power, otherwise remove it */
+                       val = sdhci->data->power_active_high ? !val : val ;
+                       gpio_set_value(sdhci->data->card_power_gpio, val);
+               }
+       }
+
+       /* inform sdhci driver about card insertion/removal */
+       tasklet_schedule(&host->card_tasklet);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit sdhci_probe(struct platform_device *pdev)
+{
+       struct sdhci_host *host;
+       struct resource *iomem;
+       struct spear_sdhci *sdhci;
+       int ret;
+
+       BUG_ON(pdev == NULL);
+
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!iomem) {
+               ret = -ENOMEM;
+               dev_dbg(&pdev->dev, "memory resource not defined\n");
+               goto err;
+       }
+
+       if (!request_mem_region(iomem->start, resource_size(iomem),
+                               "spear-sdhci")) {
+               ret = -EBUSY;
+               dev_dbg(&pdev->dev, "cannot request region\n");
+               goto err;
+       }
+
+       sdhci = kzalloc(sizeof(*sdhci), GFP_KERNEL);
+       if (!sdhci) {
+               ret = -ENOMEM;
+               dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n");
+               goto err_kzalloc;
+       }
+
+       /* clk enable */
+       sdhci->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(sdhci->clk)) {
+               ret = PTR_ERR(sdhci->clk);
+               dev_dbg(&pdev->dev, "Error getting clock\n");
+               goto err_clk_get;
+       }
+
+       ret = clk_enable(sdhci->clk);
+       if (ret) {
+               dev_dbg(&pdev->dev, "Error enabling clock\n");
+               goto err_clk_enb;
+       }
+
+       /* overwrite platform_data */
+       sdhci->data = dev_get_platdata(&pdev->dev);
+       pdev->dev.platform_data = sdhci;
+
+       if (pdev->dev.parent)
+               host = sdhci_alloc_host(pdev->dev.parent, 0);
+       else
+               host = sdhci_alloc_host(&pdev->dev, 0);
+
+       if (IS_ERR(host)) {
+               ret = PTR_ERR(host);
+               dev_dbg(&pdev->dev, "error allocating host\n");
+               goto err_alloc_host;
+       }
+
+       host->hw_name = "sdhci";
+       host->ops = &sdhci_pltfm_ops;
+       host->irq = platform_get_irq(pdev, 0);
+       host->quirks = SDHCI_QUIRK_BROKEN_ADMA;
+
+       host->ioaddr = ioremap(iomem->start, resource_size(iomem));
+       if (!host->ioaddr) {
+               ret = -ENOMEM;
+               dev_dbg(&pdev->dev, "failed to remap registers\n");
+               goto err_ioremap;
+       }
+
+       ret = sdhci_add_host(host);
+       if (ret) {
+               dev_dbg(&pdev->dev, "error adding host\n");
+               goto err_add_host;
+       }
+
+       platform_set_drvdata(pdev, host);
+
+       /*
+        * It is optional to use GPIOs for sdhci Power control & sdhci card
+        * interrupt detection. If sdhci->data is NULL, then use original sdhci
+        * lines otherwise GPIO lines.
+        * If GPIO is selected for power control, then power should be disabled
+        * after card removal and should be enabled when card insertion
+        * interrupt occurs
+        */
+       if (!sdhci->data)
+               return 0;
+
+       if (sdhci->data->card_power_gpio >= 0) {
+               int val = 0;
+
+               ret = gpio_request(sdhci->data->card_power_gpio, "sdhci");
+               if (ret < 0) {
+                       dev_dbg(&pdev->dev, "gpio request fail: %d\n",
+                                       sdhci->data->card_power_gpio);
+                       goto err_pgpio_request;
+               }
+
+               if (sdhci->data->power_always_enb)
+                       val = sdhci->data->power_active_high;
+               else
+                       val = !sdhci->data->power_active_high;
+
+               ret = gpio_direction_output(sdhci->data->card_power_gpio, val);
+               if (ret) {
+                       dev_dbg(&pdev->dev, "gpio set direction fail: %d\n",
+                                       sdhci->data->card_power_gpio);
+                       goto err_pgpio_direction;
+               }
+
+               gpio_set_value(sdhci->data->card_power_gpio, 1);
+       }
+
+       if (sdhci->data->card_int_gpio >= 0) {
+               ret = gpio_request(sdhci->data->card_int_gpio, "sdhci");
+               if (ret < 0) {
+                       dev_dbg(&pdev->dev, "gpio request fail: %d\n",
+                                       sdhci->data->card_int_gpio);
+                       goto err_igpio_request;
+               }
+
+               ret = gpio_direction_input(sdhci->data->card_int_gpio);
+               if (ret) {
+                       dev_dbg(&pdev->dev, "gpio set direction fail: %d\n",
+                                       sdhci->data->card_int_gpio);
+                       goto err_igpio_direction;
+               }
+               ret = request_irq(gpio_to_irq(sdhci->data->card_int_gpio),
+                               sdhci_gpio_irq, IRQF_TRIGGER_LOW,
+                               mmc_hostname(host->mmc), pdev);
+               if (ret) {
+                       dev_dbg(&pdev->dev, "gpio request irq fail: %d\n",
+                                       sdhci->data->card_int_gpio);
+                       goto err_igpio_request_irq;
+               }
+
+       }
+
+       return 0;
+
+err_igpio_request_irq:
+err_igpio_direction:
+       if (sdhci->data->card_int_gpio >= 0)
+               gpio_free(sdhci->data->card_int_gpio);
+err_igpio_request:
+err_pgpio_direction:
+       if (sdhci->data->card_power_gpio >= 0)
+               gpio_free(sdhci->data->card_power_gpio);
+err_pgpio_request:
+       platform_set_drvdata(pdev, NULL);
+       sdhci_remove_host(host, 1);
+err_add_host:
+       iounmap(host->ioaddr);
+err_ioremap:
+       sdhci_free_host(host);
+err_alloc_host:
+       clk_disable(sdhci->clk);
+err_clk_enb:
+       clk_put(sdhci->clk);
+err_clk_get:
+       kfree(sdhci);
+err_kzalloc:
+       release_mem_region(iomem->start, resource_size(iomem));
+err:
+       dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret);
+       return ret;
+}
+
+static int __devexit sdhci_remove(struct platform_device *pdev)
+{
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev);
+       int dead;
+       u32 scratch;
+
+       if (sdhci->data) {
+               if (sdhci->data->card_int_gpio >= 0) {
+                       free_irq(gpio_to_irq(sdhci->data->card_int_gpio), pdev);
+                       gpio_free(sdhci->data->card_int_gpio);
+               }
+
+               if (sdhci->data->card_power_gpio >= 0)
+                       gpio_free(sdhci->data->card_power_gpio);
+       }
+
+       platform_set_drvdata(pdev, NULL);
+       dead = 0;
+       scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
+       if (scratch == (u32)-1)
+               dead = 1;
+
+       sdhci_remove_host(host, dead);
+       iounmap(host->ioaddr);
+       sdhci_free_host(host);
+       clk_disable(sdhci->clk);
+       clk_put(sdhci->clk);
+       kfree(sdhci);
+       if (iomem)
+               release_mem_region(iomem->start, resource_size(iomem));
+
+       return 0;
+}
+
+static struct platform_driver sdhci_driver = {
+       .driver = {
+               .name   = "sdhci",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = sdhci_probe,
+       .remove         = __devexit_p(sdhci_remove),
+};
+
+static int __init sdhci_init(void)
+{
+       return platform_driver_register(&sdhci_driver);
+}
+module_init(sdhci_init);
+
+static void __exit sdhci_exit(void)
+{
+       platform_driver_unregister(&sdhci_driver);
+}
+module_exit(sdhci_exit);
+
+MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver");
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_LICENSE("GPL v2");
index 9d4fdfa685e57521a711c29904c100a66df4cd48..c6d1bd8d4ac43d917e2772f2242dcdea03aa6040 100644 (file)
@@ -496,12 +496,22 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
        }
 
-       /*
-        * Add a terminating entry.
-        */
+       if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
+               /*
+               * Mark the last descriptor as the terminating descriptor
+               */
+               if (desc != host->adma_desc) {
+                       desc -= 8;
+                       desc[0] |= 0x2; /* end */
+               }
+       } else {
+               /*
+               * Add a terminating entry.
+               */
 
-       /* nop, end, valid */
-       sdhci_set_adma_desc(desc, 0, 0, 0x3);
+               /* nop, end, valid */
+               sdhci_set_adma_desc(desc, 0, 0, 0x3);
+       }
 
        /*
         * Resync align buffer as we might have changed it.
@@ -1587,7 +1597,7 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
 
        sdhci_disable_card_detection(host);
 
-       ret = mmc_suspend_host(host->mmc, state);
+       ret = mmc_suspend_host(host->mmc);
        if (ret)
                return ret;
 
@@ -1744,7 +1754,8 @@ int sdhci_add_host(struct sdhci_host *host)
        host->max_clk =
                (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
        host->max_clk *= 1000000;
-       if (host->max_clk == 0) {
+       if (host->max_clk == 0 || host->quirks &
+                       SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
                if (!host->ops->get_max_clock) {
                        printk(KERN_ERR
                               "%s: Hardware doesn't specify base clock "
index 842f46f9428469657679e45c1b5b1dc8097c694f..c8468134adc95db0dbfd5ec901ebf96930c22b84 100644 (file)
 #define  SDHCI_INT_DATA_MASK   (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
                SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
                SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
-               SDHCI_INT_DATA_END_BIT | SDHCI_ADMA_ERROR)
+               SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
 #define SDHCI_INT_ALL_MASK     ((unsigned int)-1)
 
 #define SDHCI_ACMD12_ERR       0x3C
@@ -236,6 +236,10 @@ struct sdhci_host {
 #define SDHCI_QUIRK_DELAY_AFTER_POWER                  (1<<23)
 /* Controller uses SDCLK instead of TMCLK for data timeouts */
 #define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK            (1<<24)
+/* Controller reports wrong base clock capability */
+#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN              (1<<25)
+/* Controller cannot support End Attribute in NOP ADMA descriptor */
+#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC              (1<<26)
 
        int                     irq;            /* Device IRQ */
        void __iomem *          ioaddr;         /* Mapped address */
@@ -294,12 +298,12 @@ struct sdhci_host {
 
 struct sdhci_ops {
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-       u32             (*readl)(struct sdhci_host *host, int reg);
-       u16             (*readw)(struct sdhci_host *host, int reg);
-       u8              (*readb)(struct sdhci_host *host, int reg);
-       void            (*writel)(struct sdhci_host *host, u32 val, int reg);
-       void            (*writew)(struct sdhci_host *host, u16 val, int reg);
-       void            (*writeb)(struct sdhci_host *host, u8 val, int reg);
+       u32             (*read_l)(struct sdhci_host *host, int reg);
+       u16             (*read_w)(struct sdhci_host *host, int reg);
+       u8              (*read_b)(struct sdhci_host *host, int reg);
+       void            (*write_l)(struct sdhci_host *host, u32 val, int reg);
+       void            (*write_w)(struct sdhci_host *host, u16 val, int reg);
+       void            (*write_b)(struct sdhci_host *host, u8 val, int reg);
 #endif
 
        void    (*set_clock)(struct sdhci_host *host, unsigned int clock);
@@ -314,48 +318,48 @@ struct sdhci_ops {
 
 static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg)
 {
-       if (unlikely(host->ops->writel))
-               host->ops->writel(host, val, reg);
+       if (unlikely(host->ops->write_l))
+               host->ops->write_l(host, val, reg);
        else
                writel(val, host->ioaddr + reg);
 }
 
 static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg)
 {
-       if (unlikely(host->ops->writew))
-               host->ops->writew(host, val, reg);
+       if (unlikely(host->ops->write_w))
+               host->ops->write_w(host, val, reg);
        else
                writew(val, host->ioaddr + reg);
 }
 
 static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
 {
-       if (unlikely(host->ops->writeb))
-               host->ops->writeb(host, val, reg);
+       if (unlikely(host->ops->write_b))
+               host->ops->write_b(host, val, reg);
        else
                writeb(val, host->ioaddr + reg);
 }
 
 static inline u32 sdhci_readl(struct sdhci_host *host, int reg)
 {
-       if (unlikely(host->ops->readl))
-               return host->ops->readl(host, reg);
+       if (unlikely(host->ops->read_l))
+               return host->ops->read_l(host, reg);
        else
                return readl(host->ioaddr + reg);
 }
 
 static inline u16 sdhci_readw(struct sdhci_host *host, int reg)
 {
-       if (unlikely(host->ops->readw))
-               return host->ops->readw(host, reg);
+       if (unlikely(host->ops->read_w))
+               return host->ops->read_w(host, reg);
        else
                return readw(host->ioaddr + reg);
 }
 
 static inline u8 sdhci_readb(struct sdhci_host *host, int reg)
 {
-       if (unlikely(host->ops->readb))
-               return host->ops->readb(host, reg);
+       if (unlikely(host->ops->read_b))
+               return host->ops->read_b(host, reg);
        else
                return readb(host->ioaddr + reg);
 }
index cb41e9c3ac07cce58a2d96c00bff6cda57ec5c55..e7507af3856e24c9cfef86443e6f5a2cc30ac47c 100644 (file)
@@ -519,7 +519,7 @@ static int sdricoh_pcmcia_suspend(struct pcmcia_device *link)
 {
        struct mmc_host *mmc = link->priv;
        dev_dbg(&link->dev, "suspend\n");
-       mmc_suspend_host(mmc, PMSG_SUSPEND);
+       mmc_suspend_host(mmc);
        return 0;
 }
 
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
new file mode 100644 (file)
index 0000000..eb97830
--- /dev/null
@@ -0,0 +1,965 @@
+/*
+ * MMCIF eMMC driver.
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ * Yusuke Goda <yusuke.goda.sx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ *
+ * TODO
+ *  1. DMA
+ *  2. Power management
+ *  3. Handle MMC errors better
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/mmc/sh_mmcif.h>
+
+#define DRIVER_NAME    "sh_mmcif"
+#define DRIVER_VERSION "2010-04-28"
+
+#define MMCIF_CE_CMD_SET       0x00000000
+#define MMCIF_CE_ARG           0x00000008
+#define MMCIF_CE_ARG_CMD12     0x0000000C
+#define MMCIF_CE_CMD_CTRL      0x00000010
+#define MMCIF_CE_BLOCK_SET     0x00000014
+#define MMCIF_CE_CLK_CTRL      0x00000018
+#define MMCIF_CE_BUF_ACC       0x0000001C
+#define MMCIF_CE_RESP3         0x00000020
+#define MMCIF_CE_RESP2         0x00000024
+#define MMCIF_CE_RESP1         0x00000028
+#define MMCIF_CE_RESP0         0x0000002C
+#define MMCIF_CE_RESP_CMD12    0x00000030
+#define MMCIF_CE_DATA          0x00000034
+#define MMCIF_CE_INT           0x00000040
+#define MMCIF_CE_INT_MASK      0x00000044
+#define MMCIF_CE_HOST_STS1     0x00000048
+#define MMCIF_CE_HOST_STS2     0x0000004C
+#define MMCIF_CE_VERSION       0x0000007C
+
+/* CE_CMD_SET */
+#define CMD_MASK               0x3f000000
+#define CMD_SET_RTYP_NO                ((0 << 23) | (0 << 22))
+#define CMD_SET_RTYP_6B                ((0 << 23) | (1 << 22)) /* R1/R1b/R3/R4/R5 */
+#define CMD_SET_RTYP_17B       ((1 << 23) | (0 << 22)) /* R2 */
+#define CMD_SET_RBSY           (1 << 21) /* R1b */
+#define CMD_SET_CCSEN          (1 << 20)
+#define CMD_SET_WDAT           (1 << 19) /* 1: on data, 0: no data */
+#define CMD_SET_DWEN           (1 << 18) /* 1: write, 0: read */
+#define CMD_SET_CMLTE          (1 << 17) /* 1: multi block trans, 0: single */
+#define CMD_SET_CMD12EN                (1 << 16) /* 1: CMD12 auto issue */
+#define CMD_SET_RIDXC_INDEX    ((0 << 15) | (0 << 14)) /* index check */
+#define CMD_SET_RIDXC_BITS     ((0 << 15) | (1 << 14)) /* check bits check */
+#define CMD_SET_RIDXC_NO       ((1 << 15) | (0 << 14)) /* no check */
+#define CMD_SET_CRC7C          ((0 << 13) | (0 << 12)) /* CRC7 check*/
+#define CMD_SET_CRC7C_BITS     ((0 << 13) | (1 << 12)) /* check bits check*/
+#define CMD_SET_CRC7C_INTERNAL ((1 << 13) | (0 << 12)) /* internal CRC7 check*/
+#define CMD_SET_CRC16C         (1 << 10) /* 0: CRC16 check*/
+#define CMD_SET_CRCSTE         (1 << 8) /* 1: not receive CRC status */
+#define CMD_SET_TBIT           (1 << 7) /* 1: tran mission bit "Low" */
+#define CMD_SET_OPDM           (1 << 6) /* 1: open/drain */
+#define CMD_SET_CCSH           (1 << 5)
+#define CMD_SET_DATW_1         ((0 << 1) | (0 << 0)) /* 1bit */
+#define CMD_SET_DATW_4         ((0 << 1) | (1 << 0)) /* 4bit */
+#define CMD_SET_DATW_8         ((1 << 1) | (0 << 0)) /* 8bit */
+
+/* CE_CMD_CTRL */
+#define CMD_CTRL_BREAK         (1 << 0)
+
+/* CE_BLOCK_SET */
+#define BLOCK_SIZE_MASK                0x0000ffff
+
+/* CE_CLK_CTRL */
+#define CLK_ENABLE             (1 << 24) /* 1: output mmc clock */
+#define CLK_CLEAR              ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
+#define CLK_SUP_PCLK           ((1 << 19) | (1 << 18) | (1 << 17) | (1 << 16))
+#define SRSPTO_256             ((1 << 13) | (0 << 12)) /* resp timeout */
+#define SRBSYTO_29             ((1 << 11) | (1 << 10) |        \
+                                (1 << 9) | (1 << 8)) /* resp busy timeout */
+#define SRWDTO_29              ((1 << 7) | (1 << 6) |          \
+                                (1 << 5) | (1 << 4)) /* read/write timeout */
+#define SCCSTO_29              ((1 << 3) | (1 << 2) |          \
+                                (1 << 1) | (1 << 0)) /* ccs timeout */
+
+/* CE_BUF_ACC */
+#define BUF_ACC_DMAWEN         (1 << 25)
+#define BUF_ACC_DMAREN         (1 << 24)
+#define BUF_ACC_BUSW_32                (0 << 17)
+#define BUF_ACC_BUSW_16                (1 << 17)
+#define BUF_ACC_ATYP           (1 << 16)
+
+/* CE_INT */
+#define INT_CCSDE              (1 << 29)
+#define INT_CMD12DRE           (1 << 26)
+#define INT_CMD12RBE           (1 << 25)
+#define INT_CMD12CRE           (1 << 24)
+#define INT_DTRANE             (1 << 23)
+#define INT_BUFRE              (1 << 22)
+#define INT_BUFWEN             (1 << 21)
+#define INT_BUFREN             (1 << 20)
+#define INT_CCSRCV             (1 << 19)
+#define INT_RBSYE              (1 << 17)
+#define INT_CRSPE              (1 << 16)
+#define INT_CMDVIO             (1 << 15)
+#define INT_BUFVIO             (1 << 14)
+#define INT_WDATERR            (1 << 11)
+#define INT_RDATERR            (1 << 10)
+#define INT_RIDXERR            (1 << 9)
+#define INT_RSPERR             (1 << 8)
+#define INT_CCSTO              (1 << 5)
+#define INT_CRCSTO             (1 << 4)
+#define INT_WDATTO             (1 << 3)
+#define INT_RDATTO             (1 << 2)
+#define INT_RBSYTO             (1 << 1)
+#define INT_RSPTO              (1 << 0)
+#define INT_ERR_STS            (INT_CMDVIO | INT_BUFVIO | INT_WDATERR |  \
+                                INT_RDATERR | INT_RIDXERR | INT_RSPERR | \
+                                INT_CCSTO | INT_CRCSTO | INT_WDATTO |    \
+                                INT_RDATTO | INT_RBSYTO | INT_RSPTO)
+
+/* CE_INT_MASK */
+#define MASK_ALL               0x00000000
+#define MASK_MCCSDE            (1 << 29)
+#define MASK_MCMD12DRE         (1 << 26)
+#define MASK_MCMD12RBE         (1 << 25)
+#define MASK_MCMD12CRE         (1 << 24)
+#define MASK_MDTRANE           (1 << 23)
+#define MASK_MBUFRE            (1 << 22)
+#define MASK_MBUFWEN           (1 << 21)
+#define MASK_MBUFREN           (1 << 20)
+#define MASK_MCCSRCV           (1 << 19)
+#define MASK_MRBSYE            (1 << 17)
+#define MASK_MCRSPE            (1 << 16)
+#define MASK_MCMDVIO           (1 << 15)
+#define MASK_MBUFVIO           (1 << 14)
+#define MASK_MWDATERR          (1 << 11)
+#define MASK_MRDATERR          (1 << 10)
+#define MASK_MRIDXERR          (1 << 9)
+#define MASK_MRSPERR           (1 << 8)
+#define MASK_MCCSTO            (1 << 5)
+#define MASK_MCRCSTO           (1 << 4)
+#define MASK_MWDATTO           (1 << 3)
+#define MASK_MRDATTO           (1 << 2)
+#define MASK_MRBSYTO           (1 << 1)
+#define MASK_MRSPTO            (1 << 0)
+
+/* CE_HOST_STS1 */
+#define STS1_CMDSEQ            (1 << 31)
+
+/* CE_HOST_STS2 */
+#define STS2_CRCSTE            (1 << 31)
+#define STS2_CRC16E            (1 << 30)
+#define STS2_AC12CRCE          (1 << 29)
+#define STS2_RSPCRC7E          (1 << 28)
+#define STS2_CRCSTEBE          (1 << 27)
+#define STS2_RDATEBE           (1 << 26)
+#define STS2_AC12REBE          (1 << 25)
+#define STS2_RSPEBE            (1 << 24)
+#define STS2_AC12IDXE          (1 << 23)
+#define STS2_RSPIDXE           (1 << 22)
+#define STS2_CCSTO             (1 << 15)
+#define STS2_RDATTO            (1 << 14)
+#define STS2_DATBSYTO          (1 << 13)
+#define STS2_CRCSTTO           (1 << 12)
+#define STS2_AC12BSYTO         (1 << 11)
+#define STS2_RSPBSYTO          (1 << 10)
+#define STS2_AC12RSPTO         (1 << 9)
+#define STS2_RSPTO             (1 << 8)
+#define STS2_CRC_ERR           (STS2_CRCSTE | STS2_CRC16E |            \
+                                STS2_AC12CRCE | STS2_RSPCRC7E | STS2_CRCSTEBE)
+#define STS2_TIMEOUT_ERR       (STS2_CCSTO | STS2_RDATTO |             \
+                                STS2_DATBSYTO | STS2_CRCSTTO |         \
+                                STS2_AC12BSYTO | STS2_RSPBSYTO |       \
+                                STS2_AC12RSPTO | STS2_RSPTO)
+
+/* CE_VERSION */
+#define SOFT_RST_ON            (1 << 31)
+#define SOFT_RST_OFF           (0 << 31)
+
+#define CLKDEV_EMMC_DATA       52000000 /* 52MHz */
+#define CLKDEV_MMC_DATA                20000000 /* 20MHz */
+#define CLKDEV_INIT            400000   /* 400 KHz */
+
+struct sh_mmcif_host {
+       struct mmc_host *mmc;
+       struct mmc_data *data;
+       struct mmc_command *cmd;
+       struct platform_device *pd;
+       struct clk *hclk;
+       unsigned int clk;
+       int bus_width;
+       u16 wait_int;
+       u16 sd_error;
+       long timeout;
+       void __iomem *addr;
+       wait_queue_head_t intr_wait;
+};
+
+static inline u32 sh_mmcif_readl(struct sh_mmcif_host *host, unsigned int reg)
+{
+       return readl(host->addr + reg);
+}
+
+static inline void sh_mmcif_writel(struct sh_mmcif_host *host,
+                                       unsigned int reg, u32 val)
+{
+       writel(val, host->addr + reg);
+}
+
+static inline void sh_mmcif_bitset(struct sh_mmcif_host *host,
+                                       unsigned int reg, u32 val)
+{
+       writel(val | sh_mmcif_readl(host, reg), host->addr + reg);
+}
+
+static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host,
+                                       unsigned int reg, u32 val)
+{
+       writel(~val & sh_mmcif_readl(host, reg), host->addr + reg);
+}
+
+
+static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
+{
+       struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+
+       sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
+       sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR);
+
+       if (!clk)
+               return;
+       if (p->sup_pclk && clk == host->clk)
+               sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
+       else
+               sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR &
+                       (ilog2(__rounddown_pow_of_two(host->clk / clk)) << 16));
+
+       sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
+}
+
+static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
+{
+       u32 tmp;
+
+       tmp = 0x010f0000 & sh_mmcif_readl(host, MMCIF_CE_CLK_CTRL);
+
+       sh_mmcif_writel(host, MMCIF_CE_VERSION, SOFT_RST_ON);
+       sh_mmcif_writel(host, MMCIF_CE_VERSION, SOFT_RST_OFF);
+       sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp |
+               SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29);
+       /* byte swap on */
+       sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_ATYP);
+}
+
+static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
+{
+       u32 state1, state2;
+       int ret, timeout = 10000000;
+
+       host->sd_error = 0;
+       host->wait_int = 0;
+
+       state1 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS1);
+       state2 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS2);
+       pr_debug("%s: ERR HOST_STS1 = %08x\n", \
+                       DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS1));
+       pr_debug("%s: ERR HOST_STS2 = %08x\n", \
+                       DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS2));
+
+       if (state1 & STS1_CMDSEQ) {
+               sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
+               sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK);
+               while (1) {
+                       timeout--;
+                       if (timeout < 0) {
+                               pr_err(DRIVER_NAME": Forceed end of " \
+                                       "command sequence timeout err\n");
+                               return -EIO;
+                       }
+                       if (!(sh_mmcif_readl(host, MMCIF_CE_HOST_STS1)
+                                                               & STS1_CMDSEQ))
+                               break;
+                       mdelay(1);
+               }
+               sh_mmcif_sync_reset(host);
+               pr_debug(DRIVER_NAME": Forced end of command sequence\n");
+               return -EIO;
+       }
+
+       if (state2 & STS2_CRC_ERR) {
+               pr_debug(DRIVER_NAME": Happened CRC error\n");
+               ret = -EIO;
+       } else if (state2 & STS2_TIMEOUT_ERR) {
+               pr_debug(DRIVER_NAME": Happened Timeout error\n");
+               ret = -ETIMEDOUT;
+       } else {
+               pr_debug(DRIVER_NAME": Happened End/Index error\n");
+               ret = -EIO;
+       }
+       return ret;
+}
+
+static int sh_mmcif_single_read(struct sh_mmcif_host *host,
+                                       struct mmc_request *mrq)
+{
+       struct mmc_data *data = mrq->data;
+       long time;
+       u32 blocksize, i, *p = sg_virt(data->sg);
+
+       host->wait_int = 0;
+
+       /* buf read enable */
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
+       time = wait_event_interruptible_timeout(host->intr_wait,
+                       host->wait_int == 1 ||
+                       host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+               return sh_mmcif_error_manage(host);
+
+       host->wait_int = 0;
+       blocksize = (BLOCK_SIZE_MASK &
+                       sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3;
+       for (i = 0; i < blocksize / 4; i++)
+               *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA);
+
+       /* buffer read end */
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
+       time = wait_event_interruptible_timeout(host->intr_wait,
+                       host->wait_int == 1 ||
+                       host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+               return sh_mmcif_error_manage(host);
+
+       host->wait_int = 0;
+       return 0;
+}
+
+static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
+                                       struct mmc_request *mrq)
+{
+       struct mmc_data *data = mrq->data;
+       long time;
+       u32 blocksize, i, j, sec, *p;
+
+       blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET);
+       for (j = 0; j < data->sg_len; j++) {
+               p = sg_virt(data->sg);
+               host->wait_int = 0;
+               for (sec = 0; sec < data->sg->length / blocksize; sec++) {
+                       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
+                       /* buf read enable */
+                       time = wait_event_interruptible_timeout(host->intr_wait,
+                               host->wait_int == 1 ||
+                               host->sd_error == 1, host->timeout);
+
+                       if (host->wait_int != 1 &&
+                           (time == 0 || host->sd_error != 0))
+                               return sh_mmcif_error_manage(host);
+
+                       host->wait_int = 0;
+                       for (i = 0; i < blocksize / 4; i++)
+                               *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA);
+               }
+               if (j < data->sg_len - 1)
+                       data->sg++;
+       }
+       return 0;
+}
+
+static int sh_mmcif_single_write(struct sh_mmcif_host *host,
+                                       struct mmc_request *mrq)
+{
+       struct mmc_data *data = mrq->data;
+       long time;
+       u32 blocksize, i, *p = sg_virt(data->sg);
+
+       host->wait_int = 0;
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+
+       /* buf write enable */
+       time = wait_event_interruptible_timeout(host->intr_wait,
+                       host->wait_int == 1 ||
+                       host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+               return sh_mmcif_error_manage(host);
+
+       host->wait_int = 0;
+       blocksize = (BLOCK_SIZE_MASK &
+                       sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3;
+       for (i = 0; i < blocksize / 4; i++)
+               sh_mmcif_writel(host, MMCIF_CE_DATA, *p++);
+
+       /* buffer write end */
+       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
+
+       time = wait_event_interruptible_timeout(host->intr_wait,
+                       host->wait_int == 1 ||
+                       host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0))
+               return sh_mmcif_error_manage(host);
+
+       host->wait_int = 0;
+       return 0;
+}
+
+static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
+                                               struct mmc_request *mrq)
+{
+       struct mmc_data *data = mrq->data;
+       long time;
+       u32 i, sec, j, blocksize, *p;
+
+       blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET);
+
+       for (j = 0; j < data->sg_len; j++) {
+               p = sg_virt(data->sg);
+               host->wait_int = 0;
+               for (sec = 0; sec < data->sg->length / blocksize; sec++) {
+                       sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+                       /* buf write enable*/
+                       time = wait_event_interruptible_timeout(host->intr_wait,
+                               host->wait_int == 1 ||
+                               host->sd_error == 1, host->timeout);
+
+                       if (host->wait_int != 1 &&
+                           (time == 0 || host->sd_error != 0))
+                               return sh_mmcif_error_manage(host);
+
+                       host->wait_int = 0;
+                       for (i = 0; i < blocksize / 4; i++)
+                               sh_mmcif_writel(host, MMCIF_CE_DATA, *p++);
+               }
+               if (j < data->sg_len - 1)
+                       data->sg++;
+       }
+       return 0;
+}
+
+static void sh_mmcif_get_response(struct sh_mmcif_host *host,
+                                               struct mmc_command *cmd)
+{
+       if (cmd->flags & MMC_RSP_136) {
+               cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP3);
+               cmd->resp[1] = sh_mmcif_readl(host, MMCIF_CE_RESP2);
+               cmd->resp[2] = sh_mmcif_readl(host, MMCIF_CE_RESP1);
+               cmd->resp[3] = sh_mmcif_readl(host, MMCIF_CE_RESP0);
+       } else
+               cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP0);
+}
+
+static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host,
+                                               struct mmc_command *cmd)
+{
+       cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP_CMD12);
+}
+
+static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
+               struct mmc_request *mrq, struct mmc_command *cmd, u32 opc)
+{
+       u32 tmp = 0;
+
+       /* Response Type check */
+       switch (mmc_resp_type(cmd)) {
+       case MMC_RSP_NONE:
+               tmp |= CMD_SET_RTYP_NO;
+               break;
+       case MMC_RSP_R1:
+       case MMC_RSP_R1B:
+       case MMC_RSP_R3:
+               tmp |= CMD_SET_RTYP_6B;
+               break;
+       case MMC_RSP_R2:
+               tmp |= CMD_SET_RTYP_17B;
+               break;
+       default:
+               pr_err(DRIVER_NAME": Not support type response.\n");
+               break;
+       }
+       switch (opc) {
+       /* RBSY */
+       case MMC_SWITCH:
+       case MMC_STOP_TRANSMISSION:
+       case MMC_SET_WRITE_PROT:
+       case MMC_CLR_WRITE_PROT:
+       case MMC_ERASE:
+       case MMC_GEN_CMD:
+               tmp |= CMD_SET_RBSY;
+               break;
+       }
+       /* WDAT / DATW */
+       if (host->data) {
+               tmp |= CMD_SET_WDAT;
+               switch (host->bus_width) {
+               case MMC_BUS_WIDTH_1:
+                       tmp |= CMD_SET_DATW_1;
+                       break;
+               case MMC_BUS_WIDTH_4:
+                       tmp |= CMD_SET_DATW_4;
+                       break;
+               case MMC_BUS_WIDTH_8:
+                       tmp |= CMD_SET_DATW_8;
+                       break;
+               default:
+                       pr_err(DRIVER_NAME": Not support bus width.\n");
+                       break;
+               }
+       }
+       /* DWEN */
+       if (opc == MMC_WRITE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK)
+               tmp |= CMD_SET_DWEN;
+       /* CMLTE/CMD12EN */
+       if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) {
+               tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
+               sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET,
+                                       mrq->data->blocks << 16);
+       }
+       /* RIDXC[1:0] check bits */
+       if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID ||
+           opc == MMC_SEND_CSD || opc == MMC_SEND_CID)
+               tmp |= CMD_SET_RIDXC_BITS;
+       /* RCRC7C[1:0] check bits */
+       if (opc == MMC_SEND_OP_COND)
+               tmp |= CMD_SET_CRC7C_BITS;
+       /* RCRC7C[1:0] internal CRC7 */
+       if (opc == MMC_ALL_SEND_CID ||
+               opc == MMC_SEND_CSD || opc == MMC_SEND_CID)
+               tmp |= CMD_SET_CRC7C_INTERNAL;
+
+       return opc = ((opc << 24) | tmp);
+}
+
+static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host,
+                               struct mmc_request *mrq, u32 opc)
+{
+       u32 ret;
+
+       switch (opc) {
+       case MMC_READ_MULTIPLE_BLOCK:
+               ret = sh_mmcif_multi_read(host, mrq);
+               break;
+       case MMC_WRITE_MULTIPLE_BLOCK:
+               ret = sh_mmcif_multi_write(host, mrq);
+               break;
+       case MMC_WRITE_BLOCK:
+               ret = sh_mmcif_single_write(host, mrq);
+               break;
+       case MMC_READ_SINGLE_BLOCK:
+       case MMC_SEND_EXT_CSD:
+               ret = sh_mmcif_single_read(host, mrq);
+               break;
+       default:
+               pr_err(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc);
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
+                       struct mmc_request *mrq, struct mmc_command *cmd)
+{
+       long time;
+       int ret = 0, mask = 0;
+       u32 opc = cmd->opcode;
+
+       host->cmd = cmd;
+
+       switch (opc) {
+       /* respons busy check */
+       case MMC_SWITCH:
+       case MMC_STOP_TRANSMISSION:
+       case MMC_SET_WRITE_PROT:
+       case MMC_CLR_WRITE_PROT:
+       case MMC_ERASE:
+       case MMC_GEN_CMD:
+               mask = MASK_MRBSYE;
+               break;
+       default:
+               mask = MASK_MCRSPE;
+               break;
+       }
+       mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR |
+               MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR |
+               MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO |
+               MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO;
+
+       if (host->data) {
+               sh_mmcif_writel(host, MMCIF_CE_BLOCK_SET, 0);
+               sh_mmcif_writel(host, MMCIF_CE_BLOCK_SET, mrq->data->blksz);
+       }
+       opc = sh_mmcif_set_cmd(host, mrq, cmd, opc);
+
+       sh_mmcif_writel(host, MMCIF_CE_INT, 0xD80430C0);
+       sh_mmcif_writel(host, MMCIF_CE_INT_MASK, mask);
+       /* set arg */
+       sh_mmcif_writel(host, MMCIF_CE_ARG, cmd->arg);
+       host->wait_int = 0;
+       /* set cmd */
+       sh_mmcif_writel(host, MMCIF_CE_CMD_SET, opc);
+
+       time = wait_event_interruptible_timeout(host->intr_wait,
+               host->wait_int == 1 || host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && time == 0) {
+               cmd->error = sh_mmcif_error_manage(host);
+               return;
+       }
+       if (host->sd_error) {
+               switch (cmd->opcode) {
+               case MMC_ALL_SEND_CID:
+               case MMC_SELECT_CARD:
+               case MMC_APP_CMD:
+                       cmd->error = -ETIMEDOUT;
+                       break;
+               default:
+                       pr_debug("%s: Cmd(d'%d) err\n",
+                                       DRIVER_NAME, cmd->opcode);
+                       cmd->error = sh_mmcif_error_manage(host);
+                       break;
+               }
+               host->sd_error = 0;
+               host->wait_int = 0;
+               return;
+       }
+       if (!(cmd->flags & MMC_RSP_PRESENT)) {
+               cmd->error = ret;
+               host->wait_int = 0;
+               return;
+       }
+       if (host->wait_int == 1) {
+               sh_mmcif_get_response(host, cmd);
+               host->wait_int = 0;
+       }
+       if (host->data) {
+               ret = sh_mmcif_data_trans(host, mrq, cmd->opcode);
+               if (ret < 0)
+                       mrq->data->bytes_xfered = 0;
+               else
+                       mrq->data->bytes_xfered =
+                               mrq->data->blocks * mrq->data->blksz;
+       }
+       cmd->error = ret;
+}
+
+static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
+               struct mmc_request *mrq, struct mmc_command *cmd)
+{
+       long time;
+
+       if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK)
+               sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
+       else if (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
+               sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
+       else {
+               pr_err(DRIVER_NAME": not support stop cmd\n");
+               cmd->error = sh_mmcif_error_manage(host);
+               return;
+       }
+
+       time = wait_event_interruptible_timeout(host->intr_wait,
+                       host->wait_int == 1 ||
+                       host->sd_error == 1, host->timeout);
+       if (host->wait_int != 1 && (time == 0 || host->sd_error != 0)) {
+               cmd->error = sh_mmcif_error_manage(host);
+               return;
+       }
+       sh_mmcif_get_cmd12response(host, cmd);
+       host->wait_int = 0;
+       cmd->error = 0;
+}
+
+static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct sh_mmcif_host *host = mmc_priv(mmc);
+
+       switch (mrq->cmd->opcode) {
+       /* MMCIF does not support SD/SDIO command */
+       case SD_IO_SEND_OP_COND:
+       case MMC_APP_CMD:
+               mrq->cmd->error = -ETIMEDOUT;
+               mmc_request_done(mmc, mrq);
+               return;
+       case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
+               if (!mrq->data) {
+                       /* send_if_cond cmd (not support) */
+                       mrq->cmd->error = -ETIMEDOUT;
+                       mmc_request_done(mmc, mrq);
+                       return;
+               }
+               break;
+       default:
+               break;
+       }
+       host->data = mrq->data;
+       sh_mmcif_start_cmd(host, mrq, mrq->cmd);
+       host->data = NULL;
+
+       if (mrq->cmd->error != 0) {
+               mmc_request_done(mmc, mrq);
+               return;
+       }
+       if (mrq->stop)
+               sh_mmcif_stop_cmd(host, mrq, mrq->stop);
+       mmc_request_done(mmc, mrq);
+}
+
+static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct sh_mmcif_host *host = mmc_priv(mmc);
+       struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+
+       if (ios->power_mode == MMC_POWER_OFF) {
+               /* clock stop */
+               sh_mmcif_clock_control(host, 0);
+               if (p->down_pwr)
+                       p->down_pwr(host->pd);
+               return;
+       } else if (ios->power_mode == MMC_POWER_UP) {
+               if (p->set_pwr)
+                       p->set_pwr(host->pd, ios->power_mode);
+       }
+
+       if (ios->clock)
+               sh_mmcif_clock_control(host, ios->clock);
+
+       host->bus_width = ios->bus_width;
+}
+
+static struct mmc_host_ops sh_mmcif_ops = {
+       .request        = sh_mmcif_request,
+       .set_ios        = sh_mmcif_set_ios,
+};
+
+static void sh_mmcif_detect(struct mmc_host *mmc)
+{
+       mmc_detect_change(mmc, 0);
+}
+
+static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
+{
+       struct sh_mmcif_host *host = dev_id;
+       u32 state = 0;
+       int err = 0;
+
+       state = sh_mmcif_readl(host, MMCIF_CE_INT);
+
+       if (state & INT_RBSYE) {
+               sh_mmcif_writel(host, MMCIF_CE_INT, ~(INT_RBSYE | INT_CRSPE));
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE);
+       } else if (state & INT_CRSPE) {
+               sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_CRSPE);
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCRSPE);
+       } else if (state & INT_BUFREN) {
+               sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFREN);
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
+       } else if (state & INT_BUFWEN) {
+               sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFWEN);
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
+       } else if (state & INT_CMD12DRE) {
+               sh_mmcif_writel(host, MMCIF_CE_INT,
+                       ~(INT_CMD12DRE | INT_CMD12RBE |
+                         INT_CMD12CRE | INT_BUFRE));
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
+       } else if (state & INT_BUFRE) {
+               sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFRE);
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
+       } else if (state & INT_DTRANE) {
+               sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_DTRANE);
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
+       } else if (state & INT_CMD12RBE) {
+               sh_mmcif_writel(host, MMCIF_CE_INT,
+                               ~(INT_CMD12RBE | INT_CMD12CRE));
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
+       } else if (state & INT_ERR_STS) {
+               /* err interrupts */
+               sh_mmcif_writel(host, MMCIF_CE_INT, ~state);
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
+               err = 1;
+       } else {
+               pr_debug("%s: Not support int\n", DRIVER_NAME);
+               sh_mmcif_writel(host, MMCIF_CE_INT, ~state);
+               sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
+               err = 1;
+       }
+       if (err) {
+               host->sd_error = 1;
+               pr_debug("%s: int err state = %08x\n", DRIVER_NAME, state);
+       }
+       host->wait_int = 1;
+       wake_up(&host->intr_wait);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit sh_mmcif_probe(struct platform_device *pdev)
+{
+       int ret = 0, irq[2];
+       struct mmc_host *mmc;
+       struct sh_mmcif_host *host = NULL;
+       struct sh_mmcif_plat_data *pd = NULL;
+       struct resource *res;
+       void __iomem *reg;
+       char clk_name[8];
+
+       irq[0] = platform_get_irq(pdev, 0);
+       irq[1] = platform_get_irq(pdev, 1);
+       if (irq[0] < 0 || irq[1] < 0) {
+               pr_err(DRIVER_NAME": Get irq error\n");
+               return -ENXIO;
+       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "platform_get_resource error.\n");
+               return -ENXIO;
+       }
+       reg = ioremap(res->start, resource_size(res));
+       if (!reg) {
+               dev_err(&pdev->dev, "ioremap error.\n");
+               return -ENOMEM;
+       }
+       pd = (struct sh_mmcif_plat_data *)(pdev->dev.platform_data);
+       if (!pd) {
+               dev_err(&pdev->dev, "sh_mmcif plat data error.\n");
+               ret = -ENXIO;
+               goto clean_up;
+       }
+       mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev);
+       if (!mmc) {
+               ret = -ENOMEM;
+               goto clean_up;
+       }
+       host            = mmc_priv(mmc);
+       host->mmc       = mmc;
+       host->addr      = reg;
+       host->timeout   = 1000;
+
+       snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
+       host->hclk = clk_get(&pdev->dev, clk_name);
+       if (IS_ERR(host->hclk)) {
+               dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+               ret = PTR_ERR(host->hclk);
+               goto clean_up1;
+       }
+       clk_enable(host->hclk);
+       host->clk = clk_get_rate(host->hclk);
+       host->pd = pdev;
+
+       init_waitqueue_head(&host->intr_wait);
+
+       mmc->ops = &sh_mmcif_ops;
+       mmc->f_max = host->clk;
+       /* close to 400KHz */
+       if (mmc->f_max < 51200000)
+               mmc->f_min = mmc->f_max / 128;
+       else if (mmc->f_max < 102400000)
+               mmc->f_min = mmc->f_max / 256;
+       else
+               mmc->f_min = mmc->f_max / 512;
+       if (pd->ocr)
+               mmc->ocr_avail = pd->ocr;
+       mmc->caps = MMC_CAP_MMC_HIGHSPEED;
+       if (pd->caps)
+               mmc->caps |= pd->caps;
+       mmc->max_phys_segs = 128;
+       mmc->max_hw_segs = 128;
+       mmc->max_blk_size = 512;
+       mmc->max_blk_count = 65535;
+       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+       mmc->max_seg_size = mmc->max_req_size;
+
+       sh_mmcif_sync_reset(host);
+       platform_set_drvdata(pdev, host);
+       mmc_add_host(mmc);
+
+       ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
+       if (ret) {
+               pr_err(DRIVER_NAME": request_irq error (sh_mmc:error)\n");
+               goto clean_up2;
+       }
+       ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host);
+       if (ret) {
+               free_irq(irq[0], host);
+               pr_err(DRIVER_NAME": request_irq error (sh_mmc:int)\n");
+               goto clean_up2;
+       }
+
+       sh_mmcif_writel(host, MMCIF_CE_INT_MASK, MASK_ALL);
+       sh_mmcif_detect(host->mmc);
+
+       pr_info("%s: driver version %s\n", DRIVER_NAME, DRIVER_VERSION);
+       pr_debug("%s: chip ver H'%04x\n", DRIVER_NAME,
+                       sh_mmcif_readl(host, MMCIF_CE_VERSION) & 0x0000ffff);
+       return ret;
+
+clean_up2:
+       clk_disable(host->hclk);
+clean_up1:
+       mmc_free_host(mmc);
+clean_up:
+       if (reg)
+               iounmap(reg);
+       return ret;
+}
+
+static int __devexit sh_mmcif_remove(struct platform_device *pdev)
+{
+       struct sh_mmcif_host *host = platform_get_drvdata(pdev);
+       int irq[2];
+
+       sh_mmcif_writel(host, MMCIF_CE_INT_MASK, MASK_ALL);
+
+       irq[0] = platform_get_irq(pdev, 0);
+       irq[1] = platform_get_irq(pdev, 1);
+
+       if (host->addr)
+               iounmap(host->addr);
+
+       platform_set_drvdata(pdev, NULL);
+       mmc_remove_host(host->mmc);
+
+       free_irq(irq[0], host);
+       free_irq(irq[1], host);
+
+       clk_disable(host->hclk);
+       mmc_free_host(host->mmc);
+
+       return 0;
+}
+
+static struct platform_driver sh_mmcif_driver = {
+       .probe          = sh_mmcif_probe,
+       .remove         = sh_mmcif_remove,
+       .driver         = {
+               .name   = DRIVER_NAME,
+       },
+};
+
+static int __init sh_mmcif_init(void)
+{
+       return platform_driver_register(&sh_mmcif_driver);
+}
+
+static void __exit sh_mmcif_exit(void)
+{
+       platform_driver_unregister(&sh_mmcif_driver);
+}
+
+module_init(sh_mmcif_init);
+module_exit(sh_mmcif_exit);
+
+
+MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS(DRIVER_NAME);
+MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>");
index 82554ddec6b3cb6b3d3e0a438fdbc2bceeb3561e..cec99958b65286b3768fb3e5c06e91140909bbf5 100644 (file)
@@ -1032,7 +1032,7 @@ static void tifm_sd_remove(struct tifm_dev *sock)
 
 static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
 {
-       return mmc_suspend_host(tifm_get_drvdata(sock), state);
+       return mmc_suspend_host(tifm_get_drvdata(sock));
 }
 
 static int tifm_sd_resume(struct tifm_dev *sock)
index 883fcac210043dff457bbe99f3e0a09ed8d7eaf0..ee7d0a5a51c496cb92b04e7b9bc8172f8a233875 100644 (file)
@@ -768,7 +768,7 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
        struct mmc_host *mmc = platform_get_drvdata(dev);
        int ret;
 
-       ret = mmc_suspend_host(mmc, state);
+       ret = mmc_suspend_host(mmc);
 
        /* Tell MFD core it can disable us now.*/
        if (!ret && cell->disable)
index 632858a94376b0b04c2d4a61fe79ad0f99b11760..19f2d72dbca58c4b8e4ecaad1d029029b3e43cf3 100644 (file)
@@ -1280,7 +1280,7 @@ static int via_sd_suspend(struct pci_dev *pcidev, pm_message_t state)
        via_save_pcictrlreg(host);
        via_save_sdcreg(host);
 
-       ret = mmc_suspend_host(host->mmc, state);
+       ret = mmc_suspend_host(host->mmc);
 
        pci_save_state(pcidev);
        pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
index 69efe01eece829cb2f0011b8771471d91245818a..0012f5d13d28715c0ecd4404e28a8f9502e3a085 100644 (file)
@@ -1819,7 +1819,7 @@ static int wbsd_suspend(struct wbsd_host *host, pm_message_t state)
 {
        BUG_ON(host == NULL);
 
-       return mmc_suspend_host(host->mmc, state);
+       return mmc_suspend_host(host->mmc);
 }
 
 static int wbsd_resume(struct wbsd_host *host)
index 1586e1caa2f56a790c550a535bd17702d6230c72..8bef6d60f88b6f10a683ffae201530123c5c49e9 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/parport.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
 #include <asm/setup.h>
 #include <asm/amigahw.h>
 #include <asm/irq.h>
@@ -31,7 +33,6 @@
 #define DPRINTK(x...)  do { } while (0)
 #endif
 
-static struct parport *this_port = NULL;
 
 static void amiga_write_data(struct parport *p, unsigned char data)
 {
@@ -227,18 +228,11 @@ static struct parport_operations pp_amiga_ops = {
 
 /* ----------- Initialisation code --------------------------------- */
 
-static int __init parport_amiga_init(void)
+static int __init amiga_parallel_probe(struct platform_device *pdev)
 {
        struct parport *p;
        int err;
 
-       if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_PARALLEL))
-               return -ENODEV;
-
-       err = -EBUSY;
-       if (!request_mem_region(CIAA_PHYSADDR-1+0x100, 0x100, "parallel"))
-               goto out_mem;
-
        ciaa.ddrb = 0xff;
        ciab.ddra &= 0xf8;
        mb();
@@ -246,41 +240,63 @@ static int __init parport_amiga_init(void)
        p = parport_register_port((unsigned long)&ciaa.prb, IRQ_AMIGA_CIAA_FLG,
                                   PARPORT_DMA_NONE, &pp_amiga_ops);
        if (!p)
-               goto out_port;
+               return -EBUSY;
 
-       err = request_irq(IRQ_AMIGA_CIAA_FLG, parport_irq_handler, 0, p->name, p);
+       err = request_irq(IRQ_AMIGA_CIAA_FLG, parport_irq_handler, 0, p->name,
+                         p);
        if (err)
                goto out_irq;
 
-       this_port = p;
        printk(KERN_INFO "%s: Amiga built-in port using irq\n", p->name);
        /* XXX: set operating mode */
        parport_announce_port(p);
 
+       platform_set_drvdata(pdev, p);
+
        return 0;
 
 out_irq:
        parport_put_port(p);
-out_port:
-       release_mem_region(CIAA_PHYSADDR-1+0x100, 0x100);
-out_mem:
        return err;
 }
 
-static void __exit parport_amiga_exit(void)
+static int __exit amiga_parallel_remove(struct platform_device *pdev)
+{
+       struct parport *port = platform_get_drvdata(pdev);
+
+       parport_remove_port(port);
+       if (port->irq != PARPORT_IRQ_NONE)
+               free_irq(IRQ_AMIGA_CIAA_FLG, port);
+       parport_put_port(port);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver amiga_parallel_driver = {
+       .remove = __exit_p(amiga_parallel_remove),
+       .driver   = {
+               .name   = "amiga-parallel",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init amiga_parallel_init(void)
+{
+       return platform_driver_probe(&amiga_parallel_driver,
+                                    amiga_parallel_probe);
+}
+
+module_init(amiga_parallel_init);
+
+static void __exit amiga_parallel_exit(void)
 {
-       parport_remove_port(this_port);
-       if (this_port->irq != PARPORT_IRQ_NONE)
-               free_irq(IRQ_AMIGA_CIAA_FLG, this_port);
-       parport_put_port(this_port);
-       release_mem_region(CIAA_PHYSADDR-1+0x100, 0x100);
+       platform_driver_unregister(&amiga_parallel_driver);
 }
 
+module_exit(amiga_parallel_exit);
 
 MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
 MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
 MODULE_SUPPORTED_DEVICE("Amiga builtin Parallel Port");
 MODULE_LICENSE("GPL");
-
-module_init(parport_amiga_init)
-module_exit(parport_amiga_exit)
+MODULE_ALIAS("platform:amiga-parallel");
index c32822ad84a40b6e0611557121b9aa1793104c16..070211a5955c7dc140799b55a2f57bbbe5ce0191 100644 (file)
@@ -8,3 +8,27 @@ config RAPIDIO_DISC_TIMEOUT
        ---help---
          Amount of time a discovery node waits for a host to complete
          enumeration before giving up.
+
+config RAPIDIO_ENABLE_RX_TX_PORTS
+       bool "Enable RapidIO Input/Output Ports"
+       depends on RAPIDIO
+       ---help---
+         The RapidIO specification describes a Output port transmit
+         enable and a Input port receive enable. The recommended state
+         for Input ports and Output ports should be disabled. When
+         this switch is set the RapidIO subsystem will enable all
+         ports for Input/Output direction to allow other traffic
+         than Maintenance transfers.
+
+source "drivers/rapidio/switches/Kconfig"
+
+config RAPIDIO_DEBUG
+       bool "RapidIO subsystem debug messages"
+       depends on RAPIDIO
+       help
+         Say Y here if you want the RapidIO subsystem to produce a bunch of
+         debug messages to the system log. Select this if you are having a
+         problem with the RapidIO subsystem and want to see more of what is
+         going on.
+
+         If you are unsure about this, say N here.
index 7c0e1818de5139e43207a1e479bb4328eec4ec97..b6139fe187bfe7389f1b30970dc03c16660ca161 100644 (file)
@@ -4,3 +4,7 @@
 obj-y += rio.o rio-access.o rio-driver.o rio-scan.o rio-sysfs.o
 
 obj-$(CONFIG_RAPIDIO)          += switches/
+
+ifeq ($(CONFIG_RAPIDIO_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
index 45415096c2940d5bb834341cdcf5c76f3ffc38e6..566432106cc5cbc76ebfa802c83e32aea4d01b92 100644 (file)
@@ -4,6 +4,14 @@
  * Copyright 2005 MontaVista Software, Inc.
  * Matt Porter <mporter@kernel.crashing.org>
  *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine@idt.com>
+ * - Added Port-Write/Error Management initialization and handling
+ *
+ * Copyright 2009 Sysgo AG
+ * Thomas Moll <thomas.moll@sysgo.com>
+ * - Added Input- Output- enable functionality, to allow full communication
+ *
  * 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
 LIST_HEAD(rio_devices);
 static LIST_HEAD(rio_switches);
 
-#define RIO_ENUM_CMPL_MAGIC    0xdeadbeef
-
 static void rio_enum_timeout(unsigned long);
 
+static void rio_init_em(struct rio_dev *rdev);
+
 DEFINE_SPINLOCK(rio_global_list_lock);
 
 static int next_destid = 0;
 static int next_switchid = 0;
 static int next_net = 0;
+static int next_comptag;
 
 static struct timer_list rio_enum_timer =
 TIMER_INITIALIZER(rio_enum_timeout, 0, 0);
@@ -52,12 +61,6 @@ static int rio_mport_phys_table[] = {
        -1,
 };
 
-static int rio_sport_phys_table[] = {
-       RIO_EFB_PAR_EP_FREE_ID,
-       RIO_EFB_SER_EP_FREE_ID,
-       -1,
-};
-
 /**
  * rio_get_device_id - Get the base/extended device id for a device
  * @port: RIO master port
@@ -118,12 +121,26 @@ static int rio_clear_locks(struct rio_mport *port)
        u32 result;
        int ret = 0;
 
-       /* Write component tag CSR magic complete value */
-       rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR,
-                                 RIO_ENUM_CMPL_MAGIC);
-       list_for_each_entry(rdev, &rio_devices, global_list)
-           rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR,
-                               RIO_ENUM_CMPL_MAGIC);
+       /* Assign component tag to all devices */
+       next_comptag = 1;
+       rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, next_comptag++);
+
+       list_for_each_entry(rdev, &rio_devices, global_list) {
+               /* Mark device as discovered */
+               rio_read_config_32(rdev,
+                                  rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+                                  &result);
+               rio_write_config_32(rdev,
+                                   rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+                                   result | RIO_PORT_GEN_DISCOVERED);
+
+               rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, next_comptag);
+               rdev->comp_tag = next_comptag++;
+               if (next_comptag >= 0x10000) {
+                       pr_err("RIO: Component Tag Counter Overflow\n");
+                       break;
+               }
+       }
 
        /* Release host device id locks */
        rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR,
@@ -229,27 +246,37 @@ static int rio_is_switch(struct rio_dev *rdev)
 }
 
 /**
- * rio_route_set_ops- Sets routing operations for a particular vendor switch
+ * rio_switch_init - Sets switch operations for a particular vendor switch
  * @rdev: RIO device
+ * @do_enum: Enumeration/Discovery mode flag
  *
- * Searches the RIO route ops table for known switch types. If the vid
- * and did match a switch table entry, then set the add_entry() and
- * get_entry() ops to the table entry values.
+ * Searches the RIO switch ops table for known switch types. If the vid
+ * and did match a switch table entry, then call switch initialization
+ * routine to setup switch-specific routines.
  */
-static void rio_route_set_ops(struct rio_dev *rdev)
+static void rio_switch_init(struct rio_dev *rdev, int do_enum)
 {
-       struct rio_route_ops *cur = __start_rio_route_ops;
-       struct rio_route_ops *end = __end_rio_route_ops;
+       struct rio_switch_ops *cur = __start_rio_switch_ops;
+       struct rio_switch_ops *end = __end_rio_switch_ops;
 
        while (cur < end) {
                if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
-                       pr_debug("RIO: adding routing ops for %s\n", rio_name(rdev));
-                       rdev->rswitch->add_entry = cur->add_hook;
-                       rdev->rswitch->get_entry = cur->get_hook;
+                       pr_debug("RIO: calling init routine for %s\n",
+                                rio_name(rdev));
+                       cur->init_hook(rdev, do_enum);
+                       break;
                }
                cur++;
        }
 
+       if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
+               pr_debug("RIO: adding STD routing ops for %s\n",
+                       rio_name(rdev));
+               rdev->rswitch->add_entry = rio_std_route_add_entry;
+               rdev->rswitch->get_entry = rio_std_route_get_entry;
+               rdev->rswitch->clr_table = rio_std_route_clr_table;
+       }
+
        if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
                printk(KERN_ERR "RIO: missing routing ops for %s\n",
                       rio_name(rdev));
@@ -280,6 +307,65 @@ static int __devinit rio_add_device(struct rio_dev *rdev)
        return 0;
 }
 
+/**
+ * rio_enable_rx_tx_port - enable input reciever and output transmitter of
+ * given port
+ * @port: Master port associated with the RIO network
+ * @local: local=1 select local port otherwise a far device is reached
+ * @destid: Destination ID of the device to check host bit
+ * @hopcount: Number of hops to reach the target
+ * @port_num: Port (-number on switch) to enable on a far end device
+ *
+ * Returns 0 or 1 from on General Control Command and Status Register
+ * (EXT_PTR+0x3C)
+ */
+inline int rio_enable_rx_tx_port(struct rio_mport *port,
+                                int local, u16 destid,
+                                u8 hopcount, u8 port_num) {
+#ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS
+       u32 regval;
+       u32 ext_ftr_ptr;
+
+       /*
+       * enable rx input tx output port
+       */
+       pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = "
+                "%d, port_num = %d)\n", local, destid, hopcount, port_num);
+
+       ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount);
+
+       if (local) {
+               rio_local_read_config_32(port, ext_ftr_ptr +
+                               RIO_PORT_N_CTL_CSR(0),
+                               &regval);
+       } else {
+               if (rio_mport_read_config_32(port, destid, hopcount,
+               ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), &regval) < 0)
+                       return -EIO;
+       }
+
+       if (regval & RIO_PORT_N_CTL_P_TYP_SER) {
+               /* serial */
+               regval = regval | RIO_PORT_N_CTL_EN_RX_SER
+                               | RIO_PORT_N_CTL_EN_TX_SER;
+       } else {
+               /* parallel */
+               regval = regval | RIO_PORT_N_CTL_EN_RX_PAR
+                               | RIO_PORT_N_CTL_EN_TX_PAR;
+       }
+
+       if (local) {
+               rio_local_write_config_32(port, ext_ftr_ptr +
+                                         RIO_PORT_N_CTL_CSR(0), regval);
+       } else {
+               if (rio_mport_write_config_32(port, destid, hopcount,
+                   ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0)
+                       return -EIO;
+       }
+#endif
+       return 0;
+}
+
 /**
  * rio_setup_device- Allocates and sets up a RIO device
  * @net: RIO network
@@ -325,8 +411,14 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
        rdev->asm_rev = result >> 16;
        rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR,
                                 &rdev->pef);
-       if (rdev->pef & RIO_PEF_EXT_FEATURES)
+       if (rdev->pef & RIO_PEF_EXT_FEATURES) {
                rdev->efptr = result & 0xffff;
+               rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid,
+                                                        hopcount);
+
+               rdev->em_efptr = rio_mport_get_feature(port, 0, destid,
+                                               hopcount, RIO_EFB_ERR_MGMNT);
+       }
 
        rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR,
                                 &rdev->src_ops);
@@ -349,12 +441,13 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
        if (rio_is_switch(rdev)) {
                rio_mport_read_config_32(port, destid, hopcount,
                                         RIO_SWP_INFO_CAR, &rdev->swpinfo);
-               rswitch = kmalloc(sizeof(struct rio_switch), GFP_KERNEL);
+               rswitch = kzalloc(sizeof(struct rio_switch), GFP_KERNEL);
                if (!rswitch)
                        goto cleanup;
                rswitch->switchid = next_switchid;
                rswitch->hopcount = hopcount;
                rswitch->destid = destid;
+               rswitch->port_ok = 0;
                rswitch->route_table = kzalloc(sizeof(u8)*
                                        RIO_MAX_ROUTE_ENTRIES(port->sys_size),
                                        GFP_KERNEL);
@@ -367,13 +460,22 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
                rdev->rswitch = rswitch;
                dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
                             rdev->rswitch->switchid);
-               rio_route_set_ops(rdev);
+               rio_switch_init(rdev, do_enum);
+
+               if (do_enum && rdev->rswitch->clr_table)
+                       rdev->rswitch->clr_table(port, destid, hopcount,
+                                                RIO_GLOBAL_TABLE);
 
                list_add_tail(&rswitch->node, &rio_switches);
 
-       } else
+       } else {
+               if (do_enum)
+                       /*Enable Input Output Port (transmitter reviever)*/
+                       rio_enable_rx_tx_port(port, 0, destid, hopcount, 0);
+
                dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id,
                             rdev->destid);
+       }
 
        rdev->dev.bus = &rio_bus_type;
 
@@ -414,23 +516,29 @@ cleanup:
  *
  * Reads the port error status CSR for a particular switch port to
  * determine if the port has an active link.  Returns
- * %PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is
+ * %RIO_PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is
  * inactive.
  */
 static int
 rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
 {
-       u32 result;
+       u32 result = 0;
        u32 ext_ftr_ptr;
 
-       int *entry = rio_sport_phys_table;
-
-       do {
-               if ((ext_ftr_ptr =
-                    rio_mport_get_feature(port, 0, destid, hopcount, *entry)))
+       ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 0);
 
+       while (ext_ftr_ptr) {
+               rio_mport_read_config_32(port, destid, hopcount,
+                                        ext_ftr_ptr, &result);
+               result = RIO_GET_BLOCK_ID(result);
+               if ((result == RIO_EFB_SER_EP_FREE_ID) ||
+                   (result == RIO_EFB_SER_EP_FREE_ID_V13P) ||
+                   (result == RIO_EFB_SER_EP_FREC_ID))
                        break;
-       } while (*++entry >= 0);
+
+               ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount,
+                                               ext_ftr_ptr);
+       }
 
        if (ext_ftr_ptr)
                rio_mport_read_config_32(port, destid, hopcount,
@@ -438,7 +546,81 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
                                         RIO_PORT_N_ERR_STS_CSR(sport),
                                         &result);
 
-       return (result & PORT_N_ERR_STS_PORT_OK);
+       return result & RIO_PORT_N_ERR_STS_PORT_OK;
+}
+
+/**
+ * rio_lock_device - Acquires host device lock for specified device
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ * @wait_ms: Max wait time in msec (0 = no timeout)
+ *
+ * Attepts to acquire host device lock for specified device
+ * Returns 0 if device lock acquired or EINVAL if timeout expires.
+ */
+static int
+rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms)
+{
+       u32 result;
+       int tcnt = 0;
+
+       /* Attempt to acquire device lock */
+       rio_mport_write_config_32(port, destid, hopcount,
+                                 RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
+       rio_mport_read_config_32(port, destid, hopcount,
+                                RIO_HOST_DID_LOCK_CSR, &result);
+
+       while (result != port->host_deviceid) {
+               if (wait_ms != 0 && tcnt == wait_ms) {
+                       pr_debug("RIO: timeout when locking device %x:%x\n",
+                               destid, hopcount);
+                       return -EINVAL;
+               }
+
+               /* Delay a bit */
+               mdelay(1);
+               tcnt++;
+               /* Try to acquire device lock again */
+               rio_mport_write_config_32(port, destid,
+                       hopcount,
+                       RIO_HOST_DID_LOCK_CSR,
+                       port->host_deviceid);
+               rio_mport_read_config_32(port, destid,
+                       hopcount,
+                       RIO_HOST_DID_LOCK_CSR, &result);
+       }
+
+       return 0;
+}
+
+/**
+ * rio_unlock_device - Releases host device lock for specified device
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ *
+ * Returns 0 if device lock released or EINVAL if fails.
+ */
+static int
+rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
+{
+       u32 result;
+
+       /* Release device lock */
+       rio_mport_write_config_32(port, destid,
+                                 hopcount,
+                                 RIO_HOST_DID_LOCK_CSR,
+                                 port->host_deviceid);
+       rio_mport_read_config_32(port, destid, hopcount,
+               RIO_HOST_DID_LOCK_CSR, &result);
+       if ((result & 0xffff) != 0xffff) {
+               pr_debug("RIO: badness when releasing device lock %x:%x\n",
+                        destid, hopcount);
+               return -EINVAL;
+       }
+
+       return 0;
 }
 
 /**
@@ -448,6 +630,7 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
  * @table: Routing table ID
  * @route_destid: Destination ID to be routed
  * @route_port: Port number to be routed
+ * @lock: lock switch device flag
  *
  * Calls the switch specific add_entry() method to add a route entry
  * on a switch. The route table can be specified using the @table
@@ -456,12 +639,26 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
  * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
  * on failure.
  */
-static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch,
-                              u16 table, u16 route_destid, u8 route_port)
+static int
+rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch,
+                   u16 table, u16 route_destid, u8 route_port, int lock)
 {
-       return rswitch->add_entry(mport, rswitch->destid,
+       int rc;
+
+       if (lock) {
+               rc = rio_lock_device(mport, rswitch->destid,
+                                    rswitch->hopcount, 1000);
+               if (rc)
+                       return rc;
+       }
+
+       rc = rswitch->add_entry(mport, rswitch->destid,
                                        rswitch->hopcount, table,
                                        route_destid, route_port);
+       if (lock)
+               rio_unlock_device(mport, rswitch->destid, rswitch->hopcount);
+
+       return rc;
 }
 
 /**
@@ -471,6 +668,7 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit
  * @table: Routing table ID
  * @route_destid: Destination ID to be routed
  * @route_port: Pointer to read port number into
+ * @lock: lock switch device flag
  *
  * Calls the switch specific get_entry() method to read a route entry
  * in a switch. The route table can be specified using the @table
@@ -481,11 +679,24 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit
  */
 static int
 rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table,
-                   u16 route_destid, u8 * route_port)
+                   u16 route_destid, u8 *route_port, int lock)
 {
-       return rswitch->get_entry(mport, rswitch->destid,
+       int rc;
+
+       if (lock) {
+               rc = rio_lock_device(mport, rswitch->destid,
+                                    rswitch->hopcount, 1000);
+               if (rc)
+                       return rc;
+       }
+
+       rc = rswitch->get_entry(mport, rswitch->destid,
                                        rswitch->hopcount, table,
                                        route_destid, route_port);
+       if (lock)
+               rio_unlock_device(mport, rswitch->destid, rswitch->hopcount);
+
+       return rc;
 }
 
 /**
@@ -625,14 +836,14 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
                sw_inport = rio_get_swpinfo_inport(port,
                                RIO_ANY_DESTID(port->sys_size), hopcount);
                rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
-                                   port->host_deviceid, sw_inport);
+                                   port->host_deviceid, sw_inport, 0);
                rdev->rswitch->route_table[port->host_deviceid] = sw_inport;
 
                for (destid = 0; destid < next_destid; destid++) {
                        if (destid == port->host_deviceid)
                                continue;
                        rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE,
-                                           destid, sw_inport);
+                                           destid, sw_inport, 0);
                        rdev->rswitch->route_table[destid] = sw_inport;
                }
 
@@ -644,8 +855,15 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
                    rio_name(rdev), rdev->vid, rdev->did, num_ports);
                sw_destid = next_destid;
                for (port_num = 0; port_num < num_ports; port_num++) {
-                       if (sw_inport == port_num)
+                       /*Enable Input Output Port (transmitter reviever)*/
+                       rio_enable_rx_tx_port(port, 0,
+                                             RIO_ANY_DESTID(port->sys_size),
+                                             hopcount, port_num);
+
+                       if (sw_inport == port_num) {
+                               rdev->rswitch->port_ok |= (1 << port_num);
                                continue;
+                       }
 
                        cur_destid = next_destid;
 
@@ -655,10 +873,11 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
                                pr_debug(
                                    "RIO: scanning device on port %d\n",
                                    port_num);
+                               rdev->rswitch->port_ok |= (1 << port_num);
                                rio_route_add_entry(port, rdev->rswitch,
                                                RIO_GLOBAL_TABLE,
                                                RIO_ANY_DESTID(port->sys_size),
-                                               port_num);
+                                               port_num, 0);
 
                                if (rio_enum_peer(net, port, hopcount + 1) < 0)
                                        return -1;
@@ -672,15 +891,35 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
                                                rio_route_add_entry(port, rdev->rswitch,
                                                                    RIO_GLOBAL_TABLE,
                                                                    destid,
-                                                                   port_num);
+                                                                   port_num,
+                                                                   0);
                                                rdev->rswitch->
                                                    route_table[destid] =
                                                    port_num;
                                        }
                                }
+                       } else {
+                               /* If switch supports Error Management,
+                                * set PORT_LOCKOUT bit for unused port
+                                */
+                               if (rdev->em_efptr)
+                                       rio_set_port_lockout(rdev, port_num, 1);
+
+                               rdev->rswitch->port_ok &= ~(1 << port_num);
                        }
                }
 
+               /* Direct Port-write messages to the enumeratiing host */
+               if ((rdev->src_ops & RIO_SRC_OPS_PORT_WRITE) &&
+                   (rdev->em_efptr)) {
+                       rio_write_config_32(rdev,
+                                       rdev->em_efptr + RIO_EM_PW_TGT_DEVID,
+                                       (port->host_deviceid << 16) |
+                                       (port->sys_size << 15));
+               }
+
+               rio_init_em(rdev);
+
                /* Check for empty switch */
                if (next_destid == sw_destid) {
                        next_destid++;
@@ -700,21 +939,16 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
  * rio_enum_complete- Tests if enumeration of a network is complete
  * @port: Master port to send transaction
  *
- * Tests the Component Tag CSR for presence of the magic enumeration
- * complete flag. Return %1 if enumeration is complete or %0 if
+ * Tests the Component Tag CSR for non-zero value (enumeration
+ * complete flag). Return %1 if enumeration is complete or %0 if
  * enumeration is incomplete.
  */
 static int rio_enum_complete(struct rio_mport *port)
 {
        u32 tag_csr;
-       int ret = 0;
 
        rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr);
-
-       if (tag_csr == RIO_ENUM_CMPL_MAGIC)
-               ret = 1;
-
-       return ret;
+       return (tag_csr & 0xffff) ? 1 : 0;
 }
 
 /**
@@ -763,17 +997,21 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
                                pr_debug(
                                    "RIO: scanning device on port %d\n",
                                    port_num);
+
+                               rio_lock_device(port, destid, hopcount, 1000);
+
                                for (ndestid = 0;
                                     ndestid < RIO_ANY_DESTID(port->sys_size);
                                     ndestid++) {
                                        rio_route_get_entry(port, rdev->rswitch,
                                                            RIO_GLOBAL_TABLE,
                                                            ndestid,
-                                                           &route_port);
+                                                           &route_port, 0);
                                        if (route_port == port_num)
                                                break;
                                }
 
+                               rio_unlock_device(port, destid, hopcount);
                                if (rio_disc_peer
                                    (net, port, ndestid, hopcount + 1) < 0)
                                        return -1;
@@ -792,7 +1030,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
  *
  * Reads the port error status CSR for the master port to
  * determine if the port has an active link.  Returns
- * %PORT_N_ERR_STS_PORT_OK if the  master port is active
+ * %RIO_PORT_N_ERR_STS_PORT_OK if the  master port is active
  * or %0 if it is inactive.
  */
 static int rio_mport_is_active(struct rio_mport *port)
@@ -813,7 +1051,7 @@ static int rio_mport_is_active(struct rio_mport *port)
                                         RIO_PORT_N_ERR_STS_CSR(port->index),
                                         &result);
 
-       return (result & PORT_N_ERR_STS_PORT_OK);
+       return result & RIO_PORT_N_ERR_STS_PORT_OK;
 }
 
 /**
@@ -866,12 +1104,17 @@ static void rio_update_route_tables(struct rio_mport *port)
                                continue;
 
                        if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) {
+                               /* Skip if destid ends in empty switch*/
+                               if (rswitch->destid == destid)
+                                       continue;
 
                                sport = rio_get_swpinfo_inport(port,
                                                rswitch->destid, rswitch->hopcount);
 
                                if (rswitch->add_entry) {
-                                       rio_route_add_entry(port, rswitch, RIO_GLOBAL_TABLE, destid, sport);
+                                       rio_route_add_entry(port, rswitch,
+                                               RIO_GLOBAL_TABLE, destid,
+                                               sport, 0);
                                        rswitch->route_table[destid] = sport;
                                }
                        }
@@ -879,6 +1122,32 @@ static void rio_update_route_tables(struct rio_mport *port)
        }
 }
 
+/**
+ * rio_init_em - Initializes RIO Error Management (for switches)
+ * @port: Master port associated with the RIO network
+ *
+ * For each enumerated switch, call device-specific error management
+ * initialization routine (if supplied by the switch driver).
+ */
+static void rio_init_em(struct rio_dev *rdev)
+{
+       if (rio_is_switch(rdev) && (rdev->em_efptr) &&
+           (rdev->rswitch->em_init)) {
+               rdev->rswitch->em_init(rdev);
+       }
+}
+
+/**
+ * rio_pw_enable - Enables/disables port-write handling by a master port
+ * @port: Master port associated with port-write handling
+ * @enable:  1=enable,  0=disable
+ */
+static void rio_pw_enable(struct rio_mport *port, int enable)
+{
+       if (port->ops->pwenable)
+               port->ops->pwenable(port, enable);
+}
+
 /**
  * rio_enum_mport- Start enumeration through a master port
  * @mport: Master port to send transactions
@@ -911,6 +1180,10 @@ int __devinit rio_enum_mport(struct rio_mport *mport)
                        rc = -ENOMEM;
                        goto out;
                }
+
+               /* Enable Input Output Port (transmitter reviever) */
+               rio_enable_rx_tx_port(mport, 1, 0, 0, 0);
+
                if (rio_enum_peer(net, mport, 0) < 0) {
                        /* A higher priority host won enumeration, bail. */
                        printk(KERN_INFO
@@ -922,6 +1195,7 @@ int __devinit rio_enum_mport(struct rio_mport *mport)
                }
                rio_update_route_tables(mport);
                rio_clear_locks(mport);
+               rio_pw_enable(mport, 1);
        } else {
                printk(KERN_INFO "RIO: master port %d link inactive\n",
                       mport->id);
@@ -945,15 +1219,22 @@ static void rio_build_route_tables(void)
        u8 sport;
 
        list_for_each_entry(rdev, &rio_devices, global_list)
-           if (rio_is_switch(rdev))
-               for (i = 0;
-                    i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
-                    i++) {
-                       if (rio_route_get_entry
-                           (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE,
-                            i, &sport) < 0)
-                               continue;
-                       rdev->rswitch->route_table[i] = sport;
+               if (rio_is_switch(rdev)) {
+                       rio_lock_device(rdev->net->hport, rdev->rswitch->destid,
+                                       rdev->rswitch->hopcount, 1000);
+                       for (i = 0;
+                            i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
+                            i++) {
+                               if (rio_route_get_entry
+                                   (rdev->net->hport, rdev->rswitch,
+                                    RIO_GLOBAL_TABLE, i, &sport, 0) < 0)
+                                       continue;
+                               rdev->rswitch->route_table[i] = sport;
+                       }
+
+                       rio_unlock_device(rdev->net->hport,
+                                         rdev->rswitch->destid,
+                                         rdev->rswitch->hopcount);
                }
 }
 
@@ -1012,6 +1293,13 @@ int __devinit rio_disc_mport(struct rio_mport *mport)
                del_timer_sync(&rio_enum_timer);
 
                pr_debug("done\n");
+
+               /* Read DestID assigned by enumerator */
+               rio_local_read_config_32(mport, RIO_DID_CSR,
+                                        &mport->host_deviceid);
+               mport->host_deviceid = RIO_GET_DID(mport->sys_size,
+                                                  mport->host_deviceid);
+
                if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size),
                                        0) < 0) {
                        printk(KERN_INFO
index 6395c780008ba83534849cb47cd41267f4b63933..777e099a3d8f0899e2973d8007ad3d561d4ae008 100644 (file)
@@ -5,6 +5,10 @@
  * Copyright 2005 MontaVista Software, Inc.
  * Matt Porter <mporter@kernel.crashing.org>
  *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine@idt.com>
+ * - Added Port-Write/Error Management initialization and handling
+ *
  * 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
@@ -332,6 +336,328 @@ int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res)
        return rc;
 }
 
+/**
+ * rio_request_inb_pwrite - request inbound port-write message service
+ * @mport: RIO device to which register inbound port-write callback routine
+ * @pwcback: Callback routine to execute when port-write is received
+ *
+ * Binds a port-write callback function to the RapidIO device.
+ * Returns 0 if the request has been satisfied.
+ */
+int rio_request_inb_pwrite(struct rio_dev *rdev,
+       int (*pwcback)(struct rio_dev *rdev, union rio_pw_msg *msg, int step))
+{
+       int rc = 0;
+
+       spin_lock(&rio_global_list_lock);
+       if (rdev->pwcback != NULL)
+               rc = -ENOMEM;
+       else
+               rdev->pwcback = pwcback;
+
+       spin_unlock(&rio_global_list_lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(rio_request_inb_pwrite);
+
+/**
+ * rio_release_inb_pwrite - release inbound port-write message service
+ * @rdev: RIO device which registered for inbound port-write callback
+ *
+ * Removes callback from the rio_dev structure. Returns 0 if the request
+ * has been satisfied.
+ */
+int rio_release_inb_pwrite(struct rio_dev *rdev)
+{
+       int rc = -ENOMEM;
+
+       spin_lock(&rio_global_list_lock);
+       if (rdev->pwcback) {
+               rdev->pwcback = NULL;
+               rc = 0;
+       }
+
+       spin_unlock(&rio_global_list_lock);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(rio_release_inb_pwrite);
+
+/**
+ * rio_mport_get_physefb - Helper function that returns register offset
+ *                      for Physical Layer Extended Features Block.
+ * @rdev: RIO device
+ */
+u32
+rio_mport_get_physefb(struct rio_mport *port, int local,
+                     u16 destid, u8 hopcount)
+{
+       u32 ext_ftr_ptr;
+       u32 ftr_header;
+
+       ext_ftr_ptr = rio_mport_get_efb(port, local, destid, hopcount, 0);
+
+       while (ext_ftr_ptr)  {
+               if (local)
+                       rio_local_read_config_32(port, ext_ftr_ptr,
+                                                &ftr_header);
+               else
+                       rio_mport_read_config_32(port, destid, hopcount,
+                                                ext_ftr_ptr, &ftr_header);
+
+               ftr_header = RIO_GET_BLOCK_ID(ftr_header);
+               switch (ftr_header) {
+
+               case RIO_EFB_SER_EP_ID_V13P:
+               case RIO_EFB_SER_EP_REC_ID_V13P:
+               case RIO_EFB_SER_EP_FREE_ID_V13P:
+               case RIO_EFB_SER_EP_ID:
+               case RIO_EFB_SER_EP_REC_ID:
+               case RIO_EFB_SER_EP_FREE_ID:
+               case RIO_EFB_SER_EP_FREC_ID:
+
+                       return ext_ftr_ptr;
+
+               default:
+                       break;
+               }
+
+               ext_ftr_ptr = rio_mport_get_efb(port, local, destid,
+                                               hopcount, ext_ftr_ptr);
+       }
+
+       return ext_ftr_ptr;
+}
+
+/**
+ * rio_get_comptag - Begin or continue searching for a RIO device by component tag
+ * @comp_tag: RIO component tad to match
+ * @from: Previous RIO device found in search, or %NULL for new search
+ *
+ * Iterates through the list of known RIO devices. If a RIO device is
+ * found with a matching @comp_tag, a pointer to its device
+ * structure is returned. Otherwise, %NULL is returned. A new search
+ * is initiated by passing %NULL to the @from argument. Otherwise, if
+ * @from is not %NULL, searches continue from next device on the global
+ * list.
+ */
+static struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from)
+{
+       struct list_head *n;
+       struct rio_dev *rdev;
+
+       spin_lock(&rio_global_list_lock);
+       n = from ? from->global_list.next : rio_devices.next;
+
+       while (n && (n != &rio_devices)) {
+               rdev = rio_dev_g(n);
+               if (rdev->comp_tag == comp_tag)
+                       goto exit;
+               n = n->next;
+       }
+       rdev = NULL;
+exit:
+       spin_unlock(&rio_global_list_lock);
+       return rdev;
+}
+
+/**
+ * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port.
+ * @rdev: Pointer to RIO device control structure
+ * @pnum: Switch port number to set LOCKOUT bit
+ * @lock: Operation : set (=1) or clear (=0)
+ */
+int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
+{
+       u8 hopcount = 0xff;
+       u16 destid = rdev->destid;
+       u32 regval;
+
+       if (rdev->rswitch) {
+               destid = rdev->rswitch->destid;
+               hopcount = rdev->rswitch->hopcount;
+       }
+
+       rio_mport_read_config_32(rdev->net->hport, destid, hopcount,
+                                rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
+                                &regval);
+       if (lock)
+               regval |= RIO_PORT_N_CTL_LOCKOUT;
+       else
+               regval &= ~RIO_PORT_N_CTL_LOCKOUT;
+
+       rio_mport_write_config_32(rdev->net->hport, destid, hopcount,
+                                 rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
+                                 regval);
+       return 0;
+}
+
+/**
+ * rio_inb_pwrite_handler - process inbound port-write message
+ * @pw_msg: pointer to inbound port-write message
+ *
+ * Processes an inbound port-write message. Returns 0 if the request
+ * has been satisfied.
+ */
+int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
+{
+       struct rio_dev *rdev;
+       struct rio_mport *mport;
+       u8 hopcount;
+       u16 destid;
+       u32 err_status;
+       int rc, portnum;
+
+       rdev = rio_get_comptag(pw_msg->em.comptag, NULL);
+       if (rdev == NULL) {
+               /* Someting bad here (probably enumeration error) */
+               pr_err("RIO: %s No matching device for CTag 0x%08x\n",
+                       __func__, pw_msg->em.comptag);
+               return -EIO;
+       }
+
+       pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev));
+
+#ifdef DEBUG_PW
+       {
+       u32 i;
+       for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) {
+                       pr_debug("0x%02x: %08x %08x %08x %08x",
+                                i*4, pw_msg->raw[i], pw_msg->raw[i + 1],
+                                pw_msg->raw[i + 2], pw_msg->raw[i + 3]);
+                       i += 4;
+       }
+       pr_debug("\n");
+       }
+#endif
+
+       /* Call an external service function (if such is registered
+        * for this device). This may be the service for endpoints that send
+        * device-specific port-write messages. End-point messages expected
+        * to be handled completely by EP specific device driver.
+        * For switches rc==0 signals that no standard processing required.
+        */
+       if (rdev->pwcback != NULL) {
+               rc = rdev->pwcback(rdev, pw_msg, 0);
+               if (rc == 0)
+                       return 0;
+       }
+
+       /* For End-point devices processing stops here */
+       if (!(rdev->pef & RIO_PEF_SWITCH))
+               return 0;
+
+       if (rdev->phys_efptr == 0) {
+               pr_err("RIO_PW: Bad switch initialization for %s\n",
+                       rio_name(rdev));
+               return 0;
+       }
+
+       mport = rdev->net->hport;
+       destid = rdev->rswitch->destid;
+       hopcount = rdev->rswitch->hopcount;
+
+       /*
+        * Process the port-write notification from switch
+        */
+
+       portnum = pw_msg->em.is_port & 0xFF;
+
+       if (rdev->rswitch->em_handle)
+               rdev->rswitch->em_handle(rdev, portnum);
+
+       rio_mport_read_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+                       &err_status);
+       pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status);
+
+       if (pw_msg->em.errdetect) {
+               pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n",
+                        portnum, pw_msg->em.errdetect);
+               /* Clear EM Port N Error Detect CSR */
+               rio_mport_write_config_32(mport, destid, hopcount,
+                       rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
+       }
+
+       if (pw_msg->em.ltlerrdet) {
+               pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n",
+                        pw_msg->em.ltlerrdet);
+               /* Clear EM L/T Layer Error Detect CSR */
+               rio_mport_write_config_32(mport, destid, hopcount,
+                       rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0);
+       }
+
+       /* Clear Port Errors */
+       rio_mport_write_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+                       err_status & RIO_PORT_N_ERR_STS_CLR_MASK);
+
+       if (rdev->rswitch->port_ok & (1 << portnum)) {
+               if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) {
+                       rdev->rswitch->port_ok &= ~(1 << portnum);
+                       rio_set_port_lockout(rdev, portnum, 1);
+
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr +
+                                       RIO_PORT_N_ACK_STS_CSR(portnum),
+                               RIO_PORT_N_ACK_CLEAR);
+
+                       /* Schedule Extraction Service */
+                       pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n",
+                              rio_name(rdev), portnum);
+               }
+       } else {
+               if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {
+                       rdev->rswitch->port_ok |= (1 << portnum);
+                       rio_set_port_lockout(rdev, portnum, 0);
+
+                       /* Schedule Insertion Service */
+                       pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n",
+                              rio_name(rdev), portnum);
+               }
+       }
+
+       /* Clear Port-Write Pending bit */
+       rio_mport_write_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+                       RIO_PORT_N_ERR_STS_PW_PEND);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rio_inb_pwrite_handler);
+
+/**
+ * rio_mport_get_efb - get pointer to next extended features block
+ * @port: Master port to issue transaction
+ * @local: Indicate a local master port or remote device access
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @from: Offset of  current Extended Feature block header (if 0 starts
+ * from        ExtFeaturePtr)
+ */
+u32
+rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
+                     u8 hopcount, u32 from)
+{
+       u32 reg_val;
+
+       if (from == 0) {
+               if (local)
+                       rio_local_read_config_32(port, RIO_ASM_INFO_CAR,
+                                                &reg_val);
+               else
+                       rio_mport_read_config_32(port, destid, hopcount,
+                                                RIO_ASM_INFO_CAR, &reg_val);
+               return reg_val & RIO_EXT_FTR_PTR_MASK;
+       } else {
+               if (local)
+                       rio_local_read_config_32(port, from, &reg_val);
+               else
+                       rio_mport_read_config_32(port, destid, hopcount,
+                                                from, &reg_val);
+               return RIO_GET_BLOCK_ID(reg_val);
+       }
+}
+
 /**
  * rio_mport_get_feature - query for devices' extended features
  * @port: Master port to issue transaction
@@ -451,6 +777,111 @@ struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from)
        return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from);
 }
 
+/**
+ * rio_std_route_add_entry - Add switch route table entry using standard
+ *   registers defined in RIO specification rev.1.3
+ * @mport: Master port to issue transaction
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @table: routing table ID (global or port-specific)
+ * @route_destid: destID entry in the RT
+ * @route_port: destination port for specified destID
+ */
+int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 route_port)
+{
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_DESTID_SEL_CSR,
+                               (u32)route_destid);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR,
+                               (u32)route_port);
+       }
+
+       udelay(10);
+       return 0;
+}
+
+/**
+ * rio_std_route_get_entry - Read switch route table entry (port number)
+ *   assosiated with specified destID using standard registers defined in RIO
+ *   specification rev.1.3
+ * @mport: Master port to issue transaction
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @table: routing table ID (global or port-specific)
+ * @route_destid: destID entry in the RT
+ * @route_port: returned destination port for specified destID
+ */
+int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 *route_port)
+{
+       u32 result;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
+
+               *route_port = (u8)result;
+       }
+
+       return 0;
+}
+
+/**
+ * rio_std_route_clr_table - Clear swotch route table using standard registers
+ *   defined in RIO specification rev.1.3.
+ * @mport: Master port to issue transaction
+ * @local: Indicate a local master port or remote device access
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @table: routing table ID (global or port-specific)
+ */
+int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table)
+{
+       u32 max_destid = 0xff;
+       u32 i, pef, id_inc = 1, ext_cfg = 0;
+       u32 port_sel = RIO_INVALID_ROUTE;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_read_config_32(mport, destid, hopcount,
+                                        RIO_PEF_CAR, &pef);
+
+               if (mport->sys_size) {
+                       rio_mport_read_config_32(mport, destid, hopcount,
+                                                RIO_SWITCH_RT_LIMIT,
+                                                &max_destid);
+                       max_destid &= RIO_RT_MAX_DESTID;
+               }
+
+               if (pef & RIO_PEF_EXT_RT) {
+                       ext_cfg = 0x80000000;
+                       id_inc = 4;
+                       port_sel = (RIO_INVALID_ROUTE << 24) |
+                                  (RIO_INVALID_ROUTE << 16) |
+                                  (RIO_INVALID_ROUTE << 8) |
+                                  RIO_INVALID_ROUTE;
+               }
+
+               for (i = 0; i <= max_destid;) {
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                       RIO_STD_RTE_CONF_DESTID_SEL_CSR,
+                                       ext_cfg | i);
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                       RIO_STD_RTE_CONF_PORT_SEL_CSR,
+                                       port_sel);
+                       i += id_inc;
+               }
+       }
+
+       udelay(10);
+       return 0;
+}
+
 static void rio_fixup_device(struct rio_dev *dev)
 {
 }
index 7786d02581f2adf78dd086fec096e78beba41e43..f27b7a9c47d2c685269f847141e2fc64c3782e64 100644 (file)
 
 extern u32 rio_mport_get_feature(struct rio_mport *mport, int local, u16 destid,
                                 u8 hopcount, int ftr);
+extern u32 rio_mport_get_physefb(struct rio_mport *port, int local,
+                                u16 destid, u8 hopcount);
+extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
+                            u8 hopcount, u32 from);
 extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
 extern int rio_enum_mport(struct rio_mport *mport);
 extern int rio_disc_mport(struct rio_mport *mport);
+extern int rio_std_route_add_entry(struct rio_mport *mport, u16 destid,
+                                  u8 hopcount, u16 table, u16 route_destid,
+                                  u8 route_port);
+extern int rio_std_route_get_entry(struct rio_mport *mport, u16 destid,
+                                  u8 hopcount, u16 table, u16 route_destid,
+                                  u8 *route_port);
+extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
+                                  u8 hopcount, u16 table);
+extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock);
 
 /* Structures internal to the RIO core code */
 extern struct device_attribute rio_dev_attrs[];
 extern spinlock_t rio_global_list_lock;
 
-extern struct rio_route_ops __start_rio_route_ops[];
-extern struct rio_route_ops __end_rio_route_ops[];
+extern struct rio_switch_ops __start_rio_switch_ops[];
+extern struct rio_switch_ops __end_rio_switch_ops[];
 
 /* Helpers internal to the RIO core code */
-#define DECLARE_RIO_ROUTE_SECTION(section, vid, did, add_hook, get_hook)  \
-       static struct rio_route_ops __rio_route_ops __used   \
-       __section(section)= { vid, did, add_hook, get_hook };
+#define DECLARE_RIO_SWITCH_SECTION(section, name, vid, did, init_hook) \
+       static const struct rio_switch_ops __rio_switch_##name __used \
+       __section(section) = { vid, did, init_hook };
 
 /**
- * DECLARE_RIO_ROUTE_OPS - Registers switch routing operations
+ * DECLARE_RIO_SWITCH_INIT - Registers switch initialization routine
  * @vid: RIO vendor ID
  * @did: RIO device ID
- * @add_hook: Callback that adds a route entry
- * @get_hook: Callback that gets a route entry
+ * @init_hook: Callback that performs switch-specific initialization
  *
- * Manipulating switch route tables in RIO is switch specific. This
- * registers a switch by vendor and device ID with two callbacks for
- * modifying and retrieving route entries in a switch. A &struct
- * rio_route_ops is initialized with the ops and placed into a
- * RIO-specific kernel section.
+ * Manipulating switch route tables and error management in RIO
+ * is switch specific. This registers a switch by vendor and device ID with
+ * initialization callback for setting up switch operations and (if required)
+ * hardware initialization. A &struct rio_switch_ops is initialized with
+ * pointer to the init routine and placed into a RIO-specific kernel section.
  */
-#define DECLARE_RIO_ROUTE_OPS(vid, did, add_hook, get_hook)            \
-       DECLARE_RIO_ROUTE_SECTION(.rio_route_ops,                       \
-                       vid, did, add_hook, get_hook)
+#define DECLARE_RIO_SWITCH_INIT(vid, did, init_hook)           \
+       DECLARE_RIO_SWITCH_SECTION(.rio_switch_ops, vid##did, \
+                       vid, did, init_hook)
 
 #define RIO_GET_DID(size, x)   (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
 #define RIO_SET_DID(size, x)   (size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
diff --git a/drivers/rapidio/switches/Kconfig b/drivers/rapidio/switches/Kconfig
new file mode 100644 (file)
index 0000000..2b4e9b2
--- /dev/null
@@ -0,0 +1,28 @@
+#
+# RapidIO switches configuration
+#
+config RAPIDIO_TSI57X
+       bool "IDT Tsi57x SRIO switches support"
+       depends on RAPIDIO
+       ---help---
+         Includes support for IDT Tsi57x family of serial RapidIO switches.
+
+config RAPIDIO_CPS_XX
+       bool "IDT CPS-xx SRIO switches support"
+       depends on RAPIDIO
+       ---help---
+         Includes support for IDT CPS-16/12/10/8 serial RapidIO switches.
+
+config RAPIDIO_TSI568
+       bool "Tsi568 SRIO switch support"
+       depends on RAPIDIO
+       default n
+       ---help---
+         Includes support for IDT Tsi568 serial RapidIO switch.
+
+config RAPIDIO_TSI500
+       bool "Tsi500 Parallel RapidIO switch support"
+       depends on RAPIDIO
+       default n
+       ---help---
+         Includes support for IDT Tsi500 parallel RapidIO switch.
index b924f830176116169608c602f8509e85fce96ff3..fe4adc3e8d5f317ccfb08020c266138fc50d699f 100644 (file)
@@ -2,4 +2,11 @@
 # Makefile for RIO switches
 #
 
-obj-$(CONFIG_RAPIDIO)  += tsi500.o
+obj-$(CONFIG_RAPIDIO_TSI57X)   += tsi57x.o
+obj-$(CONFIG_RAPIDIO_CPS_XX)   += idtcps.o
+obj-$(CONFIG_RAPIDIO_TSI568)   += tsi568.o
+obj-$(CONFIG_RAPIDIO_TSI500)   += tsi500.o
+
+ifeq ($(CONFIG_RAPIDIO_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c
new file mode 100644 (file)
index 0000000..2c790c1
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * IDT CPS RapidIO switches support
+ *
+ * Copyright 2009-2010 Integrated Device Technology, Inc.
+ * Alexandre Bounine <alexandre.bounine@idt.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include "../rio.h"
+
+#define CPS_DEFAULT_ROUTE      0xde
+#define CPS_NO_ROUTE           0xdf
+
+#define IDTCPS_RIO_DOMAIN 0xf20020
+
+static int
+idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 route_port)
+{
+       u32 result;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
+
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
+
+               result = (0xffffff00 & result) | (u32)route_port;
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR, result);
+       }
+
+       return 0;
+}
+
+static int
+idtcps_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 *route_port)
+{
+       u32 result;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
+
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
+
+               if (CPS_DEFAULT_ROUTE == (u8)result ||
+                   CPS_NO_ROUTE == (u8)result)
+                       *route_port = RIO_INVALID_ROUTE;
+               else
+                       *route_port = (u8)result;
+       }
+
+       return 0;
+}
+
+static int
+idtcps_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table)
+{
+       u32 i;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               for (i = 0x80000000; i <= 0x800000ff;) {
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_DESTID_SEL_CSR, i);
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               RIO_STD_RTE_CONF_PORT_SEL_CSR,
+                               (CPS_DEFAULT_ROUTE << 24) |
+                               (CPS_DEFAULT_ROUTE << 16) |
+                               (CPS_DEFAULT_ROUTE << 8) | CPS_DEFAULT_ROUTE);
+                       i += 4;
+               }
+       }
+
+       return 0;
+}
+
+static int
+idtcps_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u8 sw_domain)
+{
+       /*
+        * Switch domain configuration operates only at global level
+        */
+       rio_mport_write_config_32(mport, destid, hopcount,
+                                 IDTCPS_RIO_DOMAIN, (u32)sw_domain);
+       return 0;
+}
+
+static int
+idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u8 *sw_domain)
+{
+       u32 regval;
+
+       /*
+        * Switch domain configuration operates only at global level
+        */
+       rio_mport_read_config_32(mport, destid, hopcount,
+                               IDTCPS_RIO_DOMAIN, &regval);
+
+       *sw_domain = (u8)(regval & 0xff);
+
+       return 0;
+}
+
+static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       rdev->rswitch->add_entry = idtcps_route_add_entry;
+       rdev->rswitch->get_entry = idtcps_route_get_entry;
+       rdev->rswitch->clr_table = idtcps_route_clr_table;
+       rdev->rswitch->set_domain = idtcps_set_domain;
+       rdev->rswitch->get_domain = idtcps_get_domain;
+       rdev->rswitch->em_init = NULL;
+       rdev->rswitch->em_handle = NULL;
+
+       return 0;
+}
+
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS6Q, idtcps_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS8, idtcps_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS10Q, idtcps_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS12, idtcps_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS16, idtcps_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDT70K200, idtcps_switch_init);
index c77c23bd9840d8e76c4a6b11d218f1ac17fbd08a..914eddd5aa42a86a06965881fd5ab27174013e0b 100644 (file)
@@ -1,6 +1,10 @@
 /*
  * RapidIO Tsi500 switch support
  *
+ * Copyright 2009-2010 Integrated Device Technology, Inc.
+ * Alexandre Bounine <alexandre.bounine@idt.com>
+ *  - Modified switch operations initialization.
+ *
  * Copyright 2005 MontaVista Software, Inc.
  * Matt Porter <mporter@kernel.crashing.org>
  *
@@ -57,4 +61,18 @@ tsi500_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 tab
        return ret;
 }
 
-DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_route_add_entry, tsi500_route_get_entry);
+static int tsi500_switch_init(struct rio_dev *rdev, int do_enum)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       rdev->rswitch->add_entry = tsi500_route_add_entry;
+       rdev->rswitch->get_entry = tsi500_route_get_entry;
+       rdev->rswitch->clr_table = NULL;
+       rdev->rswitch->set_domain = NULL;
+       rdev->rswitch->get_domain = NULL;
+       rdev->rswitch->em_init = NULL;
+       rdev->rswitch->em_handle = NULL;
+
+       return 0;
+}
+
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_switch_init);
diff --git a/drivers/rapidio/switches/tsi568.c b/drivers/rapidio/switches/tsi568.c
new file mode 100644 (file)
index 0000000..f7fd789
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * RapidIO Tsi568 switch support
+ *
+ * Copyright 2009-2010 Integrated Device Technology, Inc.
+ * Alexandre Bounine <alexandre.bounine@idt.com>
+ *  - Added EM support
+ *  - Modified switch operations initialization.
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include <linux/delay.h>
+#include "../rio.h"
+
+/* Global (broadcast) route registers */
+#define SPBC_ROUTE_CFG_DESTID  0x10070
+#define SPBC_ROUTE_CFG_PORT    0x10074
+
+/* Per port route registers */
+#define SPP_ROUTE_CFG_DESTID(n)        (0x11070 + 0x100*n)
+#define SPP_ROUTE_CFG_PORT(n)  (0x11074 + 0x100*n)
+
+#define TSI568_SP_MODE_BC      0x10004
+#define  TSI568_SP_MODE_PW_DIS 0x08000000
+
+static int
+tsi568_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 route_port)
+{
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPBC_ROUTE_CFG_DESTID, route_destid);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPBC_ROUTE_CFG_PORT, route_port);
+       } else {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPP_ROUTE_CFG_DESTID(table),
+                                       route_destid);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPP_ROUTE_CFG_PORT(table), route_port);
+       }
+
+       udelay(10);
+
+       return 0;
+}
+
+static int
+tsi568_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 *route_port)
+{
+       int ret = 0;
+       u32 result;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPBC_ROUTE_CFG_DESTID, route_destid);
+               rio_mport_read_config_32(mport, destid, hopcount,
+                                       SPBC_ROUTE_CFG_PORT, &result);
+       } else {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPP_ROUTE_CFG_DESTID(table),
+                                       route_destid);
+               rio_mport_read_config_32(mport, destid, hopcount,
+                                       SPP_ROUTE_CFG_PORT(table), &result);
+       }
+
+       *route_port = result;
+       if (*route_port > 15)
+               ret = -1;
+
+       return ret;
+}
+
+static int
+tsi568_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table)
+{
+       u32 route_idx;
+       u32 lut_size;
+
+       lut_size = (mport->sys_size) ? 0x1ff : 0xff;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPBC_ROUTE_CFG_DESTID, 0x80000000);
+               for (route_idx = 0; route_idx <= lut_size; route_idx++)
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                               SPBC_ROUTE_CFG_PORT,
+                                               RIO_INVALID_ROUTE);
+       } else {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                       SPP_ROUTE_CFG_DESTID(table),
+                                       0x80000000);
+               for (route_idx = 0; route_idx <= lut_size; route_idx++)
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                               SPP_ROUTE_CFG_PORT(table),
+                                               RIO_INVALID_ROUTE);
+       }
+
+       return 0;
+}
+
+static int
+tsi568_em_init(struct rio_dev *rdev)
+{
+       struct rio_mport *mport = rdev->net->hport;
+       u16 destid = rdev->rswitch->destid;
+       u8 hopcount = rdev->rswitch->hopcount;
+       u32 regval;
+
+       pr_debug("TSI568 %s [%d:%d]\n", __func__, destid, hopcount);
+
+       /* Make sure that Port-Writes are disabled (for all ports) */
+       rio_mport_read_config_32(mport, destid, hopcount,
+                       TSI568_SP_MODE_BC, &regval);
+       rio_mport_write_config_32(mport, destid, hopcount,
+                       TSI568_SP_MODE_BC, regval | TSI568_SP_MODE_PW_DIS);
+
+       return 0;
+}
+
+static int tsi568_switch_init(struct rio_dev *rdev, int do_enum)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       rdev->rswitch->add_entry = tsi568_route_add_entry;
+       rdev->rswitch->get_entry = tsi568_route_get_entry;
+       rdev->rswitch->clr_table = tsi568_route_clr_table;
+       rdev->rswitch->set_domain = NULL;
+       rdev->rswitch->get_domain = NULL;
+       rdev->rswitch->em_init = tsi568_em_init;
+       rdev->rswitch->em_handle = NULL;
+
+       return 0;
+}
+
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_switch_init);
diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c
new file mode 100644 (file)
index 0000000..d34df72
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * RapidIO Tsi57x switch family support
+ *
+ * Copyright 2009-2010 Integrated Device Technology, Inc.
+ * Alexandre Bounine <alexandre.bounine@idt.com>
+ *  - Added EM support
+ *  - Modified switch operations initialization.
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include <linux/delay.h>
+#include "../rio.h"
+
+/* Global (broadcast) route registers */
+#define SPBC_ROUTE_CFG_DESTID  0x10070
+#define SPBC_ROUTE_CFG_PORT    0x10074
+
+/* Per port route registers */
+#define SPP_ROUTE_CFG_DESTID(n)        (0x11070 + 0x100*n)
+#define SPP_ROUTE_CFG_PORT(n)  (0x11074 + 0x100*n)
+
+#define TSI578_SP_MODE(n)      (0x11004 + n*0x100)
+#define TSI578_SP_MODE_GLBL    0x10004
+#define  TSI578_SP_MODE_PW_DIS 0x08000000
+#define  TSI578_SP_MODE_LUT_512        0x01000000
+
+#define TSI578_SP_CTL_INDEP(n) (0x13004 + n*0x100)
+#define TSI578_SP_LUT_PEINF(n) (0x13010 + n*0x100)
+#define TSI578_SP_CS_TX(n)     (0x13014 + n*0x100)
+#define TSI578_SP_INT_STATUS(n) (0x13018 + n*0x100)
+
+#define TSI578_GLBL_ROUTE_BASE 0x10078
+
+static int
+tsi57x_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 route_port)
+{
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                         SPBC_ROUTE_CFG_DESTID, route_destid);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                         SPBC_ROUTE_CFG_PORT, route_port);
+       } else {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_DESTID(table), route_destid);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_PORT(table), route_port);
+       }
+
+       udelay(10);
+
+       return 0;
+}
+
+static int
+tsi57x_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table, u16 route_destid, u8 *route_port)
+{
+       int ret = 0;
+       u32 result;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               /* Use local RT of the ingress port to avoid possible
+                  race condition */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                       RIO_SWP_INFO_CAR, &result);
+               table = (result & RIO_SWP_INFO_PORT_NUM_MASK);
+       }
+
+       rio_mport_write_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_DESTID(table), route_destid);
+       rio_mport_read_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_PORT(table), &result);
+
+       *route_port = (u8)result;
+       if (*route_port > 15)
+               ret = -1;
+
+       return ret;
+}
+
+static int
+tsi57x_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u16 table)
+{
+       u32 route_idx;
+       u32 lut_size;
+
+       lut_size = (mport->sys_size) ? 0x1ff : 0xff;
+
+       if (table == RIO_GLOBAL_TABLE) {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                                         SPBC_ROUTE_CFG_DESTID, 0x80000000);
+               for (route_idx = 0; route_idx <= lut_size; route_idx++)
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                                 SPBC_ROUTE_CFG_PORT,
+                                                 RIO_INVALID_ROUTE);
+       } else {
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_DESTID(table), 0x80000000);
+               for (route_idx = 0; route_idx <= lut_size; route_idx++)
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               SPP_ROUTE_CFG_PORT(table) , RIO_INVALID_ROUTE);
+       }
+
+       return 0;
+}
+
+static int
+tsi57x_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u8 sw_domain)
+{
+       u32 regval;
+
+       /*
+        * Switch domain configuration operates only at global level
+        */
+
+       /* Turn off flat (LUT_512) mode */
+       rio_mport_read_config_32(mport, destid, hopcount,
+                                TSI578_SP_MODE_GLBL, &regval);
+       rio_mport_write_config_32(mport, destid, hopcount, TSI578_SP_MODE_GLBL,
+                                 regval & ~TSI578_SP_MODE_LUT_512);
+       /* Set switch domain base */
+       rio_mport_write_config_32(mport, destid, hopcount,
+                                 TSI578_GLBL_ROUTE_BASE,
+                                 (u32)(sw_domain << 24));
+       return 0;
+}
+
+static int
+tsi57x_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
+                      u8 *sw_domain)
+{
+       u32 regval;
+
+       /*
+        * Switch domain configuration operates only at global level
+        */
+       rio_mport_read_config_32(mport, destid, hopcount,
+                               TSI578_GLBL_ROUTE_BASE, &regval);
+
+       *sw_domain = (u8)(regval >> 24);
+
+       return 0;
+}
+
+static int
+tsi57x_em_init(struct rio_dev *rdev)
+{
+       struct rio_mport *mport = rdev->net->hport;
+       u16 destid = rdev->rswitch->destid;
+       u8 hopcount = rdev->rswitch->hopcount;
+       u32 regval;
+       int portnum;
+
+       pr_debug("TSI578 %s [%d:%d]\n", __func__, destid, hopcount);
+
+       for (portnum = 0; portnum < 16; portnum++) {
+               /* Make sure that Port-Writes are enabled (for all ports) */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               TSI578_SP_MODE(portnum), &regval);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               TSI578_SP_MODE(portnum),
+                               regval & ~TSI578_SP_MODE_PW_DIS);
+
+               /* Clear all pending interrupts */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr +
+                                       RIO_PORT_N_ERR_STS_CSR(portnum),
+                               &regval);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr +
+                                       RIO_PORT_N_ERR_STS_CSR(portnum),
+                               regval & 0x07120214);
+
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               TSI578_SP_INT_STATUS(portnum), &regval);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               TSI578_SP_INT_STATUS(portnum),
+                               regval & 0x000700bd);
+
+               /* Enable all interrupts to allow ports to send a port-write */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               TSI578_SP_CTL_INDEP(portnum), &regval);
+               rio_mport_write_config_32(mport, destid, hopcount,
+                               TSI578_SP_CTL_INDEP(portnum),
+                               regval | 0x000b0000);
+
+               /* Skip next (odd) port if the current port is in x4 mode */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                               &regval);
+               if ((regval & RIO_PORT_N_CTL_PWIDTH) == RIO_PORT_N_CTL_PWIDTH_4)
+                       portnum++;
+       }
+
+       return 0;
+}
+
+static int
+tsi57x_em_handler(struct rio_dev *rdev, u8 portnum)
+{
+       struct rio_mport *mport = rdev->net->hport;
+       u16 destid = rdev->rswitch->destid;
+       u8 hopcount = rdev->rswitch->hopcount;
+       u32 intstat, err_status;
+       int sendcount, checkcount;
+       u8 route_port;
+       u32 regval;
+
+       rio_mport_read_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
+                       &err_status);
+
+       if ((err_status & RIO_PORT_N_ERR_STS_PORT_OK) &&
+           (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
+                         RIO_PORT_N_ERR_STS_PW_INP_ES))) {
+               /* Remove any queued packets by locking/unlocking port */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                       &regval);
+               if (!(regval & RIO_PORT_N_CTL_LOCKOUT)) {
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                               regval | RIO_PORT_N_CTL_LOCKOUT);
+                       udelay(50);
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                               rdev->phys_efptr + RIO_PORT_N_CTL_CSR(portnum),
+                               regval);
+               }
+
+               /* Read from link maintenance response register to clear
+                * valid bit
+                */
+               rio_mport_read_config_32(mport, destid, hopcount,
+                       rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(portnum),
+                       &regval);
+
+               /* Send a Packet-Not-Accepted/Link-Request-Input-Status control
+                * symbol to recover from IES/OES
+                */
+               sendcount = 3;
+               while (sendcount) {
+                       rio_mport_write_config_32(mport, destid, hopcount,
+                                         TSI578_SP_CS_TX(portnum), 0x40fc8000);
+                       checkcount = 3;
+                       while (checkcount--) {
+                               udelay(50);
+                               rio_mport_read_config_32(
+                                       mport, destid, hopcount,
+                                       rdev->phys_efptr +
+                                               RIO_PORT_N_MNT_RSP_CSR(portnum),
+                                       &regval);
+                               if (regval & RIO_PORT_N_MNT_RSP_RVAL)
+                                       goto exit_es;
+                       }
+
+                       sendcount--;
+               }
+       }
+
+exit_es:
+       /* Clear implementation specific error status bits */
+       rio_mport_read_config_32(mport, destid, hopcount,
+                                TSI578_SP_INT_STATUS(portnum), &intstat);
+       pr_debug("TSI578[%x:%x] SP%d_INT_STATUS=0x%08x\n",
+                destid, hopcount, portnum, intstat);
+
+       if (intstat & 0x10000) {
+               rio_mport_read_config_32(mport, destid, hopcount,
+                               TSI578_SP_LUT_PEINF(portnum), &regval);
+               regval = (mport->sys_size) ? (regval >> 16) : (regval >> 24);
+               route_port = rdev->rswitch->route_table[regval];
+               pr_debug("RIO: TSI578[%s] P%d LUT Parity Error (destID=%d)\n",
+                       rio_name(rdev), portnum, regval);
+               tsi57x_route_add_entry(mport, destid, hopcount,
+                               RIO_GLOBAL_TABLE, regval, route_port);
+       }
+
+       rio_mport_write_config_32(mport, destid, hopcount,
+                                 TSI578_SP_INT_STATUS(portnum),
+                                 intstat & 0x000700bd);
+
+       return 0;
+}
+
+static int tsi57x_switch_init(struct rio_dev *rdev, int do_enum)
+{
+       pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+       rdev->rswitch->add_entry = tsi57x_route_add_entry;
+       rdev->rswitch->get_entry = tsi57x_route_get_entry;
+       rdev->rswitch->clr_table = tsi57x_route_clr_table;
+       rdev->rswitch->set_domain = tsi57x_set_domain;
+       rdev->rswitch->get_domain = tsi57x_get_domain;
+       rdev->rswitch->em_init = tsi57x_em_init;
+       rdev->rswitch->em_handle = tsi57x_em_handler;
+
+       return 0;
+}
+
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI572, tsi57x_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_switch_init);
+DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_switch_init);
index f1598324344cd2365bac974519b9752ea0e912ce..10ba12c8c5e004a044c59ec7a77a91f58cf8f61e 100644 (file)
@@ -611,6 +611,13 @@ config RTC_DRV_AB3100
          Select this to enable the ST-Ericsson AB3100 Mixed Signal IC RTC
          support. This chip contains a battery- and capacitor-backed RTC.
 
+config RTC_DRV_AB8500
+       tristate "ST-Ericsson AB8500 RTC"
+       depends on AB8500_CORE
+       help
+         Select this to enable the ST-Ericsson AB8500 power management IC RTC
+         support. This chip contains a battery- and capacitor-backed RTC.
+
 config RTC_DRV_NUC900
        tristate "NUC910/NUC920 RTC driver"
        depends on RTC_CLASS && ARCH_W90X900
index 245311a1348fdae26755b76d153c7e4f2dcb8507..5adbba7cf89cfdde453caf77e4571ab1786b9b16 100644 (file)
@@ -18,6 +18,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
 # Keep the list ordered.
 
 obj-$(CONFIG_RTC_DRV_AB3100)   += rtc-ab3100.o
+obj-$(CONFIG_RTC_DRV_AB8500)   += rtc-ab8500.o
 obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
 obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
 obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
new file mode 100644 (file)
index 0000000..2fda031
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>
+ *
+ * RTC clock driver for the RTC part of the AB8500 Power management chip.
+ * Based on RTC clock driver for the AB3100 Analog Baseband Chip by
+ * Linus Walleij <linus.walleij@stericsson.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/mfd/ab8500.h>
+#include <linux/delay.h>
+
+#define AB8500_RTC_SOFF_STAT_REG       0x0F00
+#define AB8500_RTC_CC_CONF_REG         0x0F01
+#define AB8500_RTC_READ_REQ_REG                0x0F02
+#define AB8500_RTC_WATCH_TSECMID_REG   0x0F03
+#define AB8500_RTC_WATCH_TSECHI_REG    0x0F04
+#define AB8500_RTC_WATCH_TMIN_LOW_REG  0x0F05
+#define AB8500_RTC_WATCH_TMIN_MID_REG  0x0F06
+#define AB8500_RTC_WATCH_TMIN_HI_REG   0x0F07
+#define AB8500_RTC_ALRM_MIN_LOW_REG    0x0F08
+#define AB8500_RTC_ALRM_MIN_MID_REG    0x0F09
+#define AB8500_RTC_ALRM_MIN_HI_REG     0x0F0A
+#define AB8500_RTC_STAT_REG            0x0F0B
+#define AB8500_RTC_BKUP_CHG_REG                0x0F0C
+#define AB8500_RTC_FORCE_BKUP_REG      0x0F0D
+#define AB8500_RTC_CALIB_REG           0x0F0E
+#define AB8500_RTC_SWITCH_STAT_REG     0x0F0F
+#define AB8500_REV_REG                 0x1080
+
+/* RtcReadRequest bits */
+#define RTC_READ_REQUEST               0x01
+#define RTC_WRITE_REQUEST              0x02
+
+/* RtcCtrl bits */
+#define RTC_ALARM_ENA                  0x04
+#define RTC_STATUS_DATA                        0x01
+
+#define COUNTS_PER_SEC                 (0xF000 / 60)
+#define AB8500_RTC_EPOCH               2000
+
+static const unsigned long ab8500_rtc_time_regs[] = {
+       AB8500_RTC_WATCH_TMIN_HI_REG, AB8500_RTC_WATCH_TMIN_MID_REG,
+       AB8500_RTC_WATCH_TMIN_LOW_REG, AB8500_RTC_WATCH_TSECHI_REG,
+       AB8500_RTC_WATCH_TSECMID_REG
+};
+
+static const unsigned long ab8500_rtc_alarm_regs[] = {
+       AB8500_RTC_ALRM_MIN_HI_REG, AB8500_RTC_ALRM_MIN_MID_REG,
+       AB8500_RTC_ALRM_MIN_LOW_REG
+};
+
+/* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */
+static unsigned long get_elapsed_seconds(int year)
+{
+       unsigned long secs;
+       struct rtc_time tm = {
+               .tm_year = year - 1900,
+               .tm_mday = 1,
+       };
+
+       /*
+        * This function calculates secs from 1970 and not from
+        * 1900, even if we supply the offset from year 1900.
+        */
+       rtc_tm_to_time(&tm, &secs);
+       return secs;
+}
+
+static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+       unsigned long timeout = jiffies + HZ;
+       int retval, i;
+       unsigned long mins, secs;
+       unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
+
+       /* Request a data read */
+       retval = ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG,
+                             RTC_READ_REQUEST);
+       if (retval < 0)
+               return retval;
+
+       /* Early AB8500 chips will not clear the rtc read request bit */
+       if (ab8500->revision == 0) {
+               msleep(1);
+       } else {
+               /* Wait for some cycles after enabling the rtc read in ab8500 */
+               while (time_before(jiffies, timeout)) {
+                       retval = ab8500_read(ab8500, AB8500_RTC_READ_REQ_REG);
+                       if (retval < 0)
+                               return retval;
+
+                       if (!(retval & RTC_READ_REQUEST))
+                               break;
+
+                       msleep(1);
+               }
+       }
+
+       /* Read the Watchtime registers */
+       for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
+               retval = ab8500_read(ab8500, ab8500_rtc_time_regs[i]);
+               if (retval < 0)
+                       return retval;
+               buf[i] = retval;
+       }
+
+       mins = (buf[0] << 16) | (buf[1] << 8) | buf[2];
+
+       secs =  (buf[3] << 8) | buf[4];
+       secs =  secs / COUNTS_PER_SEC;
+       secs =  secs + (mins * 60);
+
+       /* Add back the initially subtracted number of seconds */
+       secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+       rtc_time_to_tm(secs, tm);
+       return rtc_valid_tm(tm);
+}
+
+static int ab8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+       int retval, i;
+       unsigned char buf[ARRAY_SIZE(ab8500_rtc_time_regs)];
+       unsigned long no_secs, no_mins, secs = 0;
+
+       if (tm->tm_year < (AB8500_RTC_EPOCH - 1900)) {
+               dev_dbg(dev, "year should be equal to or greater than %d\n",
+                               AB8500_RTC_EPOCH);
+               return -EINVAL;
+       }
+
+       /* Get the number of seconds since 1970 */
+       rtc_tm_to_time(tm, &secs);
+
+       /*
+        * Convert it to the number of seconds since 01-01-2000 00:00:00, since
+        * we only have a small counter in the RTC.
+        */
+       secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+       no_mins = secs / 60;
+
+       no_secs = secs % 60;
+       /* Make the seconds count as per the RTC resolution */
+       no_secs = no_secs * COUNTS_PER_SEC;
+
+       buf[4] = no_secs & 0xFF;
+       buf[3] = (no_secs >> 8) & 0xFF;
+
+       buf[2] = no_mins & 0xFF;
+       buf[1] = (no_mins >> 8) & 0xFF;
+       buf[0] = (no_mins >> 16) & 0xFF;
+
+       for (i = 0; i < ARRAY_SIZE(ab8500_rtc_time_regs); i++) {
+               retval = ab8500_write(ab8500, ab8500_rtc_time_regs[i], buf[i]);
+               if (retval < 0)
+                       return retval;
+       }
+
+       /* Request a data write */
+       return ab8500_write(ab8500, AB8500_RTC_READ_REQ_REG, RTC_WRITE_REQUEST);
+}
+
+static int ab8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+       int retval, i;
+       int rtc_ctrl;
+       unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
+       unsigned long secs, mins;
+
+       /* Check if the alarm is enabled or not */
+       rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
+       if (rtc_ctrl < 0)
+               return rtc_ctrl;
+
+       if (rtc_ctrl & RTC_ALARM_ENA)
+               alarm->enabled = 1;
+       else
+               alarm->enabled = 0;
+
+       alarm->pending = 0;
+
+       for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
+               retval = ab8500_read(ab8500, ab8500_rtc_alarm_regs[i]);
+               if (retval < 0)
+                       return retval;
+               buf[i] = retval;
+       }
+
+       mins = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
+       secs = mins * 60;
+
+       /* Add back the initially subtracted number of seconds */
+       secs += get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+       rtc_time_to_tm(secs, &alarm->time);
+
+       return rtc_valid_tm(&alarm->time);
+}
+
+static int ab8500_rtc_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+
+       return ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_ALARM_ENA,
+                              enabled ? RTC_ALARM_ENA : 0);
+}
+
+static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
+       int retval, i;
+       unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
+       unsigned long mins, secs = 0;
+
+       if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {
+               dev_dbg(dev, "year should be equal to or greater than %d\n",
+                               AB8500_RTC_EPOCH);
+               return -EINVAL;
+       }
+
+       /* Get the number of seconds since 1970 */
+       rtc_tm_to_time(&alarm->time, &secs);
+
+       /*
+        * Convert it to the number of seconds since 01-01-2000 00:00:00, since
+        * we only have a small counter in the RTC.
+        */
+       secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
+
+       mins = secs / 60;
+
+       buf[2] = mins & 0xFF;
+       buf[1] = (mins >> 8) & 0xFF;
+       buf[0] = (mins >> 16) & 0xFF;
+
+       /* Set the alarm time */
+       for (i = 0; i < ARRAY_SIZE(ab8500_rtc_alarm_regs); i++) {
+               retval = ab8500_write(ab8500, ab8500_rtc_alarm_regs[i], buf[i]);
+               if (retval < 0)
+                       return retval;
+       }
+
+       return ab8500_rtc_irq_enable(dev, alarm->enabled);
+}
+
+static irqreturn_t rtc_alarm_handler(int irq, void *data)
+{
+       struct rtc_device *rtc = data;
+       unsigned long events = RTC_IRQF | RTC_AF;
+
+       dev_dbg(&rtc->dev, "%s\n", __func__);
+       rtc_update_irq(rtc, 1, events);
+
+       return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops ab8500_rtc_ops = {
+       .read_time              = ab8500_rtc_read_time,
+       .set_time               = ab8500_rtc_set_time,
+       .read_alarm             = ab8500_rtc_read_alarm,
+       .set_alarm              = ab8500_rtc_set_alarm,
+       .alarm_irq_enable       = ab8500_rtc_irq_enable,
+};
+
+static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
+{
+       struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+       int err;
+       struct rtc_device *rtc;
+       int rtc_ctrl;
+       int irq;
+
+       irq = platform_get_irq_byname(pdev, "ALARM");
+       if (irq < 0)
+               return irq;
+
+       /* For RTC supply test */
+       err = ab8500_set_bits(ab8500, AB8500_RTC_STAT_REG, RTC_STATUS_DATA,
+                       RTC_STATUS_DATA);
+       if (err < 0)
+               return err;
+
+       /* Wait for reset by the PorRtc */
+       msleep(1);
+
+       rtc_ctrl = ab8500_read(ab8500, AB8500_RTC_STAT_REG);
+       if (rtc_ctrl < 0)
+               return rtc_ctrl;
+
+       /* Check if the RTC Supply fails */
+       if (!(rtc_ctrl & RTC_STATUS_DATA)) {
+               dev_err(&pdev->dev, "RTC supply failure\n");
+               return -ENODEV;
+       }
+
+       rtc = rtc_device_register("ab8500-rtc", &pdev->dev, &ab8500_rtc_ops,
+                       THIS_MODULE);
+       if (IS_ERR(rtc)) {
+               dev_err(&pdev->dev, "Registration failed\n");
+               err = PTR_ERR(rtc);
+               return err;
+       }
+
+       err = request_threaded_irq(irq, NULL, rtc_alarm_handler, 0,
+                                  "ab8500-rtc", rtc);
+       if (err < 0) {
+               rtc_device_unregister(rtc);
+               return err;
+       }
+
+       platform_set_drvdata(pdev, rtc);
+
+       return 0;
+}
+
+static int __devexit ab8500_rtc_remove(struct platform_device *pdev)
+{
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       int irq = platform_get_irq_byname(pdev, "ALARM");
+
+       free_irq(irq, rtc);
+       rtc_device_unregister(rtc);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver ab8500_rtc_driver = {
+       .driver = {
+               .name = "ab8500-rtc",
+               .owner = THIS_MODULE,
+       },
+       .probe  = ab8500_rtc_probe,
+       .remove = __devexit_p(ab8500_rtc_remove),
+};
+
+static int __init ab8500_rtc_init(void)
+{
+       return platform_driver_register(&ab8500_rtc_driver);
+}
+
+static void __exit ab8500_rtc_exit(void)
+{
+       platform_driver_unregister(&ab8500_rtc_driver);
+}
+
+module_init(ab8500_rtc_init);
+module_exit(ab8500_rtc_exit);
+MODULE_AUTHOR("Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>");
+MODULE_DESCRIPTION("AB8500 RTC Driver");
+MODULE_LICENSE("GPL v2");
index 038095d99976e294629873443866b63e7eb7d19e..6dc4e6241418ac601a40abf5dfb0744401d44d5d 100644 (file)
@@ -595,10 +595,6 @@ static void wdt_disable(void)
 static ssize_t wdt_write(struct file *file, const char __user *buf,
                         size_t count, loff_t *ppos)
 {
-       /*  Can't seek (pwrite) on this device
-       if (ppos != &file->f_pos)
-       return -ESPIPE;
-       */
        if (count) {
                wdt_ping();
                return 1;
@@ -707,7 +703,7 @@ static int wdt_open(struct inode *inode, struct file *file)
                 */
                wdt_is_open = 1;
                unlock_kernel();
-               return 0;
+               return nonseekable_open(inode, file);
        }
        return -ENODEV;
 }
index 308541ff85cf9ff127a118696bc2b62d0d6d255e..1bb5d3f0e260f1a94a74b15deb47301212784d19 100644 (file)
@@ -1,34 +1,31 @@
 #include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/zorro.h>
 
-#include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
-#include <linux/zorro.h>
-#include <asm/irq.h>
-#include <linux/spinlock.h>
 
 #include "scsi.h"
-#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "a2091.h"
 
-#include <linux/stat.h>
-
 
-static int a2091_release(struct Scsi_Host *instance);
+struct a2091_hostdata {
+       struct WD33C93_hostdata wh;
+       struct a2091_scsiregs *regs;
+};
 
 static irqreturn_t a2091_intr(int irq, void *data)
 {
        struct Scsi_Host *instance = data;
-       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
-       unsigned int status = regs->ISTR;
+       struct a2091_hostdata *hdata = shost_priv(instance);
+       unsigned int status = hdata->regs->ISTR;
        unsigned long flags;
 
        if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS))
@@ -43,38 +40,39 @@ static irqreturn_t a2091_intr(int irq, void *data)
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
        struct Scsi_Host *instance = cmd->device->host;
-       struct WD33C93_hostdata *hdata = shost_priv(instance);
-       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+       struct a2091_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct a2091_scsiregs *regs = hdata->regs;
        unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
        unsigned long addr = virt_to_bus(cmd->SCp.ptr);
 
        /* don't allow DMA if the physical address is bad */
        if (addr & A2091_XFER_MASK) {
-               hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
-               hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len,
-                                                  GFP_KERNEL);
+               wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+               wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len,
+                                               GFP_KERNEL);
 
                /* can't allocate memory; use PIO */
-               if (!hdata->dma_bounce_buffer) {
-                       hdata->dma_bounce_len = 0;
+               if (!wh->dma_bounce_buffer) {
+                       wh->dma_bounce_len = 0;
                        return 1;
                }
 
                /* get the physical address of the bounce buffer */
-               addr = virt_to_bus(hdata->dma_bounce_buffer);
+               addr = virt_to_bus(wh->dma_bounce_buffer);
 
                /* the bounce buffer may not be in the first 16M of physmem */
                if (addr & A2091_XFER_MASK) {
                        /* we could use chipmem... maybe later */
-                       kfree(hdata->dma_bounce_buffer);
-                       hdata->dma_bounce_buffer = NULL;
-                       hdata->dma_bounce_len = 0;
+                       kfree(wh->dma_bounce_buffer);
+                       wh->dma_bounce_buffer = NULL;
+                       wh->dma_bounce_len = 0;
                        return 1;
                }
 
                if (!dir_in) {
                        /* copy to bounce buffer for a write */
-                       memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+                       memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr,
                               cmd->SCp.this_residual);
                }
        }
@@ -84,7 +82,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
                cntr |= CNTR_DDIR;
 
        /* remember direction */
-       hdata->dma_dir = dir_in;
+       wh->dma_dir = dir_in;
 
        regs->CNTR = cntr;
 
@@ -108,20 +106,21 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
                     int status)
 {
-       struct WD33C93_hostdata *hdata = shost_priv(instance);
-       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+       struct a2091_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct a2091_scsiregs *regs = hdata->regs;
 
        /* disable SCSI interrupts */
        unsigned short cntr = CNTR_PDMD;
 
-       if (!hdata->dma_dir)
+       if (!wh->dma_dir)
                cntr |= CNTR_DDIR;
 
        /* disable SCSI interrupts */
        regs->CNTR = cntr;
 
        /* flush if we were reading */
-       if (hdata->dma_dir) {
+       if (wh->dma_dir) {
                regs->FLUSH = 1;
                while (!(regs->ISTR & ISTR_FE_FLG))
                        ;
@@ -137,95 +136,37 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
        regs->CNTR = CNTR_PDMD | CNTR_INTEN;
 
        /* copy from a bounce buffer, if necessary */
-       if (status && hdata->dma_bounce_buffer) {
-               if (hdata->dma_dir)
-                       memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
+       if (status && wh->dma_bounce_buffer) {
+               if (wh->dma_dir)
+                       memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer,
                               SCpnt->SCp.this_residual);
-               kfree(hdata->dma_bounce_buffer);
-               hdata->dma_bounce_buffer = NULL;
-               hdata->dma_bounce_len = 0;
-       }
-}
-
-static int __init a2091_detect(struct scsi_host_template *tpnt)
-{
-       static unsigned char called = 0;
-       struct Scsi_Host *instance;
-       unsigned long address;
-       struct zorro_dev *z = NULL;
-       wd33c93_regs wdregs;
-       a2091_scsiregs *regs;
-       struct WD33C93_hostdata *hdata;
-       int num_a2091 = 0;
-
-       if (!MACH_IS_AMIGA || called)
-               return 0;
-       called = 1;
-
-       tpnt->proc_name = "A2091";
-       tpnt->proc_info = &wd33c93_proc_info;
-
-       while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-               if (z->id != ZORRO_PROD_CBM_A590_A2091_1 &&
-                   z->id != ZORRO_PROD_CBM_A590_A2091_2)
-                       continue;
-               address = z->resource.start;
-               if (!request_mem_region(address, 256, "wd33c93"))
-                       continue;
-
-               instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
-               if (instance == NULL)
-                       goto release;
-               instance->base = ZTWO_VADDR(address);
-               instance->irq = IRQ_AMIGA_PORTS;
-               instance->unique_id = z->slotaddr;
-               regs = (a2091_scsiregs *)(instance->base);
-               regs->DAWR = DAWR_A2091;
-               wdregs.SASR = &regs->SASR;
-               wdregs.SCMD = &regs->SCMD;
-               hdata = shost_priv(instance);
-               hdata->no_sync = 0xff;
-               hdata->fast = 0;
-               hdata->dma_mode = CTRL_DMA;
-               wd33c93_init(instance, wdregs, dma_setup, dma_stop,
-                            WD33C93_FS_8_10);
-               if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED,
-                               "A2091 SCSI", instance))
-                       goto unregister;
-               regs->CNTR = CNTR_PDMD | CNTR_INTEN;
-               num_a2091++;
-               continue;
-
-unregister:
-               scsi_unregister(instance);
-release:
-               release_mem_region(address, 256);
+               kfree(wh->dma_bounce_buffer);
+               wh->dma_bounce_buffer = NULL;
+               wh->dma_bounce_len = 0;
        }
-
-       return num_a2091;
 }
 
 static int a2091_bus_reset(struct scsi_cmnd *cmd)
 {
+       struct Scsi_Host *instance = cmd->device->host;
+
        /* FIXME perform bus-specific reset */
 
        /* FIXME 2: kill this function, and let midlayer fall back
           to the same action, calling wd33c93_host_reset() */
 
-       spin_lock_irq(cmd->device->host->host_lock);
+       spin_lock_irq(instance->host_lock);
        wd33c93_host_reset(cmd);
-       spin_unlock_irq(cmd->device->host->host_lock);
+       spin_unlock_irq(instance->host_lock);
 
        return SUCCESS;
 }
 
-#define HOSTS_C
-
-static struct scsi_host_template driver_template = {
-       .proc_name              = "A2901",
+static struct scsi_host_template a2091_scsi_template = {
+       .module                 = THIS_MODULE,
        .name                   = "Commodore A2091/A590 SCSI",
-       .detect                 = a2091_detect,
-       .release                = a2091_release,
+       .proc_info              = wd33c93_proc_info,
+       .proc_name              = "A2901",
        .queuecommand           = wd33c93_queuecommand,
        .eh_abort_handler       = wd33c93_abort,
        .eh_bus_reset_handler   = a2091_bus_reset,
@@ -237,19 +178,103 @@ static struct scsi_host_template driver_template = {
        .use_clustering         = DISABLE_CLUSTERING
 };
 
+static int __devinit a2091_probe(struct zorro_dev *z,
+                                const struct zorro_device_id *ent)
+{
+       struct Scsi_Host *instance;
+       int error;
+       struct a2091_scsiregs *regs;
+       wd33c93_regs wdregs;
+       struct a2091_hostdata *hdata;
 
-#include "scsi_module.c"
+       if (!request_mem_region(z->resource.start, 256, "wd33c93"))
+               return -EBUSY;
 
-static int a2091_release(struct Scsi_Host *instance)
+       instance = scsi_host_alloc(&a2091_scsi_template,
+                                  sizeof(struct a2091_hostdata));
+       if (!instance) {
+               error = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       instance->irq = IRQ_AMIGA_PORTS;
+       instance->unique_id = z->slotaddr;
+
+       regs = (struct a2091_scsiregs *)ZTWO_VADDR(z->resource.start);
+       regs->DAWR = DAWR_A2091;
+
+       wdregs.SASR = &regs->SASR;
+       wdregs.SCMD = &regs->SCMD;
+
+       hdata = shost_priv(instance);
+       hdata->wh.no_sync = 0xff;
+       hdata->wh.fast = 0;
+       hdata->wh.dma_mode = CTRL_DMA;
+       hdata->regs = regs;
+
+       wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_8_10);
+       error = request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED,
+                           "A2091 SCSI", instance);
+       if (error)
+               goto fail_irq;
+
+       regs->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+       error = scsi_add_host(instance, NULL);
+       if (error)
+               goto fail_host;
+
+       zorro_set_drvdata(z, instance);
+
+       scsi_scan_host(instance);
+       return 0;
+
+fail_host:
+       free_irq(IRQ_AMIGA_PORTS, instance);
+fail_irq:
+       scsi_host_put(instance);
+fail_alloc:
+       release_mem_region(z->resource.start, 256);
+       return error;
+}
+
+static void __devexit a2091_remove(struct zorro_dev *z)
 {
-#ifdef MODULE
-       a2091_scsiregs *regs = (a2091_scsiregs *)(instance->base);
+       struct Scsi_Host *instance = zorro_get_drvdata(z);
+       struct a2091_hostdata *hdata = shost_priv(instance);
 
-       regs->CNTR = 0;
-       release_mem_region(ZTWO_PADDR(instance->base), 256);
+       hdata->regs->CNTR = 0;
+       scsi_remove_host(instance);
        free_irq(IRQ_AMIGA_PORTS, instance);
-#endif
-       return 1;
+       scsi_host_put(instance);
+       release_mem_region(z->resource.start, 256);
+}
+
+static struct zorro_device_id a2091_zorro_tbl[] __devinitdata = {
+       { ZORRO_PROD_CBM_A590_A2091_1 },
+       { ZORRO_PROD_CBM_A590_A2091_2 },
+       { 0 }
+};
+MODULE_DEVICE_TABLE(zorro, a2091_zorro_tbl);
+
+static struct zorro_driver a2091_driver = {
+       .name           = "a2091",
+       .id_table       = a2091_zorro_tbl,
+       .probe          = a2091_probe,
+       .remove         = __devexit_p(a2091_remove),
+};
+
+static int __init a2091_init(void)
+{
+       return zorro_register_driver(&a2091_driver);
+}
+module_init(a2091_init);
+
+static void __exit a2091_exit(void)
+{
+       zorro_unregister_driver(&a2091_driver);
 }
+module_exit(a2091_exit);
 
+MODULE_DESCRIPTION("Commodore A2091/A590 SCSI");
 MODULE_LICENSE("GPL");
index 1c3daa1fd754000b9a7d2d0a0ccb06c50d76b939..794b8e65c71133a565ada330ee8622732bcd402d 100644 (file)
@@ -25,7 +25,7 @@
  */
 #define A2091_XFER_MASK                (0xff000001)
 
-typedef struct {
+struct a2091_scsiregs {
                 unsigned char  pad1[64];
        volatile unsigned short ISTR;
        volatile unsigned short CNTR;
@@ -44,7 +44,7 @@ typedef struct {
        volatile unsigned short CINT;
                 unsigned char  pad7[2];
        volatile unsigned short FLUSH;
-} a2091_scsiregs;
+};
 
 #define DAWR_A2091             (3)
 
index bc6eb69f5fd09554ffe714e5339e3e9ec67b7a40..d9468027fb6150caed5a9854623b5673ddff58a4 100644 (file)
@@ -1,53 +1,52 @@
 #include <linux/types.h>
 #include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
 
-#include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
-#include <asm/irq.h>
 
 #include "scsi.h"
-#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "a3000.h"
 
-#include <linux/stat.h>
-
 
-#define DMA(ptr)       ((a3000_scsiregs *)((ptr)->base))
-
-static struct Scsi_Host *a3000_host = NULL;
-
-static int a3000_release(struct Scsi_Host *instance);
+struct a3000_hostdata {
+       struct WD33C93_hostdata wh;
+       struct a3000_scsiregs *regs;
+};
 
-static irqreturn_t a3000_intr(int irq, void *dummy)
+static irqreturn_t a3000_intr(int irq, void *data)
 {
+       struct Scsi_Host *instance = data;
+       struct a3000_hostdata *hdata = shost_priv(instance);
+       unsigned int status = hdata->regs->ISTR;
        unsigned long flags;
-       unsigned int status = DMA(a3000_host)->ISTR;
 
        if (!(status & ISTR_INT_P))
                return IRQ_NONE;
        if (status & ISTR_INTS) {
-               spin_lock_irqsave(a3000_host->host_lock, flags);
-               wd33c93_intr(a3000_host);
-               spin_unlock_irqrestore(a3000_host->host_lock, flags);
+               spin_lock_irqsave(instance->host_lock, flags);
+               wd33c93_intr(instance);
+               spin_unlock_irqrestore(instance->host_lock, flags);
                return IRQ_HANDLED;
        }
-       printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
+       pr_warning("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
        return IRQ_NONE;
 }
 
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
-       struct WD33C93_hostdata *hdata = shost_priv(a3000_host);
+       struct Scsi_Host *instance = cmd->device->host;
+       struct a3000_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct a3000_scsiregs *regs = hdata->regs;
        unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
        unsigned long addr = virt_to_bus(cmd->SCp.ptr);
 
@@ -58,23 +57,23 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
         * buffer
         */
        if (addr & A3000_XFER_MASK) {
-               hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
-               hdata->dma_bounce_buffer = kmalloc(hdata->dma_bounce_len,
-                                                  GFP_KERNEL);
+               wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+               wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len,
+                                               GFP_KERNEL);
 
                /* can't allocate memory; use PIO */
-               if (!hdata->dma_bounce_buffer) {
-                       hdata->dma_bounce_len = 0;
+               if (!wh->dma_bounce_buffer) {
+                       wh->dma_bounce_len = 0;
                        return 1;
                }
 
                if (!dir_in) {
                        /* copy to bounce buffer for a write */
-                       memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+                       memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr,
                               cmd->SCp.this_residual);
                }
 
-               addr = virt_to_bus(hdata->dma_bounce_buffer);
+               addr = virt_to_bus(wh->dma_bounce_buffer);
        }
 
        /* setup dma direction */
@@ -82,12 +81,12 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
                cntr |= CNTR_DDIR;
 
        /* remember direction */
-       hdata->dma_dir = dir_in;
+       wh->dma_dir = dir_in;
 
-       DMA(a3000_host)->CNTR = cntr;
+       regs->CNTR = cntr;
 
        /* setup DMA *physical* address */
-       DMA(a3000_host)->ACR = addr;
+       regs->ACR = addr;
 
        if (dir_in) {
                /* invalidate any cache */
@@ -99,7 +98,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 
        /* start DMA */
        mb();                   /* make sure setup is completed */
-       DMA(a3000_host)->ST_DMA = 1;
+       regs->ST_DMA = 1;
        mb();                   /* make sure DMA has started before next IO */
 
        /* return success */
@@ -109,22 +108,24 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
                     int status)
 {
-       struct WD33C93_hostdata *hdata = shost_priv(instance);
+       struct a3000_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct a3000_scsiregs *regs = hdata->regs;
 
        /* disable SCSI interrupts */
        unsigned short cntr = CNTR_PDMD;
 
-       if (!hdata->dma_dir)
+       if (!wh->dma_dir)
                cntr |= CNTR_DDIR;
 
-       DMA(instance)->CNTR = cntr;
+       regs->CNTR = cntr;
        mb();                   /* make sure CNTR is updated before next IO */
 
        /* flush if we were reading */
-       if (hdata->dma_dir) {
-               DMA(instance)->FLUSH = 1;
+       if (wh->dma_dir) {
+               regs->FLUSH = 1;
                mb();           /* don't allow prefetch */
-               while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
+               while (!(regs->ISTR & ISTR_FE_FLG))
                        barrier();
                mb();           /* no IO until FLUSH is done */
        }
@@ -133,96 +134,54 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
        /* I think that this CINT is only necessary if you are
         * using the terminal count features.   HM 7 Mar 1994
         */
-       DMA(instance)->CINT = 1;
+       regs->CINT = 1;
 
        /* stop DMA */
-       DMA(instance)->SP_DMA = 1;
+       regs->SP_DMA = 1;
        mb();                   /* make sure DMA is stopped before next IO */
 
        /* restore the CONTROL bits (minus the direction flag) */
-       DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+       regs->CNTR = CNTR_PDMD | CNTR_INTEN;
        mb();                   /* make sure CNTR is updated before next IO */
 
        /* copy from a bounce buffer, if necessary */
-       if (status && hdata->dma_bounce_buffer) {
+       if (status && wh->dma_bounce_buffer) {
                if (SCpnt) {
-                       if (hdata->dma_dir && SCpnt)
-                               memcpy(SCpnt->SCp.ptr,
-                                      hdata->dma_bounce_buffer,
+                       if (wh->dma_dir && SCpnt)
+                               memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer,
                                       SCpnt->SCp.this_residual);
-                       kfree(hdata->dma_bounce_buffer);
-                       hdata->dma_bounce_buffer = NULL;
-                       hdata->dma_bounce_len = 0;
+                       kfree(wh->dma_bounce_buffer);
+                       wh->dma_bounce_buffer = NULL;
+                       wh->dma_bounce_len = 0;
                } else {
-                       kfree(hdata->dma_bounce_buffer);
-                       hdata->dma_bounce_buffer = NULL;
-                       hdata->dma_bounce_len = 0;
+                       kfree(wh->dma_bounce_buffer);
+                       wh->dma_bounce_buffer = NULL;
+                       wh->dma_bounce_len = 0;
                }
        }
 }
 
-static int __init a3000_detect(struct scsi_host_template *tpnt)
-{
-       wd33c93_regs regs;
-       struct WD33C93_hostdata *hdata;
-
-       if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
-               return 0;
-       if (!request_mem_region(0xDD0000, 256, "wd33c93"))
-               return 0;
-
-       tpnt->proc_name = "A3000";
-       tpnt->proc_info = &wd33c93_proc_info;
-
-       a3000_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
-       if (a3000_host == NULL)
-               goto fail_register;
-
-       a3000_host->base = ZTWO_VADDR(0xDD0000);
-       a3000_host->irq = IRQ_AMIGA_PORTS;
-       DMA(a3000_host)->DAWR = DAWR_A3000;
-       regs.SASR = &(DMA(a3000_host)->SASR);
-       regs.SCMD = &(DMA(a3000_host)->SCMD);
-       hdata = shost_priv(a3000_host);
-       hdata->no_sync = 0xff;
-       hdata->fast = 0;
-       hdata->dma_mode = CTRL_DMA;
-       wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
-       if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
-                       a3000_intr))
-               goto fail_irq;
-       DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
-
-       return 1;
-
-fail_irq:
-       scsi_unregister(a3000_host);
-fail_register:
-       release_mem_region(0xDD0000, 256);
-       return 0;
-}
-
 static int a3000_bus_reset(struct scsi_cmnd *cmd)
 {
+       struct Scsi_Host *instance = cmd->device->host;
+
        /* FIXME perform bus-specific reset */
 
        /* FIXME 2: kill this entire function, which should
           cause mid-layer to call wd33c93_host_reset anyway? */
 
-       spin_lock_irq(cmd->device->host->host_lock);
+       spin_lock_irq(instance->host_lock);
        wd33c93_host_reset(cmd);
-       spin_unlock_irq(cmd->device->host->host_lock);
+       spin_unlock_irq(instance->host_lock);
 
        return SUCCESS;
 }
 
-#define HOSTS_C
-
-static struct scsi_host_template driver_template = {
-       .proc_name              = "A3000",
+static struct scsi_host_template amiga_a3000_scsi_template = {
+       .module                 = THIS_MODULE,
        .name                   = "Amiga 3000 built-in SCSI",
-       .detect                 = a3000_detect,
-       .release                = a3000_release,
+       .proc_info              = wd33c93_proc_info,
+       .proc_name              = "A3000",
        .queuecommand           = wd33c93_queuecommand,
        .eh_abort_handler       = wd33c93_abort,
        .eh_bus_reset_handler   = a3000_bus_reset,
@@ -234,15 +193,104 @@ static struct scsi_host_template driver_template = {
        .use_clustering         = ENABLE_CLUSTERING
 };
 
+static int __init amiga_a3000_scsi_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct Scsi_Host *instance;
+       int error;
+       struct a3000_scsiregs *regs;
+       wd33c93_regs wdregs;
+       struct a3000_hostdata *hdata;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       if (!request_mem_region(res->start, resource_size(res), "wd33c93"))
+               return -EBUSY;
+
+       instance = scsi_host_alloc(&amiga_a3000_scsi_template,
+                                  sizeof(struct a3000_hostdata));
+       if (!instance) {
+               error = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       instance->irq = IRQ_AMIGA_PORTS;
 
-#include "scsi_module.c"
+       regs = (struct a3000_scsiregs *)ZTWO_VADDR(res->start);
+       regs->DAWR = DAWR_A3000;
+
+       wdregs.SASR = &regs->SASR;
+       wdregs.SCMD = &regs->SCMD;
+
+       hdata = shost_priv(instance);
+       hdata->wh.no_sync = 0xff;
+       hdata->wh.fast = 0;
+       hdata->wh.dma_mode = CTRL_DMA;
+       hdata->regs = regs;
+
+       wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15);
+       error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED,
+                           "A3000 SCSI", instance);
+       if (error)
+               goto fail_irq;
+
+       regs->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+       error = scsi_add_host(instance, NULL);
+       if (error)
+               goto fail_host;
+
+       platform_set_drvdata(pdev, instance);
+
+       scsi_scan_host(instance);
+       return 0;
+
+fail_host:
+       free_irq(IRQ_AMIGA_PORTS, instance);
+fail_irq:
+       scsi_host_put(instance);
+fail_alloc:
+       release_mem_region(res->start, resource_size(res));
+       return error;
+}
+
+static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev)
+{
+       struct Scsi_Host *instance = platform_get_drvdata(pdev);
+       struct a3000_hostdata *hdata = shost_priv(instance);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       hdata->regs->CNTR = 0;
+       scsi_remove_host(instance);
+       free_irq(IRQ_AMIGA_PORTS, instance);
+       scsi_host_put(instance);
+       release_mem_region(res->start, resource_size(res));
+       return 0;
+}
+
+static struct platform_driver amiga_a3000_scsi_driver = {
+       .remove = __exit_p(amiga_a3000_scsi_remove),
+       .driver   = {
+               .name   = "amiga-a3000-scsi",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init amiga_a3000_scsi_init(void)
+{
+       return platform_driver_probe(&amiga_a3000_scsi_driver,
+                                    amiga_a3000_scsi_probe);
+}
+module_init(amiga_a3000_scsi_init);
 
-static int a3000_release(struct Scsi_Host *instance)
+static void __exit amiga_a3000_scsi_exit(void)
 {
-       DMA(instance)->CNTR = 0;
-       release_mem_region(0xDD0000, 256);
-       free_irq(IRQ_AMIGA_PORTS, a3000_intr);
-       return 1;
+       platform_driver_unregister(&amiga_a3000_scsi_driver);
 }
+module_exit(amiga_a3000_scsi_exit);
 
+MODULE_DESCRIPTION("Amiga 3000 built-in SCSI");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:amiga-a3000-scsi");
index 684813ee378c485cb5060b3ba9cfbcf483981bc6..49db4a335aaba4152ea553af335014fc234b74d2 100644 (file)
@@ -25,7 +25,7 @@
  */
 #define A3000_XFER_MASK                (0x00000003)
 
-typedef struct {
+struct a3000_scsiregs {
                 unsigned char  pad1[2];
        volatile unsigned short DAWR;
        volatile unsigned int   WTC;
@@ -46,7 +46,7 @@ typedef struct {
        volatile unsigned char  SASR;
                 unsigned char  pad9;
        volatile unsigned char  SCMD;
-} a3000_scsiregs;
+};
 
 #define DAWR_A3000             (3)
 
index 11ae6be8aeaf81ee466609eff419961d82c76d19..23c76f41883cf46a00bfa5bd00b8b17795be620d 100644 (file)
 
 #include "53c700.h"
 
-MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / Kars de Jong <jongk@linux-m68k.org>");
-MODULE_DESCRIPTION("Amiga A4000T NCR53C710 driver");
-MODULE_LICENSE("GPL");
-
 
 static struct scsi_host_template a4000t_scsi_driver_template = {
        .name           = "A4000T builtin SCSI",
@@ -32,30 +28,35 @@ static struct scsi_host_template a4000t_scsi_driver_template = {
        .module         = THIS_MODULE,
 };
 
-static struct platform_device *a4000t_scsi_device;
 
-#define A4000T_SCSI_ADDR 0xdd0040
+#define A4000T_SCSI_OFFSET     0x40
 
-static int __devinit a4000t_probe(struct platform_device *dev)
+static int __init amiga_a4000t_scsi_probe(struct platform_device *pdev)
 {
-       struct Scsi_Host *host;
+       struct resource *res;
+       phys_addr_t scsi_addr;
        struct NCR_700_Host_Parameters *hostdata;
+       struct Scsi_Host *host;
 
-       if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI)))
-               goto out;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
 
-       if (!request_mem_region(A4000T_SCSI_ADDR, 0x1000,
+       if (!request_mem_region(res->start, resource_size(res),
                                "A4000T builtin SCSI"))
-               goto out;
+               return -EBUSY;
 
-       hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+       hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters),
+                          GFP_KERNEL);
        if (!hostdata) {
-               printk(KERN_ERR "a4000t-scsi: Failed to allocate host data\n");
+               dev_err(&pdev->dev, "Failed to allocate host data\n");
                goto out_release;
        }
 
+       scsi_addr = res->start + A4000T_SCSI_OFFSET;
+
        /* Fill in the required pieces of hostdata */
-       hostdata->base = (void __iomem *)ZTWO_VADDR(A4000T_SCSI_ADDR);
+       hostdata->base = (void __iomem *)ZTWO_VADDR(scsi_addr);
        hostdata->clock = 50;
        hostdata->chip710 = 1;
        hostdata->dmode_extra = DMODE_FC2;
@@ -63,26 +64,25 @@ static int __devinit a4000t_probe(struct platform_device *dev)
 
        /* and register the chip */
        host = NCR_700_detect(&a4000t_scsi_driver_template, hostdata,
-                             &dev->dev);
+                             &pdev->dev);
        if (!host) {
-               printk(KERN_ERR "a4000t-scsi: No host detected; "
-                               "board configuration problem?\n");
+               dev_err(&pdev->dev,
+                       "No host detected; board configuration problem?\n");
                goto out_free;
        }
 
        host->this_id = 7;
-       host->base = A4000T_SCSI_ADDR;
+       host->base = scsi_addr;
        host->irq = IRQ_AMIGA_PORTS;
 
        if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "a4000t-scsi",
                        host)) {
-               printk(KERN_ERR "a4000t-scsi: request_irq failed\n");
+               dev_err(&pdev->dev, "request_irq failed\n");
                goto out_put_host;
        }
 
-       platform_set_drvdata(dev, host);
+       platform_set_drvdata(pdev, host);
        scsi_scan_host(host);
-
        return 0;
 
  out_put_host:
@@ -90,58 +90,49 @@ static int __devinit a4000t_probe(struct platform_device *dev)
  out_free:
        kfree(hostdata);
  out_release:
-       release_mem_region(A4000T_SCSI_ADDR, 0x1000);
- out:
+       release_mem_region(res->start, resource_size(res));
        return -ENODEV;
 }
 
-static __devexit int a4000t_device_remove(struct platform_device *dev)
+static int __exit amiga_a4000t_scsi_remove(struct platform_device *pdev)
 {
-       struct Scsi_Host *host = platform_get_drvdata(dev);
+       struct Scsi_Host *host = platform_get_drvdata(pdev);
        struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        scsi_remove_host(host);
-
        NCR_700_release(host);
        kfree(hostdata);
        free_irq(host->irq, host);
-       release_mem_region(A4000T_SCSI_ADDR, 0x1000);
-
+       release_mem_region(res->start, resource_size(res));
        return 0;
 }
 
-static struct platform_driver a4000t_scsi_driver = {
-       .driver = {
-               .name           = "a4000t-scsi",
-               .owner          = THIS_MODULE,
+static struct platform_driver amiga_a4000t_scsi_driver = {
+       .remove = __exit_p(amiga_a4000t_scsi_remove),
+       .driver   = {
+               .name   = "amiga-a4000t-scsi",
+               .owner  = THIS_MODULE,
        },
-       .probe          = a4000t_probe,
-       .remove         = __devexit_p(a4000t_device_remove),
 };
 
-static int __init a4000t_scsi_init(void)
+static int __init amiga_a4000t_scsi_init(void)
 {
-       int err;
-
-       err = platform_driver_register(&a4000t_scsi_driver);
-       if (err)
-               return err;
-
-       a4000t_scsi_device = platform_device_register_simple("a4000t-scsi",
-                       -1, NULL, 0);
-       if (IS_ERR(a4000t_scsi_device)) {
-               platform_driver_unregister(&a4000t_scsi_driver);
-               return PTR_ERR(a4000t_scsi_device);
-       }
-
-       return err;
+       return platform_driver_probe(&amiga_a4000t_scsi_driver,
+                                    amiga_a4000t_scsi_probe);
 }
 
-static void __exit a4000t_scsi_exit(void)
+module_init(amiga_a4000t_scsi_init);
+
+static void __exit amiga_a4000t_scsi_exit(void)
 {
-       platform_device_unregister(a4000t_scsi_device);
-       platform_driver_unregister(&a4000t_scsi_driver);
+       platform_driver_unregister(&amiga_a4000t_scsi_driver);
 }
 
-module_init(a4000t_scsi_init);
-module_exit(a4000t_scsi_exit);
+module_exit(amiga_a4000t_scsi_exit);
+
+MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / "
+             "Kars de Jong <jongk@linux-m68k.org>");
+MODULE_DESCRIPTION("Amiga A4000T NCR53C710 driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:amiga-a4000t-scsi");
index 18b7102bb80e87bf7315a125400350ec5d3e1eef..2ce26eb7a1ec5c24062a2764181dfc3a8666c578 100644 (file)
@@ -1,36 +1,35 @@
 #include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/zorro.h>
 
-#include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
-#include <linux/zorro.h>
-#include <asm/irq.h>
-#include <linux/spinlock.h>
 
 #include "scsi.h"
-#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "gvp11.h"
 
-#include <linux/stat.h>
 
+#define CHECK_WD33C93
 
-#define DMA(ptr)       ((gvp11_scsiregs *)((ptr)->base))
+struct gvp11_hostdata {
+       struct WD33C93_hostdata wh;
+       struct gvp11_scsiregs *regs;
+};
 
-static irqreturn_t gvp11_intr(int irq, void *_instance)
+static irqreturn_t gvp11_intr(int irq, void *data)
 {
+       struct Scsi_Host *instance = data;
+       struct gvp11_hostdata *hdata = shost_priv(instance);
+       unsigned int status = hdata->regs->CNTR;
        unsigned long flags;
-       unsigned int status;
-       struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
 
-       status = DMA(instance)->CNTR;
        if (!(status & GVP11_DMAC_INT_PENDING))
                return IRQ_NONE;
 
@@ -50,64 +49,66 @@ void gvp11_setup(char *str, int *ints)
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
        struct Scsi_Host *instance = cmd->device->host;
-       struct WD33C93_hostdata *hdata = shost_priv(instance);
+       struct gvp11_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct gvp11_scsiregs *regs = hdata->regs;
        unsigned short cntr = GVP11_DMAC_INT_ENABLE;
        unsigned long addr = virt_to_bus(cmd->SCp.ptr);
        int bank_mask;
        static int scsi_alloc_out_of_range = 0;
 
        /* use bounce buffer if the physical address is bad */
-       if (addr & hdata->dma_xfer_mask) {
-               hdata->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
+       if (addr & wh->dma_xfer_mask) {
+               wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff;
 
                if (!scsi_alloc_out_of_range) {
-                       hdata->dma_bounce_buffer =
-                               kmalloc(hdata->dma_bounce_len, GFP_KERNEL);
-                       hdata->dma_buffer_pool = BUF_SCSI_ALLOCED;
+                       wh->dma_bounce_buffer =
+                               kmalloc(wh->dma_bounce_len, GFP_KERNEL);
+                       wh->dma_buffer_pool = BUF_SCSI_ALLOCED;
                }
 
                if (scsi_alloc_out_of_range ||
-                   !hdata->dma_bounce_buffer) {
-                       hdata->dma_bounce_buffer =
-                               amiga_chip_alloc(hdata->dma_bounce_len,
+                   !wh->dma_bounce_buffer) {
+                       wh->dma_bounce_buffer =
+                               amiga_chip_alloc(wh->dma_bounce_len,
                                                 "GVP II SCSI Bounce Buffer");
 
-                       if (!hdata->dma_bounce_buffer) {
-                               hdata->dma_bounce_len = 0;
+                       if (!wh->dma_bounce_buffer) {
+                               wh->dma_bounce_len = 0;
                                return 1;
                        }
 
-                       hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
+                       wh->dma_buffer_pool = BUF_CHIP_ALLOCED;
                }
 
                /* check if the address of the bounce buffer is OK */
-               addr = virt_to_bus(hdata->dma_bounce_buffer);
+               addr = virt_to_bus(wh->dma_bounce_buffer);
 
-               if (addr & hdata->dma_xfer_mask) {
+               if (addr & wh->dma_xfer_mask) {
                        /* fall back to Chip RAM if address out of range */
-                       if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED) {
-                               kfree(hdata->dma_bounce_buffer);
+                       if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED) {
+                               kfree(wh->dma_bounce_buffer);
                                scsi_alloc_out_of_range = 1;
                        } else {
-                               amiga_chip_free(hdata->dma_bounce_buffer);
+                               amiga_chip_free(wh->dma_bounce_buffer);
                        }
 
-                       hdata->dma_bounce_buffer =
-                               amiga_chip_alloc(hdata->dma_bounce_len,
+                       wh->dma_bounce_buffer =
+                               amiga_chip_alloc(wh->dma_bounce_len,
                                                 "GVP II SCSI Bounce Buffer");
 
-                       if (!hdata->dma_bounce_buffer) {
-                               hdata->dma_bounce_len = 0;
+                       if (!wh->dma_bounce_buffer) {
+                               wh->dma_bounce_len = 0;
                                return 1;
                        }
 
-                       addr = virt_to_bus(hdata->dma_bounce_buffer);
-                       hdata->dma_buffer_pool = BUF_CHIP_ALLOCED;
+                       addr = virt_to_bus(wh->dma_bounce_buffer);
+                       wh->dma_buffer_pool = BUF_CHIP_ALLOCED;
                }
 
                if (!dir_in) {
                        /* copy to bounce buffer for a write */
-                       memcpy(hdata->dma_bounce_buffer, cmd->SCp.ptr,
+                       memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr,
                               cmd->SCp.this_residual);
                }
        }
@@ -116,11 +117,11 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
        if (!dir_in)
                cntr |= GVP11_DMAC_DIR_WRITE;
 
-       hdata->dma_dir = dir_in;
-       DMA(cmd->device->host)->CNTR = cntr;
+       wh->dma_dir = dir_in;
+       regs->CNTR = cntr;
 
        /* setup DMA *physical* address */
-       DMA(cmd->device->host)->ACR = addr;
+       regs->ACR = addr;
 
        if (dir_in) {
                /* invalidate any cache */
@@ -130,12 +131,12 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
                cache_push(addr, cmd->SCp.this_residual);
        }
 
-       bank_mask = (~hdata->dma_xfer_mask >> 18) & 0x01c0;
+       bank_mask = (~wh->dma_xfer_mask >> 18) & 0x01c0;
        if (bank_mask)
-               DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
+               regs->BANK = bank_mask & (addr >> 18);
 
        /* start DMA */
-       DMA(cmd->device->host)->ST_DMA = 1;
+       regs->ST_DMA = 1;
 
        /* return success */
        return 0;
@@ -144,236 +145,53 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
                     int status)
 {
-       struct WD33C93_hostdata *hdata = shost_priv(instance);
+       struct gvp11_hostdata *hdata = shost_priv(instance);
+       struct WD33C93_hostdata *wh = &hdata->wh;
+       struct gvp11_scsiregs *regs = hdata->regs;
 
        /* stop DMA */
-       DMA(instance)->SP_DMA = 1;
+       regs->SP_DMA = 1;
        /* remove write bit from CONTROL bits */
-       DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
+       regs->CNTR = GVP11_DMAC_INT_ENABLE;
 
        /* copy from a bounce buffer, if necessary */
-       if (status && hdata->dma_bounce_buffer) {
-               if (hdata->dma_dir && SCpnt)
-                       memcpy(SCpnt->SCp.ptr, hdata->dma_bounce_buffer,
+       if (status && wh->dma_bounce_buffer) {
+               if (wh->dma_dir && SCpnt)
+                       memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer,
                               SCpnt->SCp.this_residual);
 
-               if (hdata->dma_buffer_pool == BUF_SCSI_ALLOCED)
-                       kfree(hdata->dma_bounce_buffer);
-               else
-                       amiga_chip_free(hdata->dma_bounce_buffer);
-
-               hdata->dma_bounce_buffer = NULL;
-               hdata->dma_bounce_len = 0;
-       }
-}
-
-#define CHECK_WD33C93
-
-int __init gvp11_detect(struct scsi_host_template *tpnt)
-{
-       static unsigned char called = 0;
-       struct Scsi_Host *instance;
-       unsigned long address;
-       unsigned int epc;
-       struct zorro_dev *z = NULL;
-       unsigned int default_dma_xfer_mask;
-       struct WD33C93_hostdata *hdata;
-       wd33c93_regs regs;
-       int num_gvp11 = 0;
-#ifdef CHECK_WD33C93
-       volatile unsigned char *sasr_3393, *scmd_3393;
-       unsigned char save_sasr;
-       unsigned char q, qq;
-#endif
-
-       if (!MACH_IS_AMIGA || called)
-               return 0;
-       called = 1;
-
-       tpnt->proc_name = "GVP11";
-       tpnt->proc_info = &wd33c93_proc_info;
-
-       while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
-               /*
-                * This should (hopefully) be the correct way to identify
-                * all the different GVP SCSI controllers (except for the
-                * SERIES I though).
-                */
-
-               if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI ||
-                   z->id == ZORRO_PROD_GVP_SERIES_II)
-                       default_dma_xfer_mask = ~0x00ffffff;
-               else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI ||
-                        z->id == ZORRO_PROD_GVP_A530_SCSI ||
-                        z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI)
-                       default_dma_xfer_mask = ~0x01ffffff;
-               else if (z->id == ZORRO_PROD_GVP_A1291 ||
-                        z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1)
-                       default_dma_xfer_mask = ~0x07ffffff;
+               if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED)
+                       kfree(wh->dma_bounce_buffer);
                else
-                       continue;
-
-               /*
-                * Rumors state that some GVP ram boards use the same product
-                * code as the SCSI controllers. Therefore if the board-size
-                * is not 64KB we asume it is a ram board and bail out.
-                */
-               if (z->resource.end - z->resource.start != 0xffff)
-                       continue;
+                       amiga_chip_free(wh->dma_bounce_buffer);
 
-               address = z->resource.start;
-               if (!request_mem_region(address, 256, "wd33c93"))
-                       continue;
-
-#ifdef CHECK_WD33C93
-
-               /*
-                * These darn GVP boards are a problem - it can be tough to tell
-                * whether or not they include a SCSI controller. This is the
-                * ultimate Yet-Another-GVP-Detection-Hack in that it actually
-                * probes for a WD33c93 chip: If we find one, it's extremely
-                * likely that this card supports SCSI, regardless of Product_
-                * Code, Board_Size, etc.
-                */
-
-               /* Get pointers to the presumed register locations and save contents */
-
-               sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR);
-               scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD);
-               save_sasr = *sasr_3393;
-
-               /* First test the AuxStatus Reg */
-
-               q = *sasr_3393; /* read it */
-               if (q & 0x08)   /* bit 3 should always be clear */
-                       goto release;
-               *sasr_3393 = WD_AUXILIARY_STATUS;       /* setup indirect address */
-               if (*sasr_3393 == WD_AUXILIARY_STATUS) {        /* shouldn't retain the write */
-                       *sasr_3393 = save_sasr; /* Oops - restore this byte */
-                       goto release;
-               }
-               if (*sasr_3393 != q) {  /* should still read the same */
-                       *sasr_3393 = save_sasr; /* Oops - restore this byte */
-                       goto release;
-               }
-               if (*scmd_3393 != q)    /* and so should the image at 0x1f */
-                       goto release;
-
-               /*
-                * Ok, we probably have a wd33c93, but let's check a few other places
-                * for good measure. Make sure that this works for both 'A and 'B
-                * chip versions.
-                */
-
-               *sasr_3393 = WD_SCSI_STATUS;
-               q = *scmd_3393;
-               *sasr_3393 = WD_SCSI_STATUS;
-               *scmd_3393 = ~q;
-               *sasr_3393 = WD_SCSI_STATUS;
-               qq = *scmd_3393;
-               *sasr_3393 = WD_SCSI_STATUS;
-               *scmd_3393 = q;
-               if (qq != q)    /* should be read only */
-                       goto release;
-               *sasr_3393 = 0x1e;      /* this register is unimplemented */
-               q = *scmd_3393;
-               *sasr_3393 = 0x1e;
-               *scmd_3393 = ~q;
-               *sasr_3393 = 0x1e;
-               qq = *scmd_3393;
-               *sasr_3393 = 0x1e;
-               *scmd_3393 = q;
-               if (qq != q || qq != 0xff)      /* should be read only, all 1's */
-                       goto release;
-               *sasr_3393 = WD_TIMEOUT_PERIOD;
-               q = *scmd_3393;
-               *sasr_3393 = WD_TIMEOUT_PERIOD;
-               *scmd_3393 = ~q;
-               *sasr_3393 = WD_TIMEOUT_PERIOD;
-               qq = *scmd_3393;
-               *sasr_3393 = WD_TIMEOUT_PERIOD;
-               *scmd_3393 = q;
-               if (qq != (~q & 0xff))  /* should be read/write */
-                       goto release;
-#endif
-
-               instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
-               if (instance == NULL)
-                       goto release;
-               instance->base = ZTWO_VADDR(address);
-               instance->irq = IRQ_AMIGA_PORTS;
-               instance->unique_id = z->slotaddr;
-
-               hdata = shost_priv(instance);
-               if (gvp11_xfer_mask)
-                       hdata->dma_xfer_mask = gvp11_xfer_mask;
-               else
-                       hdata->dma_xfer_mask = default_dma_xfer_mask;
-
-               DMA(instance)->secret2 = 1;
-               DMA(instance)->secret1 = 0;
-               DMA(instance)->secret3 = 15;
-               while (DMA(instance)->CNTR & GVP11_DMAC_BUSY)
-                       ;
-               DMA(instance)->CNTR = 0;
-
-               DMA(instance)->BANK = 0;
-
-               epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
-
-               /*
-                * Check for 14MHz SCSI clock
-                */
-               regs.SASR = &(DMA(instance)->SASR);
-               regs.SCMD = &(DMA(instance)->SCMD);
-               hdata->no_sync = 0xff;
-               hdata->fast = 0;
-               hdata->dma_mode = CTRL_DMA;
-               wd33c93_init(instance, regs, dma_setup, dma_stop,
-                            (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
-                                                    : WD33C93_FS_12_15);
-
-               if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED,
-                               "GVP11 SCSI", instance))
-                       goto unregister;
-               DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
-               num_gvp11++;
-               continue;
-
-unregister:
-               scsi_unregister(instance);
-release:
-               release_mem_region(address, 256);
+               wh->dma_bounce_buffer = NULL;
+               wh->dma_bounce_len = 0;
        }
-
-       return num_gvp11;
 }
 
 static int gvp11_bus_reset(struct scsi_cmnd *cmd)
 {
+       struct Scsi_Host *instance = cmd->device->host;
+
        /* FIXME perform bus-specific reset */
 
        /* FIXME 2: shouldn't we no-op this function (return
           FAILED), and fall back to host reset function,
           wd33c93_host_reset ? */
 
-       spin_lock_irq(cmd->device->host->host_lock);
+       spin_lock_irq(instance->host_lock);
        wd33c93_host_reset(cmd);
-       spin_unlock_irq(cmd->device->host->host_lock);
+       spin_unlock_irq(instance->host_lock);
 
        return SUCCESS;
 }
 
-
-#define HOSTS_C
-
-#include "gvp11.h"
-
-static struct scsi_host_template driver_template = {
-       .proc_name              = "GVP11",
+static struct scsi_host_template gvp11_scsi_template = {
+       .module                 = THIS_MODULE,
        .name                   = "GVP Series II SCSI",
-       .detect                 = gvp11_detect,
-       .release                = gvp11_release,
+       .proc_info              = wd33c93_proc_info,
+       .proc_name              = "GVP11",
        .queuecommand           = wd33c93_queuecommand,
        .eh_abort_handler       = wd33c93_abort,
        .eh_bus_reset_handler   = gvp11_bus_reset,
@@ -385,17 +203,230 @@ static struct scsi_host_template driver_template = {
        .use_clustering         = DISABLE_CLUSTERING
 };
 
+static int __devinit check_wd33c93(struct gvp11_scsiregs *regs)
+{
+#ifdef CHECK_WD33C93
+       volatile unsigned char *sasr_3393, *scmd_3393;
+       unsigned char save_sasr;
+       unsigned char q, qq;
 
-#include "scsi_module.c"
+       /*
+        * These darn GVP boards are a problem - it can be tough to tell
+        * whether or not they include a SCSI controller. This is the
+        * ultimate Yet-Another-GVP-Detection-Hack in that it actually
+        * probes for a WD33c93 chip: If we find one, it's extremely
+        * likely that this card supports SCSI, regardless of Product_
+        * Code, Board_Size, etc.
+        */
+
+       /* Get pointers to the presumed register locations and save contents */
+
+       sasr_3393 = &regs->SASR;
+       scmd_3393 = &regs->SCMD;
+       save_sasr = *sasr_3393;
+
+       /* First test the AuxStatus Reg */
+
+       q = *sasr_3393; /* read it */
+       if (q & 0x08)   /* bit 3 should always be clear */
+               return -ENODEV;
+       *sasr_3393 = WD_AUXILIARY_STATUS;       /* setup indirect address */
+       if (*sasr_3393 == WD_AUXILIARY_STATUS) {        /* shouldn't retain the write */
+               *sasr_3393 = save_sasr; /* Oops - restore this byte */
+               return -ENODEV;
+       }
+       if (*sasr_3393 != q) {  /* should still read the same */
+               *sasr_3393 = save_sasr; /* Oops - restore this byte */
+               return -ENODEV;
+       }
+       if (*scmd_3393 != q)    /* and so should the image at 0x1f */
+               return -ENODEV;
+
+       /*
+        * Ok, we probably have a wd33c93, but let's check a few other places
+        * for good measure. Make sure that this works for both 'A and 'B
+        * chip versions.
+        */
+
+       *sasr_3393 = WD_SCSI_STATUS;
+       q = *scmd_3393;
+       *sasr_3393 = WD_SCSI_STATUS;
+       *scmd_3393 = ~q;
+       *sasr_3393 = WD_SCSI_STATUS;
+       qq = *scmd_3393;
+       *sasr_3393 = WD_SCSI_STATUS;
+       *scmd_3393 = q;
+       if (qq != q)    /* should be read only */
+               return -ENODEV;
+       *sasr_3393 = 0x1e;      /* this register is unimplemented */
+       q = *scmd_3393;
+       *sasr_3393 = 0x1e;
+       *scmd_3393 = ~q;
+       *sasr_3393 = 0x1e;
+       qq = *scmd_3393;
+       *sasr_3393 = 0x1e;
+       *scmd_3393 = q;
+       if (qq != q || qq != 0xff)      /* should be read only, all 1's */
+               return -ENODEV;
+       *sasr_3393 = WD_TIMEOUT_PERIOD;
+       q = *scmd_3393;
+       *sasr_3393 = WD_TIMEOUT_PERIOD;
+       *scmd_3393 = ~q;
+       *sasr_3393 = WD_TIMEOUT_PERIOD;
+       qq = *scmd_3393;
+       *sasr_3393 = WD_TIMEOUT_PERIOD;
+       *scmd_3393 = q;
+       if (qq != (~q & 0xff))  /* should be read/write */
+               return -ENODEV;
+#endif /* CHECK_WD33C93 */
 
-int gvp11_release(struct Scsi_Host *instance)
+       return 0;
+}
+
+static int __devinit gvp11_probe(struct zorro_dev *z,
+                                const struct zorro_device_id *ent)
 {
-#ifdef MODULE
-       DMA(instance)->CNTR = 0;
-       release_mem_region(ZTWO_PADDR(instance->base), 256);
+       struct Scsi_Host *instance;
+       unsigned long address;
+       int error;
+       unsigned int epc;
+       unsigned int default_dma_xfer_mask;
+       struct gvp11_hostdata *hdata;
+       struct gvp11_scsiregs *regs;
+       wd33c93_regs wdregs;
+
+       default_dma_xfer_mask = ent->driver_data;
+
+       /*
+        * Rumors state that some GVP ram boards use the same product
+        * code as the SCSI controllers. Therefore if the board-size
+        * is not 64KB we asume it is a ram board and bail out.
+        */
+       if (zorro_resource_len(z) != 0x10000)
+               return -ENODEV;
+
+       address = z->resource.start;
+       if (!request_mem_region(address, 256, "wd33c93"))
+               return -EBUSY;
+
+       regs = (struct gvp11_scsiregs *)(ZTWO_VADDR(address));
+
+       error = check_wd33c93(regs);
+       if (error)
+               goto fail_check_or_alloc;
+
+       instance = scsi_host_alloc(&gvp11_scsi_template,
+                                  sizeof(struct gvp11_hostdata));
+       if (!instance) {
+               error = -ENOMEM;
+               goto fail_check_or_alloc;
+       }
+
+       instance->irq = IRQ_AMIGA_PORTS;
+       instance->unique_id = z->slotaddr;
+
+       regs->secret2 = 1;
+       regs->secret1 = 0;
+       regs->secret3 = 15;
+       while (regs->CNTR & GVP11_DMAC_BUSY)
+               ;
+       regs->CNTR = 0;
+       regs->BANK = 0;
+
+       wdregs.SASR = &regs->SASR;
+       wdregs.SCMD = &regs->SCMD;
+
+       hdata = shost_priv(instance);
+       if (gvp11_xfer_mask)
+               hdata->wh.dma_xfer_mask = gvp11_xfer_mask;
+       else
+               hdata->wh.dma_xfer_mask = default_dma_xfer_mask;
+
+       hdata->wh.no_sync = 0xff;
+       hdata->wh.fast = 0;
+       hdata->wh.dma_mode = CTRL_DMA;
+       hdata->regs = regs;
+
+       /*
+        * Check for 14MHz SCSI clock
+        */
+       epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
+       wd33c93_init(instance, wdregs, dma_setup, dma_stop,
+                    (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
+                                            : WD33C93_FS_12_15);
+
+       error = request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED,
+                           "GVP11 SCSI", instance);
+       if (error)
+               goto fail_irq;
+
+       regs->CNTR = GVP11_DMAC_INT_ENABLE;
+
+       error = scsi_add_host(instance, NULL);
+       if (error)
+               goto fail_host;
+
+       zorro_set_drvdata(z, instance);
+       scsi_scan_host(instance);
+       return 0;
+
+fail_host:
        free_irq(IRQ_AMIGA_PORTS, instance);
-#endif
-       return 1;
+fail_irq:
+       scsi_host_put(instance);
+fail_check_or_alloc:
+       release_mem_region(address, 256);
+       return error;
+}
+
+static void __devexit gvp11_remove(struct zorro_dev *z)
+{
+       struct Scsi_Host *instance = zorro_get_drvdata(z);
+       struct gvp11_hostdata *hdata = shost_priv(instance);
+
+       hdata->regs->CNTR = 0;
+       scsi_remove_host(instance);
+       free_irq(IRQ_AMIGA_PORTS, instance);
+       scsi_host_put(instance);
+       release_mem_region(z->resource.start, 256);
+}
+
+       /*
+        * This should (hopefully) be the correct way to identify
+        * all the different GVP SCSI controllers (except for the
+        * SERIES I though).
+        */
+
+static struct zorro_device_id gvp11_zorro_tbl[] __devinitdata = {
+       { ZORRO_PROD_GVP_COMBO_030_R3_SCSI,     ~0x00ffffff },
+       { ZORRO_PROD_GVP_SERIES_II,             ~0x00ffffff },
+       { ZORRO_PROD_GVP_GFORCE_030_SCSI,       ~0x01ffffff },
+       { ZORRO_PROD_GVP_A530_SCSI,             ~0x01ffffff },
+       { ZORRO_PROD_GVP_COMBO_030_R4_SCSI,     ~0x01ffffff },
+       { ZORRO_PROD_GVP_A1291,                 ~0x07ffffff },
+       { ZORRO_PROD_GVP_GFORCE_040_SCSI_1,     ~0x07ffffff },
+       { 0 }
+};
+MODULE_DEVICE_TABLE(zorro, gvp11_zorro_tbl);
+
+static struct zorro_driver gvp11_driver = {
+       .name           = "gvp11",
+       .id_table       = gvp11_zorro_tbl,
+       .probe          = gvp11_probe,
+       .remove         = __devexit_p(gvp11_remove),
+};
+
+static int __init gvp11_init(void)
+{
+       return zorro_register_driver(&gvp11_driver);
+}
+module_init(gvp11_init);
+
+static void __exit gvp11_exit(void)
+{
+       zorro_unregister_driver(&gvp11_driver);
 }
+module_exit(gvp11_exit);
 
+MODULE_DESCRIPTION("GVP Series II SCSI");
 MODULE_LICENSE("GPL");
index e2efdf9601ef98fb0b5490bb7378bab2b6906d2f..852913cde5dd9a5b5bdf43722d76613ef68c12d2 100644 (file)
@@ -11,9 +11,6 @@
 
 #include <linux/types.h>
 
-int gvp11_detect(struct scsi_host_template *);
-int gvp11_release(struct Scsi_Host *);
-
 #ifndef CMD_PER_LUN
 #define CMD_PER_LUN            2
 #endif
@@ -22,15 +19,13 @@ int gvp11_release(struct Scsi_Host *);
 #define CAN_QUEUE              16
 #endif
 
-#ifndef HOSTS_C
-
 /*
  * if the transfer address ANDed with this results in a non-zero
  * result, then we can't use DMA.
  */
 #define GVP11_XFER_MASK                (0xff000001)
 
-typedef struct {
+struct gvp11_scsiregs {
                 unsigned char  pad1[64];
        volatile unsigned short CNTR;
                 unsigned char  pad2[31];
@@ -46,7 +41,7 @@ typedef struct {
        volatile unsigned short SP_DMA;
        volatile unsigned short secret2; /* store 1 here */
        volatile unsigned short secret3; /* store 15 here */
-} gvp11_scsiregs;
+};
 
 /* bits in CNTR */
 #define GVP11_DMAC_BUSY                (1<<0)
@@ -54,6 +49,4 @@ typedef struct {
 #define GVP11_DMAC_INT_ENABLE  (1<<3)
 #define GVP11_DMAC_DIR_WRITE   (1<<4)
 
-#endif /* else def HOSTS_C */
-
 #endif /* GVP11_H */
index 716d1785cda726fc3180cd854e0c4aebeb2879ab..c29d0dbb9660b97e34515317927208a475215f95 100644 (file)
 #include <linux/stat.h>
 
 
-static struct Scsi_Host *mvme147_host = NULL;
-
-static irqreturn_t mvme147_intr(int irq, void *dummy)
+static irqreturn_t mvme147_intr(int irq, void *data)
 {
+       struct Scsi_Host *instance = data;
+
        if (irq == MVME147_IRQ_SCSI_PORT)
-               wd33c93_intr(mvme147_host);
+               wd33c93_intr(instance);
        else
                m147_pcc->dma_intr = 0x89;      /* Ack and enable ints */
        return IRQ_HANDLED;
@@ -29,7 +29,8 @@ static irqreturn_t mvme147_intr(int irq, void *dummy)
 
 static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
 {
-       struct WD33C93_hostdata *hdata = shost_priv(mvme147_host);
+       struct Scsi_Host *instance = cmd->device->host;
+       struct WD33C93_hostdata *hdata = shost_priv(instance);
        unsigned char flags = 0x01;
        unsigned long addr = virt_to_bus(cmd->SCp.ptr);
 
@@ -66,6 +67,7 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
 int mvme147_detect(struct scsi_host_template *tpnt)
 {
        static unsigned char called = 0;
+       struct Scsi_Host *instance;
        wd33c93_regs regs;
        struct WD33C93_hostdata *hdata;
 
@@ -76,25 +78,25 @@ int mvme147_detect(struct scsi_host_template *tpnt)
        tpnt->proc_name = "MVME147";
        tpnt->proc_info = &wd33c93_proc_info;
 
-       mvme147_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
-       if (!mvme147_host)
+       instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata));
+       if (!instance)
                goto err_out;
 
-       mvme147_host->base = 0xfffe4000;
-       mvme147_host->irq = MVME147_IRQ_SCSI_PORT;
+       instance->base = 0xfffe4000;
+       instance->irq = MVME147_IRQ_SCSI_PORT;
        regs.SASR = (volatile unsigned char *)0xfffe4000;
        regs.SCMD = (volatile unsigned char *)0xfffe4001;
-       hdata = shost_priv(mvme147_host);
+       hdata = shost_priv(instance);
        hdata->no_sync = 0xff;
        hdata->fast = 0;
        hdata->dma_mode = CTRL_DMA;
-       wd33c93_init(mvme147_host, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
+       wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
 
        if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0,
-                       "MVME147 SCSI PORT", mvme147_intr))
+                       "MVME147 SCSI PORT", instance))
                goto err_unregister;
        if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0,
-                       "MVME147 SCSI DMA", mvme147_intr))
+                       "MVME147 SCSI DMA", instance))
                goto err_free_irq;
 #if 0  /* Disabled; causes problems booting */
        m147_pcc->scsi_interrupt = 0x10;        /* Assert SCSI bus reset */
@@ -113,7 +115,7 @@ int mvme147_detect(struct scsi_host_template *tpnt)
 err_free_irq:
        free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
 err_unregister:
-       scsi_unregister(mvme147_host);
+       scsi_unregister(instance);
 err_out:
        return 0;
 }
@@ -132,9 +134,6 @@ static int mvme147_bus_reset(struct scsi_cmnd *cmd)
        return SUCCESS;
 }
 
-#define HOSTS_C
-
-#include "mvme147.h"
 
 static struct scsi_host_template driver_template = {
        .proc_name              = "MVME147",
index 8dbf1c3afb7b7537239c4aedd4882670f34e0969..d64b7178fa088a3eb24453affaa6e5782037d195 100644 (file)
@@ -3587,7 +3587,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name
                if (i == (-ENOSPC)) {
                        transfer = STp->buffer->writing;        /* FIXME -- check this logic */
                        if (transfer <= do_count) {
-                               filp->f_pos += do_count - transfer;
+                               *ppos += do_count - transfer;
                                count -= do_count - transfer;
                                if (STps->drv_block >= 0) {
                                        STps->drv_block += (do_count - transfer) / STp->block_size;
@@ -3625,7 +3625,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name
                        goto out;
                }
 
-               filp->f_pos += do_count;
+               *ppos += do_count;
                b_point += do_count;
                count -= do_count;
                if (STps->drv_block >= 0) {
@@ -3647,7 +3647,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name
                if (STps->drv_block >= 0) {
                        STps->drv_block += blks;
                }
-               filp->f_pos += count;
+               *ppos += count;
                count = 0;
        }
 
@@ -3823,7 +3823,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo
                        }
                        STp->logical_blk_num += transfer / STp->block_size;
                        STps->drv_block      += transfer / STp->block_size;
-                       filp->f_pos          += transfer;
+                       *ppos          += transfer;
                        buf                  += transfer;
                        total                += transfer;
                }
@@ -5626,6 +5626,7 @@ static const struct file_operations osst_fops = {
        .open =         os_scsi_tape_open,
        .flush =        os_scsi_tape_flush,
        .release =      os_scsi_tape_close,
+       .llseek =       noop_llseek,
 };
 
 static int osst_supports(struct scsi_device * SDp)
index 3ea1a713ef250fcc35a64b10c71a65ac73ea6e42..24211d0efa6d5d82557dac4e6047c3b9efc25c3f 100644 (file)
@@ -3962,6 +3962,7 @@ static const struct file_operations st_fops =
        .open =         st_open,
        .flush =        st_flush,
        .release =      st_release,
+       .llseek =       noop_llseek,
 };
 
 static int st_probe(struct device *dev)
index 49f0d31c118a4103e8b56ff3c1d5d8f74a1e9a21..cf7c34a994590ef4d004ed5f3c79b28a8e383068 100644 (file)
@@ -242,13 +242,13 @@ static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev,
                printk(KERN_DEBUG "saa7134-go7007: irq: lost %ld\n",
                                (status >> 16) & 0x0f);
        if (status & 0x100000) {
-               dma_sync_single(&dev->pci->dev,
-                               saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+               dma_sync_single_for_cpu(&dev->pci->dev,
+                                       saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
                go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE);
                saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma));
        } else {
-               dma_sync_single(&dev->pci->dev,
-                               saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+               dma_sync_single_for_cpu(&dev->pci->dev,
+                                       saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
                go7007_parse_video_stream(go, saa->top, PAGE_SIZE);
                saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma));
        }
index e89304c725686896b78164543016f8189992295b..b53deee25d74d525faa4692e3539af0cd3ceb369 100644 (file)
@@ -5879,20 +5879,13 @@ out:
 static int ixj_build_filter_cadence(IXJ *j, IXJ_FILTER_CADENCE __user * cp)
 {
        IXJ_FILTER_CADENCE *lcp;
-       lcp = kmalloc(sizeof(IXJ_FILTER_CADENCE), GFP_KERNEL);
-       if (lcp == NULL) {
+       lcp = memdup_user(cp, sizeof(IXJ_FILTER_CADENCE));
+       if (IS_ERR(lcp)) {
                if(ixjdebug & 0x0001) {
-                       printk(KERN_INFO "Could not allocate memory for cadence\n");
+                       printk(KERN_INFO "Could not allocate memory for cadence or could not copy cadence to kernel\n");
                }
-               return -ENOMEM;
+               return PTR_ERR(lcp);
         }
-       if (copy_from_user(lcp, cp, sizeof(IXJ_FILTER_CADENCE))) {
-               if(ixjdebug & 0x0001) {
-                       printk(KERN_INFO "Could not copy cadence to kernel\n");
-               }
-               kfree(lcp);
-               return -EFAULT;
-       }
        if (lcp->filter > 5) {
                if(ixjdebug & 0x0001) {
                        printk(KERN_INFO "Cadence out of range\n");
index 23b2a8c0dbfcbdee211e253a5df9fd7b19aad80a..b020ba7f1cf22f6fabad4dfc0d682243402ba245 100644 (file)
@@ -501,7 +501,9 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
 
 static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
 {
+#ifndef NO_BL_SUPPORT
        struct backlight_properties props;
+#endif
        struct bfin_bf54xfb_info *info;
        struct fb_info *fbinfo;
        int ret;
@@ -654,7 +656,8 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
                printk(KERN_ERR DRIVER_NAME
                        ": unable to register backlight.\n");
                ret = -EINVAL;
-               goto out9;
+               unregister_framebuffer(fbinfo);
+               goto out8;
        }
 
        lcd_dev = lcd_device_register(DRIVER_NAME, &pdev->dev, NULL, &bfin_lcd_ops);
@@ -663,8 +666,6 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
 
        return 0;
 
-out9:
-       unregister_framebuffer(fbinfo);
 out8:
        free_irq(info->irq, info);
 out7:
index c2ec3dcd4e918023886376b3103b21928c8b1e27..7a50272eaab94972e459efd8776785c789e4b478 100644 (file)
@@ -420,7 +420,9 @@ static irqreturn_t bfin_t350mcqb_irq_error(int irq, void *dev_id)
 
 static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
 {
+#ifndef NO_BL_SUPPORT
        struct backlight_properties props;
+#endif
        struct bfin_t350mcqbfb_info *info;
        struct fb_info *fbinfo;
        int ret;
@@ -550,7 +552,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
                printk(KERN_ERR DRIVER_NAME
                        ": unable to register backlight.\n");
                ret = -EINVAL;
-               goto out9;
+               unregister_framebuffer(fbinfo);
+               goto out8;
        }
 
        lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops);
@@ -559,8 +562,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
 
        return 0;
 
-out9:
-       unregister_framebuffer(fbinfo);
 out8:
        free_irq(info->irq, info);
 out7:
index d4471b4c037476e82a8ade24acac32164fc6727e..dce8c97b4333b4871f356b6d5cac1c17f351a600 100644 (file)
@@ -71,7 +71,8 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
                        "S3 Trio64UV+", "S3 Trio64V2/DX", "S3 Trio64V2/GX",
                        "S3 Plato/PX", "S3 Aurora64VP", "S3 Virge",
                        "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX",
-                       "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P"};
+                       "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P",
+                       "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X"};
 
 #define CHIP_UNKNOWN           0x00
 #define CHIP_732_TRIO32                0x01
@@ -89,10 +90,14 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
 #define CHIP_356_VIRGE_GX2     0x0D
 #define CHIP_357_VIRGE_GX2P    0x0E
 #define CHIP_359_VIRGE_GX2P    0x0F
+#define CHIP_360_TRIO3D_1X     0x10
+#define CHIP_362_TRIO3D_2X     0x11
+#define CHIP_368_TRIO3D_2X     0x12
 
 #define CHIP_XXX_TRIO          0x80
 #define CHIP_XXX_TRIO64V2_DXGX 0x81
 #define CHIP_XXX_VIRGE_DXGX    0x82
+#define CHIP_36X_TRIO3D_1X_2X  0x83
 
 #define CHIP_UNDECIDED_FLAG    0x80
 #define CHIP_MASK              0xFF
@@ -324,6 +329,7 @@ static void s3fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 
 static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
 {
+       struct s3fb_info *par = info->par;
        u16 m, n, r;
        u8 regval;
        int rv;
@@ -339,7 +345,13 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
        vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
 
        /* Set S3 clock registers */
-       vga_wseq(NULL, 0x12, ((n - 2) | (r << 5)));
+       if (par->chip == CHIP_360_TRIO3D_1X ||
+           par->chip == CHIP_362_TRIO3D_2X ||
+           par->chip == CHIP_368_TRIO3D_2X) {
+               vga_wseq(NULL, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */
+               vga_wseq(NULL, 0x29, r >> 2); /* remaining highest bit of r */
+       } else
+               vga_wseq(NULL, 0x12, (n - 2) | (r << 5));
        vga_wseq(NULL, 0x13, m - 2);
 
        udelay(1000);
@@ -456,7 +468,7 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 static int s3fb_set_par(struct fb_info *info)
 {
        struct s3fb_info *par = info->par;
-       u32 value, mode, hmul, offset_value, screen_size, multiplex;
+       u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes;
        u32 bpp = info->var.bits_per_pixel;
 
        if (bpp != 0) {
@@ -518,7 +530,7 @@ static int s3fb_set_par(struct fb_info *info)
        svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ?   */
        svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ?   */
 
-       svga_wcrt_mask(0x5D, 0x00, 0x28); // Clear strange HSlen bits
+       svga_wcrt_mask(0x5D, 0x00, 0x28); /* Clear strange HSlen bits */
 
 /*     svga_wcrt_mask(0x58, 0x03, 0x03); */
 
@@ -530,10 +542,14 @@ static int s3fb_set_par(struct fb_info *info)
        pr_debug("fb%d: offset register       : %d\n", info->node, offset_value);
        svga_wcrt_multi(s3_offset_regs, offset_value);
 
-       vga_wcrt(NULL, 0x54, 0x18); /* M parameter */
-       vga_wcrt(NULL, 0x60, 0xff); /* N parameter */
-       vga_wcrt(NULL, 0x61, 0xff); /* L parameter */
-       vga_wcrt(NULL, 0x62, 0xff); /* L parameter */
+       if (par->chip != CHIP_360_TRIO3D_1X &&
+           par->chip != CHIP_362_TRIO3D_2X &&
+           par->chip != CHIP_368_TRIO3D_2X) {
+               vga_wcrt(NULL, 0x54, 0x18); /* M parameter */
+               vga_wcrt(NULL, 0x60, 0xff); /* N parameter */
+               vga_wcrt(NULL, 0x61, 0xff); /* L parameter */
+               vga_wcrt(NULL, 0x62, 0xff); /* L parameter */
+       }
 
        vga_wcrt(NULL, 0x3A, 0x35);
        svga_wattr(0x33, 0x00);
@@ -570,6 +586,16 @@ static int s3fb_set_par(struct fb_info *info)
                vga_wcrt(NULL, 0x66, 0x90);
        }
 
+       if (par->chip == CHIP_360_TRIO3D_1X ||
+           par->chip == CHIP_362_TRIO3D_2X ||
+           par->chip == CHIP_368_TRIO3D_2X) {
+               dbytes = info->var.xres * ((bpp+7)/8);
+               vga_wcrt(NULL, 0x91, (dbytes + 7) / 8);
+               vga_wcrt(NULL, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80);
+
+               vga_wcrt(NULL, 0x66, 0x81);
+       }
+
        svga_wcrt_mask(0x31, 0x00, 0x40);
        multiplex = 0;
        hmul = 1;
@@ -615,11 +641,13 @@ static int s3fb_set_par(struct fb_info *info)
                break;
        case 3:
                pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
-               if (info->var.pixclock > 20000) {
-                       svga_wcrt_mask(0x50, 0x00, 0x30);
+               svga_wcrt_mask(0x50, 0x00, 0x30);
+               if (info->var.pixclock > 20000 ||
+                   par->chip == CHIP_360_TRIO3D_1X ||
+                   par->chip == CHIP_362_TRIO3D_2X ||
+                   par->chip == CHIP_368_TRIO3D_2X)
                        svga_wcrt_mask(0x67, 0x00, 0xF0);
-               } else {
-                       svga_wcrt_mask(0x50, 0x00, 0x30);
+               else {
                        svga_wcrt_mask(0x67, 0x10, 0xF0);
                        multiplex = 1;
                }
@@ -634,7 +662,10 @@ static int s3fb_set_par(struct fb_info *info)
                } else {
                        svga_wcrt_mask(0x50, 0x10, 0x30);
                        svga_wcrt_mask(0x67, 0x30, 0xF0);
-                       hmul = 2;
+                       if (par->chip != CHIP_360_TRIO3D_1X &&
+                           par->chip != CHIP_362_TRIO3D_2X &&
+                           par->chip != CHIP_368_TRIO3D_2X)
+                               hmul = 2;
                }
                break;
        case 5:
@@ -647,7 +678,10 @@ static int s3fb_set_par(struct fb_info *info)
                } else {
                        svga_wcrt_mask(0x50, 0x10, 0x30);
                        svga_wcrt_mask(0x67, 0x50, 0xF0);
-                       hmul = 2;
+                       if (par->chip != CHIP_360_TRIO3D_1X &&
+                           par->chip != CHIP_362_TRIO3D_2X &&
+                           par->chip != CHIP_368_TRIO3D_2X)
+                               hmul = 2;
                }
                break;
        case 6:
@@ -866,6 +900,17 @@ static int __devinit s3_identification(int chip)
                        return CHIP_385_VIRGE_GX;
        }
 
+       if (chip == CHIP_36X_TRIO3D_1X_2X) {
+               switch (vga_rcrt(NULL, 0x2f)) {
+               case 0x00:
+                       return CHIP_360_TRIO3D_1X;
+               case 0x01:
+                       return CHIP_362_TRIO3D_2X;
+               case 0x02:
+                       return CHIP_368_TRIO3D_2X;
+               }
+       }
+
        return CHIP_UNKNOWN;
 }
 
@@ -930,17 +975,32 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
        vga_wcrt(NULL, 0x38, 0x48);
        vga_wcrt(NULL, 0x39, 0xA5);
 
-       /* Find how many physical memory there is on card */
-       /* 0x36 register is accessible even if other registers are locked */
-       regval = vga_rcrt(NULL, 0x36);
-       info->screen_size = s3_memsizes[regval >> 5] << 10;
-       info->fix.smem_len = info->screen_size;
-
+       /* Identify chip type */
        par->chip = id->driver_data & CHIP_MASK;
        par->rev = vga_rcrt(NULL, 0x2f);
        if (par->chip & CHIP_UNDECIDED_FLAG)
                par->chip = s3_identification(par->chip);
 
+       /* Find how many physical memory there is on card */
+       /* 0x36 register is accessible even if other registers are locked */
+       regval = vga_rcrt(NULL, 0x36);
+       if (par->chip == CHIP_360_TRIO3D_1X ||
+           par->chip == CHIP_362_TRIO3D_2X ||
+           par->chip == CHIP_368_TRIO3D_2X) {
+               switch ((regval & 0xE0) >> 5) {
+               case 0: /* 8MB -- only 4MB usable for display */
+               case 1: /* 4MB with 32-bit bus */
+               case 2: /* 4MB */
+                       info->screen_size = 4 << 20;
+                       break;
+               case 6: /* 2MB */
+                       info->screen_size = 2 << 20;
+                       break;
+               }
+       } else
+               info->screen_size = s3_memsizes[regval >> 5] << 10;
+       info->fix.smem_len = info->screen_size;
+
        /* Find MCLK frequency */
        regval = vga_rseq(NULL, 0x10);
        par->mclk_freq = ((vga_rseq(NULL, 0x11) + 2) * 14318) / ((regval & 0x1F)  + 2);
@@ -1131,6 +1191,7 @@ static struct pci_device_id s3_devices[] __devinitdata = {
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_356_VIRGE_GX2},
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P},
        {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P},
+       {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X},
 
        {0, 0, 0, 0, 0, 0, 0}
 };
index 2bc40e682f9509acd5ede1696058aebbdcfeea92..1082541358f01aaa4799f4c287b700c7cd8eafee 100644 (file)
@@ -578,14 +578,9 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
                break;
 
        case VIAFB_SET_GAMMA_LUT:
-               viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL);
-               if (!viafb_gamma_table)
-                       return -ENOMEM;
-               if (copy_from_user(viafb_gamma_table, argp,
-                               256 * sizeof(u32))) {
-                       kfree(viafb_gamma_table);
-                       return -EFAULT;
-               }
+               viafb_gamma_table = memdup_user(argp, 256 * sizeof(u32));
+               if (IS_ERR(viafb_gamma_table))
+                       return PTR_ERR(viafb_gamma_table);
                viafb_set_gamma_table(viafb_bpp, viafb_gamma_table);
                kfree(viafb_gamma_table);
                break;
index d70bbbac6b7be31709f407f081672d0d6893fda5..914d1c0bc07a0e3928cb71a0d65bff35d96e0310 100644 (file)
@@ -224,7 +224,7 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
                affs_brelse(bh);
                inode = affs_iget(sb, ino);
                if (IS_ERR(inode))
-                       return ERR_PTR(PTR_ERR(inode));
+                       return ERR_CAST(inode);
        }
        dentry->d_op = AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations;
        d_add(dentry, inode);
index 1cf12b3dd83a0654d7c0629786d8ab7fd4388a23..48fdeebdb544df9e008affb6814789035d4e94ce 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -36,6 +36,7 @@
 #include <linux/blkdev.h>
 #include <linux/mempool.h>
 #include <linux/hash.h>
+#include <linux/compat.h>
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
@@ -1384,13 +1385,22 @@ static ssize_t aio_fsync(struct kiocb *iocb)
        return ret;
 }
 
-static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb)
+static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb, bool compat)
 {
        ssize_t ret;
 
-       ret = rw_copy_check_uvector(type, (struct iovec __user *)kiocb->ki_buf,
-                                   kiocb->ki_nbytes, 1,
-                                   &kiocb->ki_inline_vec, &kiocb->ki_iovec);
+#ifdef CONFIG_COMPAT
+       if (compat)
+               ret = compat_rw_copy_check_uvector(type,
+                               (struct compat_iovec __user *)kiocb->ki_buf,
+                               kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec,
+                               &kiocb->ki_iovec);
+       else
+#endif
+               ret = rw_copy_check_uvector(type,
+                               (struct iovec __user *)kiocb->ki_buf,
+                               kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec,
+                               &kiocb->ki_iovec);
        if (ret < 0)
                goto out;
 
@@ -1420,7 +1430,7 @@ static ssize_t aio_setup_single_vector(struct kiocb *kiocb)
  *     Performs the initial checks and aio retry method
  *     setup for the kiocb at the time of io submission.
  */
-static ssize_t aio_setup_iocb(struct kiocb *kiocb)
+static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
 {
        struct file *file = kiocb->ki_filp;
        ssize_t ret = 0;
@@ -1469,7 +1479,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb)
                ret = security_file_permission(file, MAY_READ);
                if (unlikely(ret))
                        break;
-               ret = aio_setup_vectored_rw(READ, kiocb);
+               ret = aio_setup_vectored_rw(READ, kiocb, compat);
                if (ret)
                        break;
                ret = -EINVAL;
@@ -1483,7 +1493,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb)
                ret = security_file_permission(file, MAY_WRITE);
                if (unlikely(ret))
                        break;
-               ret = aio_setup_vectored_rw(WRITE, kiocb);
+               ret = aio_setup_vectored_rw(WRITE, kiocb, compat);
                if (ret)
                        break;
                ret = -EINVAL;
@@ -1548,7 +1558,8 @@ static void aio_batch_free(struct hlist_head *batch_hash)
 }
 
 static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
-                        struct iocb *iocb, struct hlist_head *batch_hash)
+                        struct iocb *iocb, struct hlist_head *batch_hash,
+                        bool compat)
 {
        struct kiocb *req;
        struct file *file;
@@ -1609,7 +1620,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
        req->ki_left = req->ki_nbytes = iocb->aio_nbytes;
        req->ki_opcode = iocb->aio_lio_opcode;
 
-       ret = aio_setup_iocb(req);
+       ret = aio_setup_iocb(req, compat);
 
        if (ret)
                goto out_put_req;
@@ -1637,20 +1648,8 @@ out_put_req:
        return ret;
 }
 
-/* sys_io_submit:
- *     Queue the nr iocbs pointed to by iocbpp for processing.  Returns
- *     the number of iocbs queued.  May return -EINVAL if the aio_context
- *     specified by ctx_id is invalid, if nr is < 0, if the iocb at
- *     *iocbpp[0] is not properly initialized, if the operation specified
- *     is invalid for the file descriptor in the iocb.  May fail with
- *     -EFAULT if any of the data structures point to invalid data.  May
- *     fail with -EBADF if the file descriptor specified in the first
- *     iocb is invalid.  May fail with -EAGAIN if insufficient resources
- *     are available to queue any iocbs.  Will return 0 if nr is 0.  Will
- *     fail with -ENOSYS if not implemented.
- */
-SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
-               struct iocb __user * __user *, iocbpp)
+long do_io_submit(aio_context_t ctx_id, long nr,
+                 struct iocb __user *__user *iocbpp, bool compat)
 {
        struct kioctx *ctx;
        long ret = 0;
@@ -1687,7 +1686,7 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
                        break;
                }
 
-               ret = io_submit_one(ctx, user_iocb, &tmp, batch_hash);
+               ret = io_submit_one(ctx, user_iocb, &tmp, batch_hash, compat);
                if (ret)
                        break;
        }
@@ -1697,6 +1696,24 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
        return i ? i : ret;
 }
 
+/* sys_io_submit:
+ *     Queue the nr iocbs pointed to by iocbpp for processing.  Returns
+ *     the number of iocbs queued.  May return -EINVAL if the aio_context
+ *     specified by ctx_id is invalid, if nr is < 0, if the iocb at
+ *     *iocbpp[0] is not properly initialized, if the operation specified
+ *     is invalid for the file descriptor in the iocb.  May fail with
+ *     -EFAULT if any of the data structures point to invalid data.  May
+ *     fail with -EBADF if the file descriptor specified in the first
+ *     iocb is invalid.  May fail with -EAGAIN if insufficient resources
+ *     are available to queue any iocbs.  Will return 0 if nr is 0.  Will
+ *     fail with -ENOSYS if not implemented.
+ */
+SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,
+               struct iocb __user * __user *, iocbpp)
+{
+       return do_io_submit(ctx_id, nr, iocbpp, 0);
+}
+
 /* lookup_kiocb
  *     Finds a given iocb for cancellation.
  */
index 8713c7cfbc799efe1fa604df04dcbebe3966f225..9a0520b50663b52f9508eb962bd3fbd92f55baa4 100644 (file)
@@ -28,6 +28,7 @@ static int autofs_root_mkdir(struct inode *,struct dentry *,int);
 static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
 
 const struct file_operations autofs_root_operations = {
+       .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = autofs_root_readdir,
        .ioctl          = autofs_root_ioctl,
index d832062869f6727846f4b28c46998cb36698e6d5..ba4a38b9c22ff63d9897ad59c30c1479a0c54fed 100644 (file)
@@ -95,7 +95,7 @@ static int check_dev_ioctl_version(int cmd, struct autofs_dev_ioctl *param)
  */
 static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *in)
 {
-       struct autofs_dev_ioctl tmp, *ads;
+       struct autofs_dev_ioctl tmp;
 
        if (copy_from_user(&tmp, in, sizeof(tmp)))
                return ERR_PTR(-EFAULT);
@@ -103,16 +103,7 @@ static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *i
        if (tmp.size < sizeof(tmp))
                return ERR_PTR(-EINVAL);
 
-       ads = kmalloc(tmp.size, GFP_KERNEL);
-       if (!ads)
-               return ERR_PTR(-ENOMEM);
-
-       if (copy_from_user(ads, in, tmp.size)) {
-               kfree(ads);
-               return ERR_PTR(-EFAULT);
-       }
-
-       return ads;
+       return memdup_user(in, tmp.size);
 }
 
 static inline void free_dev_ioctl(struct autofs_dev_ioctl *param)
index 05448730f840be408e6bd7079df8c8ef26b03fd9..f0b391c50552dc986f93afe1e4c56ce3b777a600 100644 (file)
@@ -568,6 +568,79 @@ out:
        return ret;
 }
 
+/* A write operation does a read from user space and vice versa */
+#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
+
+ssize_t compat_rw_copy_check_uvector(int type,
+               const struct compat_iovec __user *uvector, unsigned long nr_segs,
+               unsigned long fast_segs, struct iovec *fast_pointer,
+               struct iovec **ret_pointer)
+{
+       compat_ssize_t tot_len;
+       struct iovec *iov = *ret_pointer = fast_pointer;
+       ssize_t ret = 0;
+       int seg;
+
+       /*
+        * SuS says "The readv() function *may* fail if the iovcnt argument
+        * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
+        * traditionally returned zero for zero segments, so...
+        */
+       if (nr_segs == 0)
+               goto out;
+
+       ret = -EINVAL;
+       if (nr_segs > UIO_MAXIOV || nr_segs < 0)
+               goto out;
+       if (nr_segs > fast_segs) {
+               ret = -ENOMEM;
+               iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
+               if (iov == NULL) {
+                       *ret_pointer = fast_pointer;
+                       goto out;
+               }
+       }
+       *ret_pointer = iov;
+
+       /*
+        * Single unix specification:
+        * We should -EINVAL if an element length is not >= 0 and fitting an
+        * ssize_t.  The total length is fitting an ssize_t
+        *
+        * Be careful here because iov_len is a size_t not an ssize_t
+        */
+       tot_len = 0;
+       ret = -EINVAL;
+       for (seg = 0; seg < nr_segs; seg++) {
+               compat_ssize_t tmp = tot_len;
+               compat_uptr_t buf;
+               compat_ssize_t len;
+
+               if (__get_user(len, &uvector->iov_len) ||
+                  __get_user(buf, &uvector->iov_base)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               if (len < 0)    /* size_t not fitting in compat_ssize_t .. */
+                       goto out;
+               tot_len += len;
+               if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
+                       goto out;
+               if (!access_ok(vrfy_dir(type), buf, len)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               iov->iov_base = compat_ptr(buf);
+               iov->iov_len = (compat_size_t) len;
+               uvector++;
+               iov++;
+       }
+       ret = tot_len;
+
+out:
+       return ret;
+}
+
 static inline long
 copy_iocb(long nr, u32 __user *ptr32, struct iocb __user * __user *ptr64)
 {
@@ -600,7 +673,7 @@ compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb)
        iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64));
        ret = copy_iocb(nr, iocb, iocb64);
        if (!ret)
-               ret = sys_io_submit(ctx_id, nr, iocb64);
+               ret = do_io_submit(ctx_id, nr, iocb64, 1);
        return ret;
 }
 
@@ -1077,70 +1150,21 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
 {
        compat_ssize_t tot_len;
        struct iovec iovstack[UIO_FASTIOV];
-       struct iovec *iov=iovstack, *vector;
+       struct iovec *iov;
        ssize_t ret;
-       int seg;
        io_fn_t fn;
        iov_fn_t fnv;
 
-       /*
-        * SuS says "The readv() function *may* fail if the iovcnt argument
-        * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
-        * traditionally returned zero for zero segments, so...
-        */
-       ret = 0;
-       if (nr_segs == 0)
-               goto out;
-
-       /*
-        * First get the "struct iovec" from user memory and
-        * verify all the pointers
-        */
        ret = -EINVAL;
-       if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
-               goto out;
        if (!file->f_op)
                goto out;
-       if (nr_segs > UIO_FASTIOV) {
-               ret = -ENOMEM;
-               iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
-               if (!iov)
-                       goto out;
-       }
+
        ret = -EFAULT;
        if (!access_ok(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
                goto out;
 
-       /*
-        * Single unix specification:
-        * We should -EINVAL if an element length is not >= 0 and fitting an
-        * ssize_t.  The total length is fitting an ssize_t
-        *
-        * Be careful here because iov_len is a size_t not an ssize_t
-        */
-       tot_len = 0;
-       vector = iov;
-       ret = -EINVAL;
-       for (seg = 0 ; seg < nr_segs; seg++) {
-               compat_ssize_t tmp = tot_len;
-               compat_ssize_t len;
-               compat_uptr_t buf;
-
-               if (__get_user(len, &uvector->iov_len) ||
-                   __get_user(buf, &uvector->iov_base)) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (len < 0)    /* size_t not fitting an compat_ssize_t .. */
-                       goto out;
-               tot_len += len;
-               if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
-                       goto out;
-               vector->iov_base = compat_ptr(buf);
-               vector->iov_len = (compat_size_t) len;
-               uvector++;
-               vector++;
-       }
+       tot_len = compat_rw_copy_check_uvector(type, uvector, nr_segs,
+                                              UIO_FASTIOV, iovstack, &iov);
        if (tot_len == 0) {
                ret = 0;
                goto out;
index 9badbc0bfb1d23afd6cf64ace5ad1f1ae757d294..e19de6a80339b3ceeae267283962f271ac6c5e55 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -768,7 +768,6 @@ static int de_thread(struct task_struct *tsk)
        struct signal_struct *sig = tsk->signal;
        struct sighand_struct *oldsighand = tsk->sighand;
        spinlock_t *lock = &oldsighand->siglock;
-       int count;
 
        if (thread_group_empty(tsk))
                goto no_thread_group;
@@ -785,13 +784,13 @@ static int de_thread(struct task_struct *tsk)
                spin_unlock_irq(lock);
                return -EAGAIN;
        }
+
        sig->group_exit_task = tsk;
-       zap_other_threads(tsk);
+       sig->notify_count = zap_other_threads(tsk);
+       if (!thread_group_leader(tsk))
+               sig->notify_count--;
 
-       /* Account for the thread group leader hanging around: */
-       count = thread_group_leader(tsk) ? 1 : 2;
-       sig->notify_count = count;
-       while (atomic_read(&sig->count) > count) {
+       while (sig->notify_count) {
                __set_current_state(TASK_UNINTERRUPTIBLE);
                spin_unlock_irq(lock);
                schedule();
@@ -1662,12 +1661,15 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
        struct completion *vfork_done;
-       int core_waiters;
+       int core_waiters = -EBUSY;
 
        init_completion(&core_state->startup);
        core_state->dumper.task = tsk;
        core_state->dumper.next = NULL;
-       core_waiters = zap_threads(tsk, mm, core_state, exit_code);
+
+       down_write(&mm->mmap_sem);
+       if (!mm->core_state)
+               core_waiters = zap_threads(tsk, mm, core_state, exit_code);
        up_write(&mm->mmap_sem);
 
        if (unlikely(core_waiters < 0))
@@ -1787,21 +1789,61 @@ static void wait_for_dump_helpers(struct file *file)
 }
 
 
+/*
+ * uhm_pipe_setup
+ * helper function to customize the process used
+ * to collect the core in userspace.  Specifically
+ * it sets up a pipe and installs it as fd 0 (stdin)
+ * for the process.  Returns 0 on success, or
+ * PTR_ERR on failure.
+ * Note that it also sets the core limit to 1.  This
+ * is a special value that we use to trap recursive
+ * core dumps
+ */
+static int umh_pipe_setup(struct subprocess_info *info)
+{
+       struct file *rp, *wp;
+       struct fdtable *fdt;
+       struct coredump_params *cp = (struct coredump_params *)info->data;
+       struct files_struct *cf = current->files;
+
+       wp = create_write_pipe(0);
+       if (IS_ERR(wp))
+               return PTR_ERR(wp);
+
+       rp = create_read_pipe(wp, 0);
+       if (IS_ERR(rp)) {
+               free_write_pipe(wp);
+               return PTR_ERR(rp);
+       }
+
+       cp->file = wp;
+
+       sys_close(0);
+       fd_install(0, rp);
+       spin_lock(&cf->file_lock);
+       fdt = files_fdtable(cf);
+       FD_SET(0, fdt->open_fds);
+       FD_CLR(0, fdt->close_on_exec);
+       spin_unlock(&cf->file_lock);
+
+       /* and disallow core files too */
+       current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1};
+
+       return 0;
+}
+
 void do_coredump(long signr, int exit_code, struct pt_regs *regs)
 {
        struct core_state core_state;
        char corename[CORENAME_MAX_SIZE + 1];
        struct mm_struct *mm = current->mm;
        struct linux_binfmt * binfmt;
-       struct inode * inode;
        const struct cred *old_cred;
        struct cred *cred;
        int retval = 0;
        int flag = 0;
-       int ispipe = 0;
-       char **helper_argv = NULL;
-       int helper_argc = 0;
-       int dump_count = 0;
+       int ispipe;
        static atomic_t core_dump_count = ATOMIC_INIT(0);
        struct coredump_params cprm = {
                .signr = signr,
@@ -1820,23 +1862,12 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        binfmt = mm->binfmt;
        if (!binfmt || !binfmt->core_dump)
                goto fail;
-
-       cred = prepare_creds();
-       if (!cred) {
-               retval = -ENOMEM;
+       if (!__get_dumpable(cprm.mm_flags))
                goto fail;
-       }
 
-       down_write(&mm->mmap_sem);
-       /*
-        * If another thread got here first, or we are not dumpable, bail out.
-        */
-       if (mm->core_state || !__get_dumpable(cprm.mm_flags)) {
-               up_write(&mm->mmap_sem);
-               put_cred(cred);
+       cred = prepare_creds();
+       if (!cred)
                goto fail;
-       }
-
        /*
         *      We cannot trust fsuid as being the "true" uid of the
         *      process nor do we know its entire history. We only know it
@@ -1849,10 +1880,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        }
 
        retval = coredump_wait(exit_code, &core_state);
-       if (retval < 0) {
-               put_cred(cred);
-               goto fail;
-       }
+       if (retval < 0)
+               goto fail_creds;
 
        old_cred = override_creds(cred);
 
@@ -1870,19 +1899,19 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        ispipe = format_corename(corename, signr);
        unlock_kernel();
 
-       if ((!ispipe) && (cprm.limit < binfmt->min_coredump))
-               goto fail_unlock;
-
        if (ispipe) {
-               if (cprm.limit == 0) {
+               int dump_count;
+               char **helper_argv;
+
+               if (cprm.limit == 1) {
                        /*
                         * Normally core limits are irrelevant to pipes, since
                         * we're not writing to the file system, but we use
-                        * cprm.limit of 0 here as a speacial value. Any
-                        * non-zero limit gets set to RLIM_INFINITY below, but
+                        * cprm.limit of 1 here as a speacial value. Any
+                        * non-1 limit gets set to RLIM_INFINITY below, but
                         * a limit of 0 skips the dump.  This is a consistent
                         * way to catch recursive crashes.  We can still crash
-                        * if the core_pattern binary sets RLIM_CORE =  !0
+                        * if the core_pattern binary sets RLIM_CORE =  !1
                         * but it runs as root, and can do lots of stupid things
                         * Note that we use task_tgid_vnr here to grab the pid
                         * of the process group leader.  That way we get the
@@ -1890,11 +1919,12 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                         * core_pattern process dies.
                         */
                        printk(KERN_WARNING
-                               "Process %d(%s) has RLIMIT_CORE set to 0\n",
+                               "Process %d(%s) has RLIMIT_CORE set to 1\n",
                                task_tgid_vnr(current), current->comm);
                        printk(KERN_WARNING "Aborting core\n");
                        goto fail_unlock;
                }
+               cprm.limit = RLIM_INFINITY;
 
                dump_count = atomic_inc_return(&core_dump_count);
                if (core_pipe_limit && (core_pipe_limit < dump_count)) {
@@ -1904,71 +1934,74 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                        goto fail_dropcount;
                }
 
-               helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc);
+               helper_argv = argv_split(GFP_KERNEL, corename+1, NULL);
                if (!helper_argv) {
                        printk(KERN_WARNING "%s failed to allocate memory\n",
                               __func__);
                        goto fail_dropcount;
                }
 
-               cprm.limit = RLIM_INFINITY;
-
-               /* SIGPIPE can happen, but it's just never processed */
-               if (call_usermodehelper_pipe(helper_argv[0], helper_argv, NULL,
-                               &cprm.file)) {
+               retval = call_usermodehelper_fns(helper_argv[0], helper_argv,
+                                       NULL, UMH_WAIT_EXEC, umh_pipe_setup,
+                                       NULL, &cprm);
+               argv_free(helper_argv);
+               if (retval) {
                        printk(KERN_INFO "Core dump to %s pipe failed\n",
                               corename);
-                       goto fail_dropcount;
+                       goto close_fail;
                }
-       } else
+       } else {
+               struct inode *inode;
+
+               if (cprm.limit < binfmt->min_coredump)
+                       goto fail_unlock;
+
                cprm.file = filp_open(corename,
                                 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
                                 0600);
-       if (IS_ERR(cprm.file))
-               goto fail_dropcount;
-       inode = cprm.file->f_path.dentry->d_inode;
-       if (inode->i_nlink > 1)
-               goto close_fail;        /* multiple links - don't dump */
-       if (!ispipe && d_unhashed(cprm.file->f_path.dentry))
-               goto close_fail;
-
-       /* AK: actually i see no reason to not allow this for named pipes etc.,
-          but keep the previous behaviour for now. */
-       if (!ispipe && !S_ISREG(inode->i_mode))
-               goto close_fail;
-       /*
-        * Dont allow local users get cute and trick others to coredump
-        * into their pre-created files:
-        * Note, this is not relevant for pipes
-        */
-       if (!ispipe && (inode->i_uid != current_fsuid()))
-               goto close_fail;
-       if (!cprm.file->f_op)
-               goto close_fail;
-       if (!cprm.file->f_op->write)
-               goto close_fail;
-       if (!ispipe &&
-           do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file) != 0)
-               goto close_fail;
+               if (IS_ERR(cprm.file))
+                       goto fail_unlock;
 
-       retval = binfmt->core_dump(&cprm);
+               inode = cprm.file->f_path.dentry->d_inode;
+               if (inode->i_nlink > 1)
+                       goto close_fail;
+               if (d_unhashed(cprm.file->f_path.dentry))
+                       goto close_fail;
+               /*
+                * AK: actually i see no reason to not allow this for named
+                * pipes etc, but keep the previous behaviour for now.
+                */
+               if (!S_ISREG(inode->i_mode))
+                       goto close_fail;
+               /*
+                * Dont allow local users get cute and trick others to coredump
+                * into their pre-created files.
+                */
+               if (inode->i_uid != current_fsuid())
+                       goto close_fail;
+               if (!cprm.file->f_op || !cprm.file->f_op->write)
+                       goto close_fail;
+               if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file))
+                       goto close_fail;
+       }
 
+       retval = binfmt->core_dump(&cprm);
        if (retval)
                current->signal->group_exit_code |= 0x80;
-close_fail:
+
        if (ispipe && core_pipe_limit)
                wait_for_dump_helpers(cprm.file);
-       filp_close(cprm.file, NULL);
+close_fail:
+       if (cprm.file)
+               filp_close(cprm.file, NULL);
 fail_dropcount:
-       if (dump_count)
+       if (ispipe)
                atomic_dec(&core_dump_count);
 fail_unlock:
-       if (helper_argv)
-               argv_free(helper_argv);
-
+       coredump_finish(mm);
        revert_creds(old_cred);
+fail_creds:
        put_cred(cred);
-       coredump_finish(mm);
 fail:
        return;
 }
index aee049cb9f84782640d365a90156f423d2a37b46..0ec7bb2c95c6afd035a9484b0a39347f9f8f61c1 100644 (file)
@@ -57,6 +57,8 @@ const struct inode_operations vxfs_dir_inode_ops = {
 };
 
 const struct file_operations vxfs_dir_operations = {
+       .llseek =               generic_file_llseek,
+       .read =                 generic_read_dir,
        .readdir =              vxfs_readdir,
 };
 
index 1e1f286dd70eeb0ea7e98b46012e378280e0cf58..4a8eb31c53381f74fca4a1dfad3ed0f19ef4ed3b 100644 (file)
@@ -103,7 +103,7 @@ static struct fscache_object *fscache_objlist_lookup(loff_t *_pos)
        /* banners (can't represent line 0 by pos 0 as that would involve
         * returning a NULL pointer) */
        if (pos == 0)
-               return (struct fscache_object *) ++(*_pos);
+               return (struct fscache_object *)(long)++(*_pos);
        if (pos < 3)
                return (struct fscache_object *)pos;
 
index b9ab69b3a482ce86bcbefd9f7703d0079f516bce..e0aca9a0ac68b9f5a75764a570df2c3d0bd81a72 100644 (file)
@@ -272,6 +272,7 @@ static int isofs_readdir(struct file *filp,
 
 const struct file_operations isofs_dir_operations =
 {
+       .llseek = generic_file_llseek,
        .read = generic_read_dir,
        .readdir = isofs_readdir,
 };
index 92dde6f8d893b51a254e258dfd8942039a95ada6..9578cbe0cd589ad00ce590d60172c2433d16688e 100644 (file)
@@ -49,6 +49,7 @@ extern int ncp_symlink(struct inode *, struct dentry *, const char *);
                      
 const struct file_operations ncp_dir_operations =
 {
+       .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = ncp_readdir,
        .unlocked_ioctl = ncp_ioctl,
index ee9a179ebdf3a83ae93dfc3c4ff40820aeafa6be..db64854b7b098972aaa4b71ccc25fd544b2dc900 100644 (file)
@@ -1741,6 +1741,7 @@ remove_lru_entry:
                        clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags);
                        smp_mb__after_clear_bit();
                }
+               spin_unlock(&inode->i_lock);
        }
        spin_unlock(&nfs_access_lru_lock);
        nfs_access_free_list(&head);
index 3aea3ca98ab788c5dae67c0769ff723eb9b94217..91679e2631ee0ebaff79cd96fd6e3019ca5a49d8 100644 (file)
@@ -1386,7 +1386,7 @@ static int nfs_commit_inode(struct inode *inode, int how)
        int res = 0;
 
        if (!nfs_commit_set_lock(NFS_I(inode), may_wait))
-               goto out;
+               goto out_mark_dirty;
        spin_lock(&inode->i_lock);
        res = nfs_scan_commit(inode, &head, 0, 0);
        spin_unlock(&inode->i_lock);
@@ -1398,9 +1398,18 @@ static int nfs_commit_inode(struct inode *inode, int how)
                        wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT,
                                        nfs_wait_bit_killable,
                                        TASK_KILLABLE);
+               else
+                       goto out_mark_dirty;
        } else
                nfs_commit_clear_lock(NFS_I(inode));
-out:
+       return res;
+       /* Note: If we exit without ensuring that the commit is complete,
+        * we must mark the inode as dirty. Otherwise, future calls to
+        * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure
+        * that the data is on the disk.
+        */
+out_mark_dirty:
+       __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
        return res;
 }
 
@@ -1509,14 +1518,17 @@ int nfs_wb_page(struct inode *inode, struct page *page)
        };
        int ret;
 
-       while(PagePrivate(page)) {
+       for (;;) {
                wait_on_page_writeback(page);
                if (clear_page_dirty_for_io(page)) {
                        ret = nfs_writepage_locked(page, &wbc);
                        if (ret < 0)
                                goto out_error;
+                       continue;
                }
-               ret = sync_inode(inode, &wbc);
+               if (!PagePrivate(page))
+                       break;
+               ret = nfs_commit_inode(inode, FLUSH_SYNC);
                if (ret < 0)
                        goto out_error;
        }
index 885ab5513ac5cfe10e18c4fba149ddf478252f40..9b58d38bc911e27faccc7ed9ffb2c53f0885df4a 100644 (file)
@@ -267,7 +267,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
                shpending = p->signal->shared_pending.signal;
                blocked = p->blocked;
                collect_sigign_sigcatch(p, &ignored, &caught);
-               num_threads = atomic_read(&p->signal->count);
+               num_threads = get_nr_threads(p);
                rcu_read_lock();  /* FIXME: is this correct? */
                qsize = atomic_read(&__task_cred(p)->user->sigpending);
                rcu_read_unlock();
@@ -410,7 +410,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
                        tty_nr = new_encode_dev(tty_devnum(sig->tty));
                }
 
-               num_threads = atomic_read(&sig->count);
+               num_threads = get_nr_threads(task);
                collect_sigign_sigcatch(task, &sigign, &sigcatch);
 
                cmin_flt = sig->cmin_flt;
index c7f9f23449dc402a16ff1b36eb817fe63f02a779..acb7ef80ea4fcc4987b0b2159f70d599f659c31e 100644 (file)
@@ -166,18 +166,6 @@ static int get_fs_path(struct task_struct *task, struct path *path, bool root)
        return result;
 }
 
-static int get_nr_threads(struct task_struct *tsk)
-{
-       unsigned long flags;
-       int count = 0;
-
-       if (lock_task_sighand(tsk, &flags)) {
-               count = atomic_read(&tsk->signal->count);
-               unlock_task_sighand(tsk, &flags);
-       }
-       return count;
-}
-
 static int proc_cwd_link(struct inode *inode, struct path *path)
 {
        struct task_struct *task = get_proc_task(inode);
@@ -2444,7 +2432,7 @@ static struct dentry *proc_base_instantiate(struct inode *dir,
        const struct pid_entry *p = ptr;
        struct inode *inode;
        struct proc_inode *ei;
-       struct dentry *error = ERR_PTR(-EINVAL);
+       struct dentry *error;
 
        /* Allocate the inode */
        error = ERR_PTR(-ENOMEM);
@@ -2794,7 +2782,7 @@ out:
 
 struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
-       struct dentry *result = ERR_PTR(-ENOENT);
+       struct dentry *result;
        struct task_struct *task;
        unsigned tgid;
        struct pid_namespace *ns;
index 43c127490606d1a3ab3c47bee8309b92176d5f3c..2791907744edffdc25719cebe93f15b0d0e23242 100644 (file)
@@ -343,21 +343,6 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */
 /*
  * Return an inode number between PROC_DYNAMIC_FIRST and
  * 0xffffffff, or zero on failure.
- *
- * Current inode allocations in the proc-fs (hex-numbers):
- *
- * 00000000            reserved
- * 00000001-00000fff   static entries  (goners)
- *      001            root-ino
- *
- * 00001000-00001fff   unused
- * 0001xxxx-7fffxxxx   pid-dir entries for pid 1-7fff
- * 80000000-efffffff   unused
- * f0000000-ffffffff   dynamic entries
- *
- * Goal:
- *     Once we split the thing into several virtual filesystems,
- *     we will get rid of magical ranges (and this comment, BTW).
  */
 static unsigned int get_inode_number(void)
 {
index c837a77351beb933e8c8f4d2a7e356fcfb48b823..6f37c391468d168ebcc5d1f366e244163f504f88 100644 (file)
@@ -588,7 +588,7 @@ static struct kcore_list kcore_text;
  */
 static void __init proc_kcore_text_init(void)
 {
-       kclist_add(&kcore_text, _stext, _end - _stext, KCORE_TEXT);
+       kclist_add(&kcore_text, _text, _end - _text, KCORE_TEXT);
 }
 #else
 static void __init proc_kcore_text_init(void)
index 757c069f2a65132584272d3fc1ccd22ea012d737..4258384ed22d9afa22fe579dd7c4242039e8ab8e 100644 (file)
@@ -110,7 +110,6 @@ void __init proc_root_init(void)
        if (err)
                return;
        proc_mnt = kern_mount_data(&proc_fs_type, &init_pid_ns);
-       err = PTR_ERR(proc_mnt);
        if (IS_ERR(proc_mnt)) {
                unregister_filesystem(&proc_fs_type);
                return;
index 6f30c3d5bcbfbfe5923f3cccc3223c9c4d3bba68..3d3fd46921336e7f6b2c73ffc93b64480d24167f 100644 (file)
@@ -77,6 +77,7 @@ out:
 
 const struct file_operations qnx4_dir_operations =
 {
+       .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = qnx4_readdir,
        .fsync          = simple_fsync,
index 113386d6fd2de0bdd12721e65b85a0fcbe8ab7b1..9c0485236e68d4abd02951d99aec5eb4a2905720 100644 (file)
@@ -97,6 +97,23 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
 }
 EXPORT_SYMBOL(generic_file_llseek);
 
+/**
+ * noop_llseek - No Operation Performed llseek implementation
+ * @file:      file structure to seek on
+ * @offset:    file offset to seek to
+ * @origin:    type of seek
+ *
+ * This is an implementation of ->llseek useable for the rare special case when
+ * userspace expects the seek to succeed but the (device) file is actually not
+ * able to perform the seek. In this case you use noop_llseek() instead of
+ * falling back to the default implementation of ->llseek.
+ */
+loff_t noop_llseek(struct file *file, loff_t offset, int origin)
+{
+       return file->f_pos;
+}
+EXPORT_SYMBOL(noop_llseek);
+
 loff_t no_llseek(struct file *file, loff_t offset, int origin)
 {
        return -ESPIPE;
index 07930449a9583ebee29e5781c3e4dbf9f609aa6f..4455fbe269a31ae341d395b187b3ae5e1f462d10 100644 (file)
@@ -18,6 +18,7 @@ static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
                              int datasync);
 
 const struct file_operations reiserfs_dir_operations = {
+       .llseek = generic_file_llseek,
        .read = generic_read_dir,
        .readdir = reiserfs_readdir,
        .fsync = reiserfs_dir_fsync,
index 6c978428892d4de01c406a8abf3d7cc914fe8f5e..00a70cab1f36ea7fc7bd96317d4bccdd8486a736 100644 (file)
@@ -37,6 +37,7 @@ static int smb_link(struct dentry *, struct inode *, struct dentry *);
 
 const struct file_operations smb_dir_operations =
 {
+       .llseek         = generic_file_llseek,
        .read           = generic_read_dir,
        .readdir        = smb_readdir,
        .unlocked_ioctl = smb_ioctl,
index 25a00d19d68681687d0f9990a661ab8a7321fb75..cc6ce8a84c217d50fb82aef341d26fd56da6e991 100644 (file)
@@ -26,6 +26,17 @@ config SQUASHFS
 
          If unsure, say N.
 
+config SQUASHFS_XATTRS
+       bool "Squashfs XATTR support"
+       depends on SQUASHFS
+       default n
+       help
+         Saying Y here includes support for extended attributes (xattrs).
+         Xattrs are name:value pairs associated with inodes by
+         the kernel or by users (see the attr(5) manual page).
+
+         If unsure, say N.
+
 config SQUASHFS_EMBEDDED
 
        bool "Additional option for memory-constrained systems" 
index df8a19ef870d6db72cca324e4ef4667931b8dbd7..2cee3e9fa452b81219a04145f77c1ba827723a6e 100644 (file)
@@ -5,3 +5,5 @@
 obj-$(CONFIG_SQUASHFS) += squashfs.o
 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
 squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
+squashfs-$(CONFIG_SQUASHFS_XATTRS) += xattr.o xattr_id.o
+
index 49daaf669e41809d33b377c40c2f39e0f2e462c7..62e63ad250755ed6d51fd56aa75f2c91f82e74e7 100644 (file)
 
 #include <linux/fs.h>
 #include <linux/vfs.h>
+#include <linux/xattr.h>
 
 #include "squashfs_fs.h"
 #include "squashfs_fs_sb.h"
 #include "squashfs_fs_i.h"
 #include "squashfs.h"
+#include "xattr.h"
 
 /*
  * Initialise VFS inode with the base inode information common to all
@@ -111,6 +113,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
        int err, type, offset = SQUASHFS_INODE_OFFSET(ino);
        union squashfs_inode squashfs_ino;
        struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base;
+       int xattr_id = SQUASHFS_INVALID_XATTR;
 
        TRACE("Entered squashfs_read_inode\n");
 
@@ -199,8 +202,10 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                        frag_offset = 0;
                }
 
+               xattr_id = le32_to_cpu(sqsh_ino->xattr);
                inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
                inode->i_size = le64_to_cpu(sqsh_ino->file_size);
+               inode->i_op = &squashfs_inode_ops;
                inode->i_fop = &generic_ro_fops;
                inode->i_mode |= S_IFREG;
                inode->i_blocks = ((inode->i_size -
@@ -251,6 +256,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                if (err < 0)
                        goto failed_read;
 
+               xattr_id = le32_to_cpu(sqsh_ino->xattr);
                inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
                inode->i_size = le32_to_cpu(sqsh_ino->file_size);
                inode->i_op = &squashfs_dir_inode_ops;
@@ -280,21 +286,33 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 
                inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
                inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
-               inode->i_op = &page_symlink_inode_operations;
+               inode->i_op = &squashfs_symlink_inode_ops;
                inode->i_data.a_ops = &squashfs_symlink_aops;
                inode->i_mode |= S_IFLNK;
                squashfs_i(inode)->start = block;
                squashfs_i(inode)->offset = offset;
 
+               if (type == SQUASHFS_LSYMLINK_TYPE) {
+                       __le32 xattr;
+
+                       err = squashfs_read_metadata(sb, NULL, &block,
+                                               &offset, inode->i_size);
+                       if (err < 0)
+                               goto failed_read;
+                       err = squashfs_read_metadata(sb, &xattr, &block,
+                                               &offset, sizeof(xattr));
+                       if (err < 0)
+                               goto failed_read;
+                       xattr_id = le32_to_cpu(xattr);
+               }
+
                TRACE("Symbolic link inode %x:%x, start_block %llx, offset "
                                "%x\n", SQUASHFS_INODE_BLK(ino), offset,
                                block, offset);
                break;
        }
        case SQUASHFS_BLKDEV_TYPE:
-       case SQUASHFS_CHRDEV_TYPE:
-       case SQUASHFS_LBLKDEV_TYPE:
-       case SQUASHFS_LCHRDEV_TYPE: {
+       case SQUASHFS_CHRDEV_TYPE: {
                struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev;
                unsigned int rdev;
 
@@ -315,10 +333,32 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                                SQUASHFS_INODE_BLK(ino), offset, rdev);
                break;
        }
+       case SQUASHFS_LBLKDEV_TYPE:
+       case SQUASHFS_LCHRDEV_TYPE: {
+               struct squashfs_ldev_inode *sqsh_ino = &squashfs_ino.ldev;
+               unsigned int rdev;
+
+               err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
+                               sizeof(*sqsh_ino));
+               if (err < 0)
+                       goto failed_read;
+
+               if (type == SQUASHFS_LCHRDEV_TYPE)
+                       inode->i_mode |= S_IFCHR;
+               else
+                       inode->i_mode |= S_IFBLK;
+               xattr_id = le32_to_cpu(sqsh_ino->xattr);
+               inode->i_op = &squashfs_inode_ops;
+               inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+               rdev = le32_to_cpu(sqsh_ino->rdev);
+               init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
+
+               TRACE("Device inode %x:%x, rdev %x\n",
+                               SQUASHFS_INODE_BLK(ino), offset, rdev);
+               break;
+       }
        case SQUASHFS_FIFO_TYPE:
-       case SQUASHFS_SOCKET_TYPE:
-       case SQUASHFS_LFIFO_TYPE:
-       case SQUASHFS_LSOCKET_TYPE: {
+       case SQUASHFS_SOCKET_TYPE: {
                struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc;
 
                err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
@@ -334,14 +374,52 @@ int squashfs_read_inode(struct inode *inode, long long ino)
                init_special_inode(inode, inode->i_mode, 0);
                break;
        }
+       case SQUASHFS_LFIFO_TYPE:
+       case SQUASHFS_LSOCKET_TYPE: {
+               struct squashfs_lipc_inode *sqsh_ino = &squashfs_ino.lipc;
+
+               err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
+                               sizeof(*sqsh_ino));
+               if (err < 0)
+                       goto failed_read;
+
+               if (type == SQUASHFS_LFIFO_TYPE)
+                       inode->i_mode |= S_IFIFO;
+               else
+                       inode->i_mode |= S_IFSOCK;
+               xattr_id = le32_to_cpu(sqsh_ino->xattr);
+               inode->i_op = &squashfs_inode_ops;
+               inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
+               init_special_inode(inode, inode->i_mode, 0);
+               break;
+       }
        default:
                ERROR("Unknown inode type %d in squashfs_iget!\n", type);
                return -EINVAL;
        }
 
+       if (xattr_id != SQUASHFS_INVALID_XATTR && msblk->xattr_id_table) {
+               err = squashfs_xattr_lookup(sb, xattr_id,
+                                       &squashfs_i(inode)->xattr_count,
+                                       &squashfs_i(inode)->xattr_size,
+                                       &squashfs_i(inode)->xattr);
+               if (err < 0)
+                       goto failed_read;
+               inode->i_blocks += ((squashfs_i(inode)->xattr_size - 1) >> 9)
+                               + 1;
+       } else
+               squashfs_i(inode)->xattr_count = 0;
+
        return 0;
 
 failed_read:
        ERROR("Unable to read inode 0x%llx\n", ino);
        return err;
 }
+
+
+const struct inode_operations squashfs_inode_ops = {
+       .getxattr = generic_getxattr,
+       .listxattr = squashfs_listxattr
+};
+
index 5266bd8ad932edb3a288217d8992693d649b7112..7a9464d08cf632bef2395baea734c9eae9d8d6a7 100644 (file)
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/dcache.h>
+#include <linux/xattr.h>
 
 #include "squashfs_fs.h"
 #include "squashfs_fs_sb.h"
 #include "squashfs_fs_i.h"
 #include "squashfs.h"
+#include "xattr.h"
 
 /*
  * Lookup name in the directory index, returning the location of the metadata
@@ -237,5 +239,7 @@ failed:
 
 
 const struct inode_operations squashfs_dir_inode_ops = {
-       .lookup = squashfs_lookup
+       .lookup = squashfs_lookup,
+       .getxattr = generic_getxattr,
+       .listxattr = squashfs_listxattr
 };
index fe2587af5512edc3947622a2e949c53c4fa4d539..733a17c42945661d505474cf600b57037e1ff556 100644 (file)
@@ -73,8 +73,11 @@ extern struct inode *squashfs_iget(struct super_block *, long long,
                                unsigned int);
 extern int squashfs_read_inode(struct inode *, long long);
 
+/* xattr.c */
+extern ssize_t squashfs_listxattr(struct dentry *, char *, size_t);
+
 /*
- * Inodes, files and decompressor operations
+ * Inodes, files,  decompressor and xattr operations
  */
 
 /* dir.c */
@@ -86,11 +89,18 @@ extern const struct export_operations squashfs_export_ops;
 /* file.c */
 extern const struct address_space_operations squashfs_aops;
 
+/* inode.c */
+extern const struct inode_operations squashfs_inode_ops;
+
 /* namei.c */
 extern const struct inode_operations squashfs_dir_inode_ops;
 
 /* symlink.c */
 extern const struct address_space_operations squashfs_symlink_aops;
+extern const struct inode_operations squashfs_symlink_inode_ops;
+
+/* xattr.c */
+extern const struct xattr_handler *squashfs_xattr_handlers[];
 
 /* zlib_wrapper.c */
 extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
index 79024245ea00f7fb370e7aa8dbef6819da33854b..8eabb808b78dcd18009565bbc5ed213b1261cb8b 100644 (file)
@@ -46,6 +46,7 @@
 #define SQUASHFS_NAME_LEN              256
 
 #define SQUASHFS_INVALID_FRAG          (0xffffffffU)
+#define SQUASHFS_INVALID_XATTR         (0xffffffffU)
 #define SQUASHFS_INVALID_BLK           (-1LL)
 
 /* Filesystem flags */
 #define SQUASHFS_LFIFO_TYPE            13
 #define SQUASHFS_LSOCKET_TYPE          14
 
+/* Xattr types */
+#define SQUASHFS_XATTR_USER             0
+#define SQUASHFS_XATTR_TRUSTED          1
+#define SQUASHFS_XATTR_SECURITY         2
+#define SQUASHFS_XATTR_VALUE_OOL        256
+#define SQUASHFS_XATTR_PREFIX_MASK      0xff
+
 /* Flag whether block is compressed or uncompressed, bit is set if block is
  * uncompressed */
 #define SQUASHFS_COMPRESSED_BIT                (1 << 15)
 
 #define SQUASHFS_ID_BLOCK_BYTES(A)     (SQUASHFS_ID_BLOCKS(A) *\
                                        sizeof(u64))
+/* xattr id lookup table defines */
+#define SQUASHFS_XATTR_BYTES(A)                ((A) * sizeof(struct squashfs_xattr_id))
+
+#define SQUASHFS_XATTR_BLOCK(A)                (SQUASHFS_XATTR_BYTES(A) / \
+                                       SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_XATTR_BLOCK_OFFSET(A) (SQUASHFS_XATTR_BYTES(A) % \
+                                       SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_XATTR_BLOCKS(A)       ((SQUASHFS_XATTR_BYTES(A) + \
+                                       SQUASHFS_METADATA_SIZE - 1) / \
+                                       SQUASHFS_METADATA_SIZE)
+
+#define SQUASHFS_XATTR_BLOCK_BYTES(A)  (SQUASHFS_XATTR_BLOCKS(A) *\
+                                       sizeof(u64))
+#define SQUASHFS_XATTR_BLK(A)          ((unsigned int) ((A) >> 16))
+
+#define SQUASHFS_XATTR_OFFSET(A)       ((unsigned int) ((A) & 0xffff))
 
 /* cached data constants for filesystem */
 #define SQUASHFS_CACHED_BLKS           8
@@ -228,7 +254,7 @@ struct squashfs_super_block {
        __le64                  root_inode;
        __le64                  bytes_used;
        __le64                  id_table_start;
-       __le64                  xattr_table_start;
+       __le64                  xattr_id_table_start;
        __le64                  inode_table_start;
        __le64                  directory_table_start;
        __le64                  fragment_table_start;
@@ -261,6 +287,17 @@ struct squashfs_ipc_inode {
        __le32                  nlink;
 };
 
+struct squashfs_lipc_inode {
+       __le16                  inode_type;
+       __le16                  mode;
+       __le16                  uid;
+       __le16                  guid;
+       __le32                  mtime;
+       __le32                  inode_number;
+       __le32                  nlink;
+       __le32                  xattr;
+};
+
 struct squashfs_dev_inode {
        __le16                  inode_type;
        __le16                  mode;
@@ -272,6 +309,18 @@ struct squashfs_dev_inode {
        __le32                  rdev;
 };
 
+struct squashfs_ldev_inode {
+       __le16                  inode_type;
+       __le16                  mode;
+       __le16                  uid;
+       __le16                  guid;
+       __le32                  mtime;
+       __le32                  inode_number;
+       __le32                  nlink;
+       __le32                  rdev;
+       __le32                  xattr;
+};
+
 struct squashfs_symlink_inode {
        __le16                  inode_type;
        __le16                  mode;
@@ -349,12 +398,14 @@ struct squashfs_ldir_inode {
 union squashfs_inode {
        struct squashfs_base_inode              base;
        struct squashfs_dev_inode               dev;
+       struct squashfs_ldev_inode              ldev;
        struct squashfs_symlink_inode           symlink;
        struct squashfs_reg_inode               reg;
        struct squashfs_lreg_inode              lreg;
        struct squashfs_dir_inode               dir;
        struct squashfs_ldir_inode              ldir;
        struct squashfs_ipc_inode               ipc;
+       struct squashfs_lipc_inode              lipc;
 };
 
 struct squashfs_dir_entry {
@@ -377,4 +428,27 @@ struct squashfs_fragment_entry {
        unsigned int            unused;
 };
 
+struct squashfs_xattr_entry {
+       __le16                  type;
+       __le16                  size;
+       char                    data[0];
+};
+
+struct squashfs_xattr_val {
+       __le32                  vsize;
+       char                    value[0];
+};
+
+struct squashfs_xattr_id {
+       __le64                  xattr;
+       __le32                  count;
+       __le32                  size;
+};
+
+struct squashfs_xattr_id_table {
+       __le64                  xattr_table_start;
+       __le32                  xattr_ids;
+       __le32                  unused;
+};
+
 #endif
index fbfca30c0c688a0c17c902db1300e08d6adcbdea..d3e3a37f28a14609c17a4d4da4759e6567346bc4 100644 (file)
@@ -26,6 +26,9 @@
 struct squashfs_inode_info {
        u64             start;
        int             offset;
+       u64             xattr;
+       unsigned int    xattr_size;
+       int             xattr_count;
        union {
                struct {
                        u64             fragment_block;
index 2e77dc547e253df03d94f8dfe0a849358810d082..d9037a5215f00b77044c030b37c1255fe4273a41 100644 (file)
@@ -61,6 +61,7 @@ struct squashfs_sb_info {
        int                                     next_meta_index;
        __le64                                  *id_table;
        __le64                                  *fragment_index;
+       __le64                                  *xattr_id_table;
        struct mutex                            read_data_mutex;
        struct mutex                            meta_index_mutex;
        struct meta_index                       *meta_index;
@@ -68,9 +69,11 @@ struct squashfs_sb_info {
        __le64                                  *inode_lookup_table;
        u64                                     inode_table;
        u64                                     directory_table;
+       u64                                     xattr_table;
        unsigned int                            block_size;
        unsigned short                          block_log;
        long long                               bytes_used;
        unsigned int                            inodes;
+       int                                     xattr_ids;
 };
 #endif
index 48b6f4a385a60ccf40276bb08c0e591edd3561b1..88b4f8606652b8e675621a2f545aff357ea176ae 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/magic.h>
+#include <linux/xattr.h>
 
 #include "squashfs_fs.h"
 #include "squashfs_fs_sb.h"
 #include "squashfs_fs_i.h"
 #include "squashfs.h"
 #include "decompressor.h"
+#include "xattr.h"
 
 static struct file_system_type squashfs_fs_type;
 static const struct super_operations squashfs_super_ops;
@@ -82,7 +84,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
        long long root_inode;
        unsigned short flags;
        unsigned int fragments;
-       u64 lookup_table_start;
+       u64 lookup_table_start, xattr_id_table_start;
        int err;
 
        TRACE("Entered squashfs_fill_superblock\n");
@@ -139,13 +141,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
        if (msblk->decompressor == NULL)
                goto failed_mount;
 
-       /*
-        * Check if there's xattrs in the filesystem.  These are not
-        * supported in this version, so warn that they will be ignored.
-        */
-       if (le64_to_cpu(sblk->xattr_table_start) != SQUASHFS_INVALID_BLK)
-               ERROR("Xattrs in filesystem, these will be ignored\n");
-
        /* Check the filesystem does not extend beyond the end of the
           block device */
        msblk->bytes_used = le64_to_cpu(sblk->bytes_used);
@@ -253,7 +248,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
 allocate_lookup_table:
        lookup_table_start = le64_to_cpu(sblk->lookup_table_start);
        if (lookup_table_start == SQUASHFS_INVALID_BLK)
-               goto allocate_root;
+               goto allocate_xattr_table;
 
        /* Allocate and read inode lookup table */
        msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
@@ -266,6 +261,21 @@ allocate_lookup_table:
 
        sb->s_export_op = &squashfs_export_ops;
 
+allocate_xattr_table:
+       sb->s_xattr = squashfs_xattr_handlers;
+       xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start);
+       if (xattr_id_table_start == SQUASHFS_INVALID_BLK)
+               goto allocate_root;
+
+       /* Allocate and read xattr id lookup table */
+       msblk->xattr_id_table = squashfs_read_xattr_id_table(sb,
+               xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids);
+       if (IS_ERR(msblk->xattr_id_table)) {
+               err = PTR_ERR(msblk->xattr_id_table);
+               msblk->xattr_id_table = NULL;
+               if (err != -ENOTSUPP)
+                       goto failed_mount;
+       }
 allocate_root:
        root = new_inode(sb);
        if (!root) {
@@ -301,6 +311,7 @@ failed_mount:
        kfree(msblk->inode_lookup_table);
        kfree(msblk->fragment_index);
        kfree(msblk->id_table);
+       kfree(msblk->xattr_id_table);
        kfree(sb->s_fs_info);
        sb->s_fs_info = NULL;
        kfree(sblk);
@@ -355,6 +366,7 @@ static void squashfs_put_super(struct super_block *sb)
                kfree(sbi->fragment_index);
                kfree(sbi->meta_index);
                kfree(sbi->inode_lookup_table);
+               kfree(sbi->xattr_id_table);
                kfree(sb->s_fs_info);
                sb->s_fs_info = NULL;
        }
index 32b911f4ee39e859d9a03d7b68b8ef7e33e11552..ec86434921e18c6a5bd180246439f84b56a5d00b 100644 (file)
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/pagemap.h>
+#include <linux/xattr.h>
 
 #include "squashfs_fs.h"
 #include "squashfs_fs_sb.h"
 #include "squashfs_fs_i.h"
 #include "squashfs.h"
+#include "xattr.h"
 
 static int squashfs_symlink_readpage(struct file *file, struct page *page)
 {
@@ -114,3 +116,12 @@ error_out:
 const struct address_space_operations squashfs_symlink_aops = {
        .readpage = squashfs_symlink_readpage
 };
+
+const struct inode_operations squashfs_symlink_inode_ops = {
+       .readlink = generic_readlink,
+       .follow_link = page_follow_link_light,
+       .put_link = page_put_link,
+       .getxattr = generic_getxattr,
+       .listxattr = squashfs_listxattr
+};
+
diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c
new file mode 100644 (file)
index 0000000..c7655e8
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2010
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
+ *
+ * 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,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * xattr_id.c
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/vfs.h>
+#include <linux/xattr.h>
+#include <linux/slab.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs_fs_i.h"
+#include "squashfs.h"
+
+static const struct xattr_handler *squashfs_xattr_handler(int);
+
+ssize_t squashfs_listxattr(struct dentry *d, char *buffer,
+       size_t buffer_size)
+{
+       struct inode *inode = d->d_inode;
+       struct super_block *sb = inode->i_sb;
+       struct squashfs_sb_info *msblk = sb->s_fs_info;
+       u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)
+                                                + msblk->xattr_table;
+       int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);
+       int count = squashfs_i(inode)->xattr_count;
+       size_t rest = buffer_size;
+       int err;
+
+       /* check that the file system has xattrs */
+       if (msblk->xattr_id_table == NULL)
+               return -EOPNOTSUPP;
+
+       /* loop reading each xattr name */
+       while (count--) {
+               struct squashfs_xattr_entry entry;
+               struct squashfs_xattr_val val;
+               const struct xattr_handler *handler;
+               int name_size, prefix_size = 0;
+
+               err = squashfs_read_metadata(sb, &entry, &start, &offset,
+                                                       sizeof(entry));
+               if (err < 0)
+                       goto failed;
+
+               name_size = le16_to_cpu(entry.size);
+               handler = squashfs_xattr_handler(le16_to_cpu(entry.type));
+               if (handler)
+                       prefix_size = handler->list(d, buffer, rest, NULL,
+                               name_size, handler->flags);
+               if (prefix_size) {
+                       if (buffer) {
+                               if (prefix_size + name_size + 1 > rest) {
+                                       err = -ERANGE;
+                                       goto failed;
+                               }
+                               buffer += prefix_size;
+                       }
+                       err = squashfs_read_metadata(sb, buffer, &start,
+                               &offset, name_size);
+                       if (err < 0)
+                               goto failed;
+                       if (buffer) {
+                               buffer[name_size] = '\0';
+                               buffer += name_size + 1;
+                       }
+                       rest -= prefix_size + name_size + 1;
+               } else  {
+                       /* no handler or insuffficient privileges, so skip */
+                       err = squashfs_read_metadata(sb, NULL, &start,
+                               &offset, name_size);
+                       if (err < 0)
+                               goto failed;
+               }
+
+
+               /* skip remaining xattr entry */
+               err = squashfs_read_metadata(sb, &val, &start, &offset,
+                                               sizeof(val));
+               if (err < 0)
+                       goto failed;
+
+               err = squashfs_read_metadata(sb, NULL, &start, &offset,
+                                               le32_to_cpu(val.vsize));
+               if (err < 0)
+                       goto failed;
+       }
+       err = buffer_size - rest;
+
+failed:
+       return err;
+}
+
+
+static int squashfs_xattr_get(struct inode *inode, int name_index,
+       const char *name, void *buffer, size_t buffer_size)
+{
+       struct super_block *sb = inode->i_sb;
+       struct squashfs_sb_info *msblk = sb->s_fs_info;
+       u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)
+                                                + msblk->xattr_table;
+       int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);
+       int count = squashfs_i(inode)->xattr_count;
+       int name_len = strlen(name);
+       int err, vsize;
+       char *target = kmalloc(name_len, GFP_KERNEL);
+
+       if (target == NULL)
+               return  -ENOMEM;
+
+       /* loop reading each xattr name */
+       for (; count; count--) {
+               struct squashfs_xattr_entry entry;
+               struct squashfs_xattr_val val;
+               int type, prefix, name_size;
+
+               err = squashfs_read_metadata(sb, &entry, &start, &offset,
+                                                       sizeof(entry));
+               if (err < 0)
+                       goto failed;
+
+               name_size = le16_to_cpu(entry.size);
+               type = le16_to_cpu(entry.type);
+               prefix = type & SQUASHFS_XATTR_PREFIX_MASK;
+
+               if (prefix == name_index && name_size == name_len)
+                       err = squashfs_read_metadata(sb, target, &start,
+                                               &offset, name_size);
+               else
+                       err = squashfs_read_metadata(sb, NULL, &start,
+                                               &offset, name_size);
+               if (err < 0)
+                       goto failed;
+
+               if (prefix == name_index && name_size == name_len &&
+                                       strncmp(target, name, name_size) == 0) {
+                       /* found xattr */
+                       if (type & SQUASHFS_XATTR_VALUE_OOL) {
+                               __le64 xattr;
+                               /* val is a reference to the real location */
+                               err = squashfs_read_metadata(sb, &val, &start,
+                                               &offset, sizeof(val));
+                               if (err < 0)
+                                       goto failed;
+                               err = squashfs_read_metadata(sb, &xattr, &start,
+                                        &offset, sizeof(xattr));
+                               if (err < 0)
+                                       goto failed;
+                               xattr = le64_to_cpu(xattr);
+                               start = SQUASHFS_XATTR_BLK(xattr) +
+                                                       msblk->xattr_table;
+                               offset = SQUASHFS_XATTR_OFFSET(xattr);
+                       }
+                       /* read xattr value */
+                       err = squashfs_read_metadata(sb, &val, &start, &offset,
+                                                       sizeof(val));
+                       if (err < 0)
+                               goto failed;
+
+                       vsize = le32_to_cpu(val.vsize);
+                       if (buffer) {
+                               if (vsize > buffer_size) {
+                                       err = -ERANGE;
+                                       goto failed;
+                               }
+                               err = squashfs_read_metadata(sb, buffer, &start,
+                                        &offset, vsize);
+                               if (err < 0)
+                                       goto failed;
+                       }
+                       break;
+               }
+
+               /* no match, skip remaining xattr entry */
+               err = squashfs_read_metadata(sb, &val, &start, &offset,
+                                                       sizeof(val));
+               if (err < 0)
+                       goto failed;
+               err = squashfs_read_metadata(sb, NULL, &start, &offset,
+                                               le32_to_cpu(val.vsize));
+               if (err < 0)
+                       goto failed;
+       }
+       err = count ? vsize : -ENODATA;
+
+failed:
+       kfree(target);
+       return err;
+}
+
+
+/*
+ * User namespace support
+ */
+static size_t squashfs_user_list(struct dentry *d, char *list, size_t list_size,
+       const char *name, size_t name_len, int type)
+{
+       if (list && XATTR_USER_PREFIX_LEN <= list_size)
+               memcpy(list, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
+       return XATTR_USER_PREFIX_LEN;
+}
+
+static int squashfs_user_get(struct dentry *d, const char *name, void *buffer,
+       size_t size, int type)
+{
+       if (name[0] == '\0')
+               return  -EINVAL;
+
+       return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_USER, name,
+               buffer, size);
+}
+
+static const struct xattr_handler squashfs_xattr_user_handler = {
+       .prefix = XATTR_USER_PREFIX,
+       .list   = squashfs_user_list,
+       .get    = squashfs_user_get
+};
+
+/*
+ * Trusted namespace support
+ */
+static size_t squashfs_trusted_list(struct dentry *d, char *list,
+       size_t list_size, const char *name, size_t name_len, int type)
+{
+       if (!capable(CAP_SYS_ADMIN))
+               return 0;
+
+       if (list && XATTR_TRUSTED_PREFIX_LEN <= list_size)
+               memcpy(list, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
+       return XATTR_TRUSTED_PREFIX_LEN;
+}
+
+static int squashfs_trusted_get(struct dentry *d, const char *name,
+       void *buffer, size_t size, int type)
+{
+       if (name[0] == '\0')
+               return  -EINVAL;
+
+       return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_TRUSTED, name,
+               buffer, size);
+}
+
+static const struct xattr_handler squashfs_xattr_trusted_handler = {
+       .prefix = XATTR_TRUSTED_PREFIX,
+       .list   = squashfs_trusted_list,
+       .get    = squashfs_trusted_get
+};
+
+/*
+ * Security namespace support
+ */
+static size_t squashfs_security_list(struct dentry *d, char *list,
+       size_t list_size, const char *name, size_t name_len, int type)
+{
+       if (list && XATTR_SECURITY_PREFIX_LEN <= list_size)
+               memcpy(list, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
+       return XATTR_SECURITY_PREFIX_LEN;
+}
+
+static int squashfs_security_get(struct dentry *d, const char *name,
+       void *buffer, size_t size, int type)
+{
+       if (name[0] == '\0')
+               return  -EINVAL;
+
+       return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_SECURITY, name,
+               buffer, size);
+}
+
+static const struct xattr_handler squashfs_xattr_security_handler = {
+       .prefix = XATTR_SECURITY_PREFIX,
+       .list   = squashfs_security_list,
+       .get    = squashfs_security_get
+};
+
+static inline const struct xattr_handler *squashfs_xattr_handler(int type)
+{
+       if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL))
+               /* ignore unrecognised type */
+               return NULL;
+
+       switch (type & SQUASHFS_XATTR_PREFIX_MASK) {
+       case SQUASHFS_XATTR_USER:
+               return &squashfs_xattr_user_handler;
+       case SQUASHFS_XATTR_TRUSTED:
+               return &squashfs_xattr_trusted_handler;
+       case SQUASHFS_XATTR_SECURITY:
+               return &squashfs_xattr_security_handler;
+       default:
+               /* ignore unrecognised type */
+               return NULL;
+       }
+}
+
+const struct xattr_handler *squashfs_xattr_handlers[] = {
+       &squashfs_xattr_user_handler,
+       &squashfs_xattr_trusted_handler,
+       &squashfs_xattr_security_handler,
+       NULL
+};
+
diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h
new file mode 100644 (file)
index 0000000..9da071a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2010
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
+ *
+ * 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,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * xattr.h
+ */
+
+#ifdef CONFIG_SQUASHFS_XATTRS
+extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64,
+               u64 *, int *);
+extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *,
+               int *, unsigned long long *);
+#else
+static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb,
+               u64 start, u64 *xattr_table_start, int *xattr_ids)
+{
+       ERROR("Xattrs in filesystem, these will be ignored\n");
+       return ERR_PTR(-ENOTSUPP);
+}
+
+static inline int squashfs_xattr_lookup(struct super_block *sb,
+               unsigned int index, int *count, int *size,
+               unsigned long long *xattr)
+{
+       return 0;
+}
+#define squashfs_listxattr NULL
+#define generic_getxattr NULL
+#define squashfs_xattr_handlers NULL
+#endif
diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c
new file mode 100644 (file)
index 0000000..cfb4110
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2010
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
+ *
+ * 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,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * xattr_id.c
+ */
+
+/*
+ * This file implements code to map the 32-bit xattr id stored in the inode
+ * into the on disk location of the xattr data.
+ */
+
+#include <linux/fs.h>
+#include <linux/vfs.h>
+#include <linux/slab.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs_fs_i.h"
+#include "squashfs.h"
+
+/*
+ * Map xattr id using the xattr id look up table
+ */
+int squashfs_xattr_lookup(struct super_block *sb, unsigned int index,
+               int *count, unsigned int *size, unsigned long long *xattr)
+{
+       struct squashfs_sb_info *msblk = sb->s_fs_info;
+       int block = SQUASHFS_XATTR_BLOCK(index);
+       int offset = SQUASHFS_XATTR_BLOCK_OFFSET(index);
+       u64 start_block = le64_to_cpu(msblk->xattr_id_table[block]);
+       struct squashfs_xattr_id id;
+       int err;
+
+       err = squashfs_read_metadata(sb, &id, &start_block, &offset,
+                                                       sizeof(id));
+       if (err < 0)
+               return err;
+
+       *xattr = le64_to_cpu(id.xattr);
+       *size = le32_to_cpu(id.size);
+       *count = le32_to_cpu(id.count);
+       return 0;
+}
+
+
+/*
+ * Read uncompressed xattr id lookup table indexes from disk into memory
+ */
+__le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start,
+               u64 *xattr_table_start, int *xattr_ids)
+{
+       unsigned int len;
+       __le64 *xid_table;
+       struct squashfs_xattr_id_table id_table;
+       int err;
+
+       err = squashfs_read_table(sb, &id_table, start, sizeof(id_table));
+       if (err < 0) {
+               ERROR("unable to read xattr id table\n");
+               return ERR_PTR(err);
+       }
+       *xattr_table_start = le64_to_cpu(id_table.xattr_table_start);
+       *xattr_ids = le32_to_cpu(id_table.xattr_ids);
+       len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids);
+
+       TRACE("In read_xattr_index_table, length %d\n", len);
+
+       /* Allocate xattr id lookup table indexes */
+       xid_table = kmalloc(len, GFP_KERNEL);
+       if (xid_table == NULL) {
+               ERROR("Failed to allocate xattr id index table\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       err = squashfs_read_table(sb, xid_table, start + sizeof(id_table), len);
+       if (err < 0) {
+               ERROR("unable to read xattr id index table\n");
+               kfree(xid_table);
+               return ERR_PTR(err);
+       }
+
+       return xid_table;
+}
index 3a84455c2a7789ef624d7a03b1154b20dbb89d06..1660c81ffa3d6df6dfc816441656279cdc4bcc32 100644 (file)
@@ -207,6 +207,7 @@ static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
 /* readdir and lookup functions */
 const struct file_operations udf_dir_operations = {
+       .llseek                 = generic_file_llseek,
        .read                   = generic_read_dir,
        .readdir                = udf_readdir,
        .unlocked_ioctl         = udf_ioctl,
index 14743d935a93f88a41691d122cc7f353fe102b17..ad9bc1ebd3a65d2f8ddd5d7172378b64499d3263 100644 (file)
@@ -918,6 +918,7 @@ again:
        sbi->s_bytesex = BYTESEX_LE;
        switch ((uspi->fs_magic = fs32_to_cpu(sb, usb3->fs_magic))) {
                case UFS_MAGIC:
+               case UFS_MAGIC_BW:
                case UFS2_MAGIC:
                case UFS_MAGIC_LFN:
                case UFS_MAGIC_FEA:
@@ -927,6 +928,7 @@ again:
        sbi->s_bytesex = BYTESEX_BE;
        switch ((uspi->fs_magic = fs32_to_cpu(sb, usb3->fs_magic))) {
                case UFS_MAGIC:
+               case UFS_MAGIC_BW:
                case UFS2_MAGIC:
                case UFS_MAGIC_LFN:
                case UFS_MAGIC_FEA:
index 6943ec677c0bef0feaca7efa2cee4202ee9949db..8aba544f9fad80b2a79ca581d6360340cf5e2314 100644 (file)
@@ -48,6 +48,7 @@ typedef __u16 __bitwise __fs16;
 #define UFS_SECTOR_SIZE 512
 #define UFS_SECTOR_BITS 9
 #define UFS_MAGIC  0x00011954
+#define UFS_MAGIC_BW 0x0f242697
 #define UFS2_MAGIC 0x19540119
 #define UFS_CIGAM  0x54190100 /* byteswapped MAGIC */
 
index 69206957b72c52efe1f9fe7d2479cfc931d7d7b7..0c80bb38773f142ef829dcbc190c60f2cf6ccff8 100644 (file)
@@ -123,15 +123,7 @@ static inline void dma_sync_single_range_for_cpu(struct device *dev,
                                                 size_t size,
                                                 enum dma_data_direction dir)
 {
-       struct dma_map_ops *ops = get_dma_ops(dev);
-
-       BUG_ON(!valid_dma_direction(dir));
-       if (ops->sync_single_range_for_cpu) {
-               ops->sync_single_range_for_cpu(dev, addr, offset, size, dir);
-               debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir);
-
-       } else
-               dma_sync_single_for_cpu(dev, addr + offset, size, dir);
+       dma_sync_single_for_cpu(dev, addr + offset, size, dir);
 }
 
 static inline void dma_sync_single_range_for_device(struct device *dev,
@@ -140,15 +132,7 @@ static inline void dma_sync_single_range_for_device(struct device *dev,
                                                    size_t size,
                                                    enum dma_data_direction dir)
 {
-       struct dma_map_ops *ops = get_dma_ops(dev);
-
-       BUG_ON(!valid_dma_direction(dir));
-       if (ops->sync_single_range_for_device) {
-               ops->sync_single_range_for_device(dev, addr, offset, size, dir);
-               debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir);
-
-       } else
-               dma_sync_single_for_device(dev, addr + offset, size, dir);
+       dma_sync_single_for_device(dev, addr + offset, size, dir);
 }
 
 static inline void
index 979c6a57f2f1b48690d46171b21edb5c954f083b..4f3d75e1ad391a669d842c7c58e65b46bfd9cbd4 100644 (file)
@@ -60,7 +60,9 @@ struct module;
  * @names: if set, must be an array of strings to use as alternative
  *      names for the GPIOs in this chip. Any entry in the array
  *      may be NULL if there is no alias for the GPIO, however the
- *      array must be @ngpio entries long.
+ *      array must be @ngpio entries long.  A name can include a single printk
+ *      format specifier for an unsigned int.  It is substituted by the actual
+ *      number of the gpio.
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -88,6 +90,9 @@ struct gpio_chip {
                                                unsigned offset);
        int                     (*direction_output)(struct gpio_chip *chip,
                                                unsigned offset, int value);
+       int                     (*set_debounce)(struct gpio_chip *chip,
+                                               unsigned offset, unsigned debounce);
+
        void                    (*set)(struct gpio_chip *chip,
                                                unsigned offset, int value);
 
@@ -98,7 +103,7 @@ struct gpio_chip {
                                                struct gpio_chip *chip);
        int                     base;
        u16                     ngpio;
-       char                    **names;
+       const char              *const *names;
        unsigned                can_sleep:1;
        unsigned                exported:1;
 };
@@ -121,6 +126,8 @@ extern void gpio_free(unsigned gpio);
 extern int gpio_direction_input(unsigned gpio);
 extern int gpio_direction_output(unsigned gpio, int value);
 
+extern int gpio_set_debounce(unsigned gpio, unsigned debounce);
+
 extern int gpio_get_value_cansleep(unsigned gpio);
 extern void gpio_set_value_cansleep(unsigned gpio, int value);
 
index 8b9454496a7c901edd8723586a98981916faeac8..5de07355fad492b10b15227e7959f7cc08e6b044 100644 (file)
@@ -11,7 +11,9 @@ struct scatterlist {
        unsigned int    offset;
        unsigned int    length;
        dma_addr_t      dma_address;
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
        unsigned int    dma_length;
+#endif
 };
 
 /*
@@ -22,22 +24,11 @@ struct scatterlist {
  * is 0.
  */
 #define sg_dma_address(sg)     ((sg)->dma_address)
-#ifndef sg_dma_len
-/*
- * Normally, you have an iommu on 64 bit machines, but not on 32 bit
- * machines. Architectures that are differnt should override this.
- */
-#if __BITS_PER_LONG == 64
+
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
 #define sg_dma_len(sg)         ((sg)->dma_length)
 #else
 #define sg_dma_len(sg)         ((sg)->length)
-#endif /* 64 bit */
-#endif /* sg_dma_len */
-
-#ifndef ISA_DMA_THRESHOLD
-#define ISA_DMA_THRESHOLD      (~0UL)
 #endif
 
-#define ARCH_HAS_SG_CHAIN
-
 #endif /* __ASM_GENERIC_SCATTERLIST_H */
index 510df36dd5d44f8b40e0ed048bbb7c8fa1ef506f..fd60700503c8545795a031e15147e466154f0051 100644 (file)
@@ -34,6 +34,9 @@
 #ifndef cpu_to_node
 #define cpu_to_node(cpu)       ((void)(cpu),0)
 #endif
+#ifndef cpu_to_mem
+#define cpu_to_mem(cpu)                ((void)(cpu),0)
+#endif
 #ifndef parent_node
 #define parent_node(node)      ((void)(node),0)
 #endif
index 67e652068e0e45b8031cafd2fb236be5e692c7c4..ef779c6fc3d7e89571390a01bbdb3da137bc1af1 100644 (file)
        }                                                               \
                                                                        \
        /* RapidIO route ops */                                         \
-       .rio_route        : AT(ADDR(.rio_route) - LOAD_OFFSET) {        \
-               VMLINUX_SYMBOL(__start_rio_route_ops) = .;              \
-               *(.rio_route_ops)                                       \
-               VMLINUX_SYMBOL(__end_rio_route_ops) = .;                \
+       .rio_ops        : AT(ADDR(.rio_ops) - LOAD_OFFSET) {            \
+               VMLINUX_SYMBOL(__start_rio_switch_ops) = .;             \
+               *(.rio_switch_ops)                                      \
+               VMLINUX_SYMBOL(__end_rio_switch_ops) = .;               \
        }                                                               \
                                                                        \
        TRACEDATA                                                       \
index 811dbb369379ff463110289bba1d44b9bb14a2a2..7a8db41552813ff15e6739943ad401cfe5f56b3c 100644 (file)
@@ -212,6 +212,8 @@ extern void kick_iocb(struct kiocb *iocb);
 extern int aio_complete(struct kiocb *iocb, long res, long res2);
 struct mm_struct;
 extern void exit_aio(struct mm_struct *mm);
+extern long do_io_submit(aio_context_t ctx_id, long nr,
+                        struct iocb __user *__user *iocbpp, bool compat);
 #else
 static inline ssize_t wait_on_sync_kiocb(struct kiocb *iocb) { return 0; }
 static inline int aio_put_req(struct kiocb *iocb) { return 0; }
@@ -219,6 +221,9 @@ static inline void kick_iocb(struct kiocb *iocb) { }
 static inline int aio_complete(struct kiocb *iocb, long res, long res2) { return 0; }
 struct mm_struct;
 static inline void exit_aio(struct mm_struct *mm) { }
+static inline long do_io_submit(aio_context_t ctx_id, long nr,
+                               struct iocb __user * __user *iocbpp,
+                               bool compat) { return 0; }
 #endif /* CONFIG_AIO */
 
 static inline struct kiocb *list_kiocb(struct list_head *h)
index daf8c480c7867e9a60f3cdd715e9b4a8c030942c..6fb2720882fc9c50f1db491c4ec90460c59f2749 100644 (file)
@@ -141,6 +141,7 @@ extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order);
 extern void bitmap_release_region(unsigned long *bitmap, int pos, int order);
 extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order);
 extern void bitmap_copy_le(void *dst, const unsigned long *src, int nbits);
+extern int bitmap_ord_to_pos(const unsigned long *bitmap, int n, int bits);
 
 #define BITMAP_LAST_WORD_MASK(nbits)                                   \
 (                                                                      \
index d53a67dff018e1644e711c384b97a6074038175f..3c80fd7e8b567c8f6d8cd768c120926a424ec577 100644 (file)
@@ -7,9 +7,6 @@
 #ifndef __BIG_ENDIAN_BITFIELD
 #define __BIG_ENDIAN_BITFIELD
 #endif
-#ifndef __BYTE_ORDER
-#define __BYTE_ORDER __BIG_ENDIAN
-#endif
 
 #include <linux/types.h>
 #include <linux/swab.h>
index f7f8ad13adb6d06fb60641374dff3e59f924ed26..83195fb82962838fa8d4c70ea77927ac0b7ac7e2 100644 (file)
@@ -7,9 +7,6 @@
 #ifndef __LITTLE_ENDIAN_BITFIELD
 #define __LITTLE_ENDIAN_BITFIELD
 #endif
-#ifndef __BYTE_ORDER
-#define __BYTE_ORDER __LITTLE_ENDIAN
-#endif
 
 #include <linux/types.h>
 #include <linux/swab.h>
index 8f78073d7caaa278017232112f0d3da05aa0d4c0..0c621604baa1d7ff8185029d4eaade8ccad82d64 100644 (file)
@@ -397,7 +397,7 @@ struct cftype {
         * This callback must be implemented, if you want provide
         * notification functionality.
         */
-       int (*unregister_event)(struct cgroup *cgrp, struct cftype *cft,
+       void (*unregister_event)(struct cgroup *cgrp, struct cftype *cft,
                        struct eventfd_ctx *eventfd);
 };
 
index 717c691ecd8e3acd03c51d9d8f42efc2ec489af9..168f7daa7bdeb8d05e30895a82460310b6924dce 100644 (file)
@@ -356,5 +356,9 @@ asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename,
 asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename,
                                  int flags, int mode);
 
+extern ssize_t compat_rw_copy_check_uvector(int type,
+               const struct compat_iovec __user *uvector, unsigned long nr_segs,
+               unsigned long fast_segs, struct iovec *fast_pointer,
+               struct iovec **ret_pointer);
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */
index 20b51cab65939b8fbe71b767648e2952ae816770..457ed765a116a4c06ecd192e0165cf5af096c818 100644 (file)
@@ -69,6 +69,7 @@ extern void cpuset_task_status_allowed(struct seq_file *m,
                                        struct task_struct *task);
 
 extern int cpuset_mem_spread_node(void);
+extern int cpuset_slab_spread_node(void);
 
 static inline int cpuset_do_page_mem_spread(void)
 {
@@ -194,6 +195,11 @@ static inline int cpuset_mem_spread_node(void)
        return 0;
 }
 
+static inline int cpuset_slab_spread_node(void)
+{
+       return 0;
+}
+
 static inline int cpuset_do_page_mem_spread(void)
 {
        return 0;
index 52507c3e1387581b0e33b6435b26642bdb722d08..75c0fa8813088c31148be71b7cbff77670b6e5d0 100644 (file)
@@ -156,7 +156,6 @@ extern int copy_creds(struct task_struct *, unsigned long);
 extern struct cred *cred_alloc_blank(void);
 extern struct cred *prepare_creds(void);
 extern struct cred *prepare_exec_creds(void);
-extern struct cred *prepare_usermodehelper_creds(void);
 extern int commit_creds(struct cred *);
 extern void abort_creds(struct cred *);
 extern const struct cred *override_creds(const struct cred *);
index ca32ed78b05719db06704a0c99e037fc859bbe83..89b7e1a605b8113ac90e7f4bd51f73d595988ade 100644 (file)
@@ -40,16 +40,6 @@ struct dma_map_ops {
        void (*sync_single_for_device)(struct device *dev,
                                       dma_addr_t dma_handle, size_t size,
                                       enum dma_data_direction dir);
-       void (*sync_single_range_for_cpu)(struct device *dev,
-                                         dma_addr_t dma_handle,
-                                         unsigned long offset,
-                                         size_t size,
-                                         enum dma_data_direction dir);
-       void (*sync_single_range_for_device)(struct device *dev,
-                                            dma_addr_t dma_handle,
-                                            unsigned long offset,
-                                            size_t size,
-                                            enum dma_data_direction dir);
        void (*sync_sg_for_cpu)(struct device *dev,
                                struct scatterlist *sg, int nents,
                                enum dma_data_direction dir);
@@ -105,21 +95,6 @@ static inline int is_device_dma_capable(struct device *dev)
 #include <asm-generic/dma-mapping-broken.h>
 #endif
 
-/* for backwards compatibility, removed soon */
-static inline void __deprecated dma_sync_single(struct device *dev,
-                                               dma_addr_t addr, size_t size,
-                                               enum dma_data_direction dir)
-{
-       dma_sync_single_for_cpu(dev, addr, size, dir);
-}
-
-static inline void __deprecated dma_sync_sg(struct device *dev,
-                                           struct scatterlist *sg, int nelems,
-                                           enum dma_data_direction dir)
-{
-       dma_sync_sg_for_cpu(dev, sg, nelems, dir);
-}
-
 static inline u64 dma_get_mask(struct device *dev)
 {
        if (dev && dev->dma_mask && *dev->dma_mask)
index 4bd94bf5e739253d17e5fb6ff3416e17966e8d09..72e2b8ac2a5a997b8d055e72d81d7358cddf6dce 100644 (file)
 #define CSR_DESCRIPTOR         0x01
 #define CSR_VENDOR             0x03
 #define CSR_HARDWARE_VERSION   0x04
-#define CSR_NODE_CAPABILITIES  0x0c
 #define CSR_UNIT               0x11
 #define CSR_SPECIFIER_ID       0x12
 #define CSR_VERSION            0x13
 #define CSR_DEPENDENT_INFO     0x14
 #define CSR_MODEL              0x17
-#define CSR_INSTANCE           0x18
 #define CSR_DIRECTORY_ID       0x20
 
 struct fw_csr_iterator {
@@ -89,7 +87,6 @@ struct fw_card {
        int current_tlabel;
        u64 tlabel_mask;
        struct list_head transaction_list;
-       struct timer_list flush_timer;
        unsigned long reset_jiffies;
 
        unsigned long long guid;
@@ -290,6 +287,8 @@ struct fw_transaction {
        int tlabel;
        int timestamp;
        struct list_head link;
+       struct fw_card *card;
+       struct timer_list split_timeout_timer;
 
        struct fw_packet packet;
 
index b336cb9ca9a0b5557f13037da2725dda3f531e2f..9682d52d1507a55752965ee0c26ba97fdf8adc5c 100644 (file)
@@ -2228,6 +2228,7 @@ extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
 
 extern void
 file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
+extern loff_t noop_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
 extern loff_t generic_file_llseek_unlocked(struct file *file, loff_t offset,
index 4e949a5b5b85d810938561328210598ac2055512..03f616b78cfa8b857e727ea220a60c05a87bb89f 100644 (file)
@@ -51,6 +51,11 @@ static inline int gpio_direction_output(unsigned gpio, int value)
        return -ENOSYS;
 }
 
+static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
+{
+       return -ENOSYS;
+}
+
 static inline int gpio_get_value(unsigned gpio)
 {
        /* GPIO can never have been requested or set as {in,out}put */
index e10336631c62d40e51989ce305282ae731c8d580..c04bac8bf2feb45cdfe18f959476c4efd6693755 100644 (file)
@@ -7,6 +7,9 @@ struct max732x_platform_data {
        /* number of the first GPIO */
        unsigned        gpio_base;
 
+       /* interrupt base */
+       int             irq_base;
+
        void            *context;       /* param to setup/teardown */
 
        int             (*setup)(struct i2c_client *client,
index d5c5a60c8a0b1a2d513b8c19e060c4b8d1d94bd5..139ba52667c89cf9f02cc1ce16cb53bc81a77f0b 100644 (file)
@@ -24,7 +24,7 @@ struct pca953x_platform_data {
        int             (*teardown)(struct i2c_client *client,
                                unsigned gpio, unsigned ngpio,
                                void *context);
-       char            **names;
+       const char      *const *names;
 };
 
 #endif /* _LINUX_PCA953X_H */
index 7996fc2c9ba9ee4fc0b573e4e07dffcc0c028c9b..2beaa13492beb5dffdb90c0041d942a3785181e1 100644 (file)
@@ -16,7 +16,7 @@ extern struct files_struct init_files;
 extern struct fs_struct init_fs;
 
 #define INIT_SIGNALS(sig) {                                            \
-       .count          = ATOMIC_INIT(1),                               \
+       .nr_threads     = 1,                                            \
        .wait_chldexit  = __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\
        .shared_pending = {                                             \
                .list = LIST_HEAD_INIT(sig.shared_pending.list),        \
@@ -35,7 +35,7 @@ extern struct nsproxy init_nsproxy;
 
 #define INIT_SIGHAND(sighand) {                                                \
        .count          = ATOMIC_INIT(1),                               \
-       .action         = { { { .sa_handler = NULL, } }, },             \
+       .action         = { { { .sa_handler = SIG_DFL, } }, },          \
        .siglock        = __SPIN_LOCK_UNLOCKED(sighand.siglock),        \
        .signalfd_wqh   = __WAIT_QUEUE_HEAD_INITIALIZER(sighand.signalfd_wqh),  \
 }
@@ -45,9 +45,9 @@ extern struct group_info init_groups;
 #define INIT_STRUCT_PID {                                              \
        .count          = ATOMIC_INIT(1),                               \
        .tasks          = {                                             \
-               { .first = &init_task.pids[PIDTYPE_PID].node },         \
-               { .first = &init_task.pids[PIDTYPE_PGID].node },        \
-               { .first = &init_task.pids[PIDTYPE_SID].node },         \
+               { .first = NULL },                                      \
+               { .first = NULL },                                      \
+               { .first = NULL },                                      \
        },                                                              \
        .level          = 0,                                            \
        .numbers        = { {                                           \
@@ -61,7 +61,7 @@ extern struct group_info init_groups;
 {                                                              \
        .node = {                                               \
                .next = NULL,                                   \
-               .pprev = &init_struct_pid.tasks[type].first,    \
+               .pprev = NULL,                                  \
        },                                                      \
        .pid = &init_struct_pid,                                \
 }
@@ -163,6 +163,7 @@ extern struct cred init_cred;
                [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID),           \
                [PIDTYPE_SID]  = INIT_PID_LINK(PIDTYPE_SID),            \
        },                                                              \
+       .thread_group   = LIST_HEAD_INIT(tsk.thread_group),             \
        .dirties = INIT_PROP_LOCAL_SINGLE(dirties),                     \
        INIT_IDS                                                        \
        INIT_PERF_EVENTS(tsk)                                           \
index 83524e4f3290ab1cff44a8fc7a1e229bb2940b6f..6fcc9101beeb3e907b9b4c030fef7db9b7f9e334 100644 (file)
@@ -1155,7 +1155,7 @@ struct input_dev {
 
        int sync;
 
-       int abs[ABS_MAX + 1];
+       int abs[ABS_CNT];
        int rep[REP_MAX + 1];
 
        unsigned long key[BITS_TO_LONGS(KEY_CNT)];
@@ -1163,11 +1163,11 @@ struct input_dev {
        unsigned long snd[BITS_TO_LONGS(SND_CNT)];
        unsigned long sw[BITS_TO_LONGS(SW_CNT)];
 
-       int absmax[ABS_MAX + 1];
-       int absmin[ABS_MAX + 1];
-       int absfuzz[ABS_MAX + 1];
-       int absflat[ABS_MAX + 1];
-       int absres[ABS_MAX + 1];
+       int absmax[ABS_CNT];
+       int absmin[ABS_CNT];
+       int absfuzz[ABS_CNT];
+       int absflat[ABS_CNT];
+       int absres[ABS_CNT];
 
        int (*open)(struct input_dev *dev);
        void (*close)(struct input_dev *dev);
index 9e20c29c1e1401d1f814476087436d93fdb83ba0..47199b13e0eb9c1f102acd1e188a23be5c53b1cc 100644 (file)
@@ -64,8 +64,8 @@ struct js_event {
 #define JSIOCSCORR             _IOW('j', 0x21, struct js_corr)                 /* set correction values */
 #define JSIOCGCORR             _IOR('j', 0x22, struct js_corr)                 /* get correction values */
 
-#define JSIOCSAXMAP            _IOW('j', 0x31, __u8[ABS_MAX + 1])              /* set axis mapping */
-#define JSIOCGAXMAP            _IOR('j', 0x32, __u8[ABS_MAX + 1])              /* get axis mapping */
+#define JSIOCSAXMAP            _IOW('j', 0x31, __u8[ABS_CNT])                  /* set axis mapping */
+#define JSIOCGAXMAP            _IOR('j', 0x32, __u8[ABS_CNT])                  /* get axis mapping */
 #define JSIOCSBTNMAP           _IOW('j', 0x33, __u16[KEY_MAX - BTN_MISC + 1])  /* set button mapping */
 #define JSIOCGBTNMAP           _IOR('j', 0x34, __u16[KEY_MAX - BTN_MISC + 1])  /* get button mapping */
 
index facb27fe7de00a570d959d49f1c114bc16103a02..6efd7a78de6aaaa6d74c526ba44f5fafa81e1fad 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/stddef.h>
 #include <linux/errno.h>
 #include <linux/compiler.h>
+#include <linux/workqueue.h>
 
 #define KMOD_PATH_LEN 256
 
@@ -45,19 +46,6 @@ static inline int request_module_nowait(const char *name, ...) { return -ENOSYS;
 
 struct key;
 struct file;
-struct subprocess_info;
-
-/* Allocate a subprocess_info structure */
-struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
-                                                 char **envp, gfp_t gfp_mask);
-
-/* Set various pieces of state into the subprocess_info structure */
-void call_usermodehelper_setkeys(struct subprocess_info *info,
-                                struct key *session_keyring);
-int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
-                                 struct file **filp);
-void call_usermodehelper_setcleanup(struct subprocess_info *info,
-                                   void (*cleanup)(char **argv, char **envp));
 
 enum umh_wait {
        UMH_NO_WAIT = -1,       /* don't wait at all */
@@ -65,6 +53,29 @@ enum umh_wait {
        UMH_WAIT_PROC = 1,      /* wait for the process to complete */
 };
 
+struct subprocess_info {
+       struct work_struct work;
+       struct completion *complete;
+       char *path;
+       char **argv;
+       char **envp;
+       enum umh_wait wait;
+       int retval;
+       int (*init)(struct subprocess_info *info);
+       void (*cleanup)(struct subprocess_info *info);
+       void *data;
+};
+
+/* Allocate a subprocess_info structure */
+struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
+                                                 char **envp, gfp_t gfp_mask);
+
+/* Set various pieces of state into the subprocess_info structure */
+void call_usermodehelper_setfns(struct subprocess_info *info,
+                   int (*init)(struct subprocess_info *info),
+                   void (*cleanup)(struct subprocess_info *info),
+                   void *data);
+
 /* Actually execute the sub-process */
 int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait);
 
@@ -73,38 +84,33 @@ int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait);
 void call_usermodehelper_freeinfo(struct subprocess_info *info);
 
 static inline int
-call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
+call_usermodehelper_fns(char *path, char **argv, char **envp,
+                       enum umh_wait wait,
+                       int (*init)(struct subprocess_info *info),
+                       void (*cleanup)(struct subprocess_info *), void *data)
 {
        struct subprocess_info *info;
        gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
 
        info = call_usermodehelper_setup(path, argv, envp, gfp_mask);
+
        if (info == NULL)
                return -ENOMEM;
+
+       call_usermodehelper_setfns(info, init, cleanup, data);
+
        return call_usermodehelper_exec(info, wait);
 }
 
 static inline int
-call_usermodehelper_keys(char *path, char **argv, char **envp,
-                        struct key *session_keyring, enum umh_wait wait)
+call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
 {
-       struct subprocess_info *info;
-       gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
-
-       info = call_usermodehelper_setup(path, argv, envp, gfp_mask);
-       if (info == NULL)
-               return -ENOMEM;
-
-       call_usermodehelper_setkeys(info, session_keyring);
-       return call_usermodehelper_exec(info, wait);
+       return call_usermodehelper_fns(path, argv, envp, wait,
+                                      NULL, NULL, NULL);
 }
 
 extern void usermodehelper_init(void);
 
-struct file;
-extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[],
-                                   struct file **filp);
-
 extern int usermodehelper_disable(void);
 extern void usermodehelper_enable(void);
 
index 05894795fdc1c041ff3ef23a81e4662fa5e909c4..9411d32840b055cfc5b445a670e43e8a0173f585 100644 (file)
@@ -90,7 +90,8 @@ int mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *cgroup)
 extern struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *mem);
 
 extern int
-mem_cgroup_prepare_migration(struct page *page, struct mem_cgroup **ptr);
+mem_cgroup_prepare_migration(struct page *page,
+       struct page *newpage, struct mem_cgroup **ptr);
 extern void mem_cgroup_end_migration(struct mem_cgroup *mem,
        struct page *oldpage, struct page *newpage);
 
@@ -227,7 +228,8 @@ static inline struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *mem)
 }
 
 static inline int
-mem_cgroup_prepare_migration(struct page *page, struct mem_cgroup **ptr)
+mem_cgroup_prepare_migration(struct page *page, struct page *newpage,
+       struct mem_cgroup **ptr)
 {
        return 0;
 }
index 3196c84cc630b67fae5a3df03c9b1dee3b3b91e3..f65913c9f5a4001f5e53207c5f4a04e61f332ff7 100644 (file)
@@ -230,7 +230,7 @@ static inline void *mmc_priv(struct mmc_host *host)
 #define mmc_classdev(x)        (&(x)->class_dev)
 #define mmc_hostname(x)        (dev_name(&(x)->class_dev))
 
-extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
+extern int mmc_suspend_host(struct mmc_host *);
 extern int mmc_resume_host(struct mmc_host *);
 
 extern void mmc_power_save_host(struct mmc_host *host);
diff --git a/include/linux/mmc/sdhci-spear.h b/include/linux/mmc/sdhci-spear.h
new file mode 100644 (file)
index 0000000..9188c97
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * include/linux/mmc/sdhci-spear.h
+ *
+ * SDHCI declarations specific to ST SPEAr platform
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Viresh Kumar<viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef MMC_SDHCI_SPEAR_H
+#define MMC_SDHCI_SPEAR_H
+
+#include <linux/platform_device.h>
+/*
+ * struct sdhci_plat_data: spear sdhci platform data structure
+ *
+ * @card_power_gpio: gpio pin for enabling/disabling power to sdhci socket
+ * @power_active_high: if set, enable power to sdhci socket by setting
+ *                     card_power_gpio
+ * @power_always_enb: If set, then enable power on probe, otherwise enable only
+ *                     on card insertion and disable on card removal.
+ * card_int_gpio: gpio pin used for card detection
+ */
+struct sdhci_plat_data {
+       int card_power_gpio;
+       int power_active_high;
+       int power_always_enb;
+       int card_int_gpio;
+};
+
+/* This function is used to set platform_data field of pdev->dev */
+static inline void
+sdhci_set_plat_data(struct platform_device *pdev, struct sdhci_plat_data *data)
+{
+       pdev->dev.platform_data = data;
+}
+
+#endif /* MMC_SDHCI_SPEAR_H */
index c6c0cceba5fe735a0719cdfc615a6cf89171b186..31baaf82f4583a06d5144ef0b304d5ecbc907563 100644 (file)
@@ -145,6 +145,9 @@ extern void sdio_writew(struct sdio_func *func, u16 b,
 extern void sdio_writel(struct sdio_func *func, u32 b,
        unsigned int addr, int *err_ret);
 
+extern u8 sdio_writeb_readb(struct sdio_func *func, u8 write_byte,
+       unsigned int addr, int *err_ret);
+
 extern int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr,
        void *src, int count);
 extern int sdio_writesb(struct sdio_func *func, unsigned int addr,
diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h
new file mode 100644 (file)
index 0000000..aafe832
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * include/linux/mmc/sh_mmcif.h
+ *
+ * platform data for eMMC driver
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ */
+
+#ifndef __SH_MMCIF_H__
+#define __SH_MMCIF_H__
+
+/*
+ * MMCIF : CE_CLK_CTRL [19:16]
+ * 1000 : Peripheral clock / 512
+ * 0111 : Peripheral clock / 256
+ * 0110 : Peripheral clock / 128
+ * 0101 : Peripheral clock / 64
+ * 0100 : Peripheral clock / 32
+ * 0011 : Peripheral clock / 16
+ * 0010 : Peripheral clock / 8
+ * 0001 : Peripheral clock / 4
+ * 0000 : Peripheral clock / 2
+ * 1111 : Peripheral clock (sup_pclk set '1')
+ */
+
+struct sh_mmcif_plat_data {
+       void (*set_pwr)(struct platform_device *pdev, int state);
+       void (*down_pwr)(struct platform_device *pdev);
+       u8      sup_pclk;       /* 1 :SH7757, 0: SH7724/SH7372 */
+       unsigned long caps;
+       u32     ocr;
+};
+
+#endif /* __SH_MMCIF_H__ */
index 0fa491326c4a165eceeef43f24c0f30ac3834832..b4d109e389b806f205aa1575135001e09a864bf5 100644 (file)
@@ -671,6 +671,12 @@ void memory_present(int nid, unsigned long start, unsigned long end);
 static inline void memory_present(int nid, unsigned long start, unsigned long end) {}
 #endif
 
+#ifdef CONFIG_HAVE_MEMORYLESS_NODES
+int local_memory_node(int node_id);
+#else
+static inline int local_memory_node(int node_id) { return node_id; };
+#endif
+
 #ifdef CONFIG_NEED_NODE_MEMMAP_SIZE
 unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long);
 #endif
index dba35e413371e599045d41134003a1ef8713fd38..8a8f1d09c1336dce6076335b5a181c5bfc131120 100644 (file)
@@ -66,6 +66,8 @@
  * int num_online_nodes()              Number of online Nodes
  * int num_possible_nodes()            Number of all possible Nodes
  *
+ * int node_random(mask)               Random node with set bit in mask
+ *
  * int node_online(node)               Is some node online?
  * int node_possible(node)             Is some node possible?
  *
@@ -430,6 +432,10 @@ static inline void node_set_offline(int nid)
        node_clear_state(nid, N_ONLINE);
        nr_online_nodes = num_node_state(N_ONLINE);
 }
+
+#define node_random(mask) __node_random(&(mask))
+extern int __node_random(const nodemask_t *maskp);
+
 #else
 
 static inline int node_state(int node, enum node_states state)
@@ -460,6 +466,8 @@ static inline int num_node_state(enum node_states state)
 
 #define node_set_online(node)     node_set_state((node), N_ONLINE)
 #define node_set_offline(node)    node_clear_state((node), N_ONLINE)
+
+static inline int node_random(const nodemask_t mask) { return 0; }
 #endif
 
 #define node_online_map        node_states[N_ONLINE]
index 7c36096223340a1d674b253430e5128b71f7abaa..540703b555cb2be4bbea2d8e7f0b84d96ca3b474 100644 (file)
@@ -164,7 +164,10 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
 /* Encapsulate (negative) errno value (in particular, NOTIFY_BAD <=> EPERM). */
 static inline int notifier_from_errno(int err)
 {
-       return NOTIFY_STOP_MASK | (NOTIFY_OK - err);
+       if (err)
+               return NOTIFY_STOP_MASK | (NOTIFY_OK - err);
+
+       return NOTIFY_OK;
 }
 
 /* Restore (negative) errno value from notify return value. */
index aef22ae2af473f4113bf19560d1b441395a458da..5bb13b3db84d46ee155784a26acfd850e94c91ff 100644 (file)
@@ -40,6 +40,7 @@ enum {
        PCG_USED, /* this object is in use. */
        PCG_ACCT_LRU, /* page has been accounted for */
        PCG_FILE_MAPPED, /* page is accounted as "mapped" */
+       PCG_MIGRATION, /* under page migration */
 };
 
 #define TESTPCGFLAG(uname, lname)                      \
@@ -79,6 +80,10 @@ SETPCGFLAG(FileMapped, FILE_MAPPED)
 CLEARPCGFLAG(FileMapped, FILE_MAPPED)
 TESTPCGFLAG(FileMapped, FILE_MAPPED)
 
+SETPCGFLAG(Migration, MIGRATION)
+CLEARPCGFLAG(Migration, MIGRATION)
+TESTPCGFLAG(Migration, MIGRATION)
+
 static inline int page_cgroup_nid(struct page_cgroup *pc)
 {
        return page_to_nid(pc->page);
index 25d02fe5c9b5a6561e19bd3410a4132ea98dffd8..fb7ab9de5f360878805779e489d1d35a2f205fa0 100644 (file)
@@ -40,6 +40,10 @@ struct rand_pool_info {
        __u32   buf[0];
 };
 
+struct rnd_state {
+       __u32 s1, s2, s3;
+};
+
 /* Exported functions */
 
 #ifdef __KERNEL__
@@ -74,6 +78,30 @@ unsigned long randomize_range(unsigned long start, unsigned long end, unsigned l
 u32 random32(void);
 void srandom32(u32 seed);
 
+u32 prandom32(struct rnd_state *);
+
+/*
+ * Handle minimum values for seeds
+ */
+static inline u32 __seed(u32 x, u32 m)
+{
+       return (x < m) ? x + m : x;
+}
+
+/**
+ * prandom32_seed - set seed for prandom32().
+ * @state: pointer to state structure to receive the seed.
+ * @seed: arbitrary 64-bit value to use as a seed.
+ */
+static inline void prandom32_seed(struct rnd_state *state, u64 seed)
+{
+       u32 i = (seed >> 32) ^ (seed << 10) ^ seed;
+
+       state->s1 = __seed(i, 1);
+       state->s2 = __seed(i, 7);
+       state->s3 = __seed(i, 15);
+}
+
 #endif /* __KERNEL___ */
 
 #endif /* _LINUX_RANDOM_H */
index dc0c75556c63c763da2f29e1173606b0502ae78b..19b5f227096ecb3465126398f65ab364724efe37 100644 (file)
 #define RIO_INB_MBOX_RESOURCE  1
 #define RIO_OUTB_MBOX_RESOURCE 2
 
+#define RIO_PW_MSG_SIZE                64
+
 extern struct bus_type rio_bus_type;
 extern struct list_head rio_devices;   /* list of all devices */
 
 struct rio_mport;
+union rio_pw_msg;
 
 /**
  * struct rio_dev - RIO device info
@@ -107,11 +110,15 @@ struct rio_dev {
        u32 swpinfo;            /* Only used for switches */
        u32 src_ops;
        u32 dst_ops;
+       u32 comp_tag;
+       u32 phys_efptr;
+       u32 em_efptr;
        u64 dma_mask;
        struct rio_switch *rswitch;     /* RIO switch info */
        struct rio_driver *driver;      /* RIO driver claiming this device */
        struct device dev;      /* LDM device structure */
        struct resource riores[RIO_MAX_DEV_RESOURCES];
+       int (*pwcback) (struct rio_dev *rdev, union rio_pw_msg *msg, int step);
        u16 destid;
 };
 
@@ -211,8 +218,12 @@ struct rio_net {
  * @hopcount: Hopcount to this switch
  * @destid: Associated destid in the path
  * @route_table: Copy of switch routing table
+ * @port_ok: Status of each port (one bit per port) - OK=1 or UNINIT=0
  * @add_entry: Callback for switch-specific route add function
  * @get_entry: Callback for switch-specific route get function
+ * @clr_table: Callback for switch-specific clear route table function
+ * @em_init: Callback for switch-specific error management initialization function
+ * @em_handle: Callback for switch-specific error management handler function
  */
 struct rio_switch {
        struct list_head node;
@@ -220,10 +231,19 @@ struct rio_switch {
        u16 hopcount;
        u16 destid;
        u8 *route_table;
+       u32 port_ok;
        int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
                          u16 table, u16 route_destid, u8 route_port);
        int (*get_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
                          u16 table, u16 route_destid, u8 * route_port);
+       int (*clr_table) (struct rio_mport *mport, u16 destid, u8 hopcount,
+                         u16 table);
+       int (*set_domain) (struct rio_mport *mport, u16 destid, u8 hopcount,
+                          u8 sw_domain);
+       int (*get_domain) (struct rio_mport *mport, u16 destid, u8 hopcount,
+                          u8 *sw_domain);
+       int (*em_init) (struct rio_dev *dev);
+       int (*em_handle) (struct rio_dev *dev, u8 swport);
 };
 
 /* Low-level architecture-dependent routines */
@@ -235,6 +255,7 @@ struct rio_switch {
  * @cread: Callback to perform network read of config space.
  * @cwrite: Callback to perform network write of config space.
  * @dsend: Callback to send a doorbell message.
+ * @pwenable: Callback to enable/disable port-write message handling.
  */
 struct rio_ops {
        int (*lcread) (struct rio_mport *mport, int index, u32 offset, int len,
@@ -246,6 +267,7 @@ struct rio_ops {
        int (*cwrite) (struct rio_mport *mport, int index, u16 destid,
                        u8 hopcount, u32 offset, int len, u32 data);
        int (*dsend) (struct rio_mport *mport, int index, u16 destid, u16 data);
+       int (*pwenable) (struct rio_mport *mport, int enable);
 };
 
 #define RIO_RESOURCE_MEM       0x00000100
@@ -302,21 +324,28 @@ struct rio_device_id {
 };
 
 /**
- * struct rio_route_ops - Per-switch route operations
+ * struct rio_switch_ops - Per-switch operations
  * @vid: RIO vendor ID
  * @did: RIO device ID
- * @add_hook: Callback that adds a route entry
- * @get_hook: Callback that gets a route entry
+ * @init_hook: Callback that performs switch device initialization
  *
- * Defines the operations that are necessary to manipulate the route
- * tables for a particular RIO switch device.
+ * Defines the operations that are necessary to initialize/control
+ * a particular RIO switch device.
  */
-struct rio_route_ops {
+struct rio_switch_ops {
        u16 vid, did;
-       int (*add_hook) (struct rio_mport * mport, u16 destid, u8 hopcount,
-                        u16 table, u16 route_destid, u8 route_port);
-       int (*get_hook) (struct rio_mport * mport, u16 destid, u8 hopcount,
-                        u16 table, u16 route_destid, u8 * route_port);
+       int (*init_hook) (struct rio_dev *rdev, int do_enum);
+};
+
+union rio_pw_msg {
+       struct {
+               u32 comptag;    /* Component Tag CSR */
+               u32 errdetect;  /* Port N Error Detect CSR */
+               u32 is_port;    /* Implementation specific + PortID */
+               u32 ltlerrdet;  /* LTL Error Detect CSR */
+               u32 padding[12];
+       } em;
+       u32 raw[RIO_PW_MSG_SIZE/sizeof(u32)];
 };
 
 /* Architecture and hardware-specific functions */
index c93a58a4003324bf6d147836d0c6a1ccaac350e5..edc55da717b30e13ae712ea4ec7ca5a1220d5fa3 100644 (file)
@@ -413,6 +413,12 @@ void rio_release_regions(struct rio_dev *);
 int rio_request_region(struct rio_dev *, int, char *);
 void rio_release_region(struct rio_dev *, int);
 
+/* Port-Write management */
+extern int rio_request_inb_pwrite(struct rio_dev *,
+                       int (*)(struct rio_dev *, union rio_pw_msg*, int));
+extern int rio_release_inb_pwrite(struct rio_dev *);
+extern int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg);
+
 /* LDM support */
 int rio_register_driver(struct rio_driver *);
 void rio_unregister_driver(struct rio_driver *);
index 919d4e07d54e5c528369bb399d8c57e064f9dbbc..db50e1c288b7b48be7e3bbd6fad70b934f42e588 100644 (file)
 
 #define RIO_VID_TUNDRA                 0x000d
 #define RIO_DID_TSI500                 0x0500
+#define RIO_DID_TSI568                 0x0568
+#define RIO_DID_TSI572                 0x0572
+#define RIO_DID_TSI574                 0x0574
+#define RIO_DID_TSI576                 0x0578 /* Same ID as Tsi578 */
+#define RIO_DID_TSI577                 0x0577
+#define RIO_DID_TSI578                 0x0578
+
+#define RIO_VID_IDT                    0x0038
+#define RIO_DID_IDT70K200              0x0310
+#define RIO_DID_IDTCPS8                        0x035c
+#define RIO_DID_IDTCPS12               0x035d
+#define RIO_DID_IDTCPS16               0x035b
+#define RIO_DID_IDTCPS6Q               0x035f
+#define RIO_DID_IDTCPS10Q              0x035e
 
 #endif                         /* LINUX_RIO_IDS_H */
index 326540f9b54e4c4ad253acbbd932eb663c0e6012..aedee0489fb41991b8b018b57a449a867b039434 100644 (file)
@@ -39,6 +39,8 @@
 #define  RIO_PEF_INB_MBOX2             0x00200000      /* [II] Mailbox 2 */
 #define  RIO_PEF_INB_MBOX3             0x00100000      /* [II] Mailbox 3 */
 #define  RIO_PEF_INB_DOORBELL          0x00080000      /* [II] Doorbells */
+#define  RIO_PEF_EXT_RT                        0x00000200      /* [III, 1.3] Extended route table support */
+#define  RIO_PEF_STD_RT                        0x00000100      /* [III, 1.3] Standard route table support */
 #define  RIO_PEF_CTLS                  0x00000010      /* [III] CTLS */
 #define  RIO_PEF_EXT_FEATURES          0x00000008      /* [I] EFT_PTR valid */
 #define  RIO_PEF_ADDR_66               0x00000004      /* [I] 66 bits */
 #define  RIO_OPS_ATOMIC_CLR            0x00000010      /* [I] Atomic clr op */
 #define  RIO_OPS_PORT_WRITE            0x00000004      /* [I] Port-write op */
 
-                                       /* 0x20-0x3c *//* Reserved */
+                                       /* 0x20-0x30 *//* Reserved */
+
+#define        RIO_SWITCH_RT_LIMIT     0x34    /* [III, 1.3] Switch Route Table Destination ID Limit CAR */
+#define         RIO_RT_MAX_DESTID              0x0000ffff
 
 #define RIO_MBOX_CSR           0x40    /* [II] Mailbox CSR */
 #define  RIO_MBOX0_AVAIL               0x80000000      /* [II] Mbox 0 avail */
 #define RIO_HOST_DID_LOCK_CSR  0x68    /* [III] Host Base Device ID Lock CSR */
 #define RIO_COMPONENT_TAG_CSR  0x6c    /* [III] Component Tag CSR */
 
-                                       /* 0x70-0xf8 *//* Reserved */
+#define RIO_STD_RTE_CONF_DESTID_SEL_CSR        0x70
+#define RIO_STD_RTE_CONF_PORT_SEL_CSR  0x74
+#define RIO_STD_RTE_DEFAULT_PORT       0x78
+
+                                       /* 0x7c-0xf8 *//* Reserved */
                                        /* 0x100-0xfff8 *//* [I] Extended Features Space */
                                        /* 0x10000-0xfffff8 *//* [I] Implementation-defined Space */
 
 #define RIO_EFB_PAR_EP_ID      0x0001  /* [IV] LP/LVDS EP Devices */
 #define RIO_EFB_PAR_EP_REC_ID  0x0002  /* [IV] LP/LVDS EP Recovery Devices */
 #define RIO_EFB_PAR_EP_FREE_ID 0x0003  /* [IV] LP/LVDS EP Free Devices */
+#define RIO_EFB_SER_EP_ID_V13P 0x0001  /* [VI] LP/Serial EP Devices, RapidIO Spec ver 1.3 and above */
+#define RIO_EFB_SER_EP_REC_ID_V13P     0x0002  /* [VI] LP/Serial EP Recovery Devices, RapidIO Spec ver 1.3 and above */
+#define RIO_EFB_SER_EP_FREE_ID_V13P    0x0003  /* [VI] LP/Serial EP Free Devices, RapidIO Spec ver 1.3 and above */
 #define RIO_EFB_SER_EP_ID      0x0004  /* [VI] LP/Serial EP Devices */
 #define RIO_EFB_SER_EP_REC_ID  0x0005  /* [VI] LP/Serial EP Recovery Devices */
 #define RIO_EFB_SER_EP_FREE_ID 0x0006  /* [VI] LP/Serial EP Free Devices */
+#define RIO_EFB_SER_EP_FREC_ID 0x0009  /* [VI] LP/Serial EP Free Recovery Devices */
+#define RIO_EFB_ERR_MGMNT      0x0007  /* [VIII] Error Management Extensions */
 
 /*
  * Physical 8/16 LP-LVDS
 #define RIO_PORT_MNT_HEADER            0x0000
 #define RIO_PORT_REQ_CTL_CSR           0x0020
 #define RIO_PORT_RSP_CTL_CSR           0x0024  /* 0x0001/0x0002 */
+#define RIO_PORT_LINKTO_CTL_CSR                0x0020  /* Serial */
+#define RIO_PORT_RSPTO_CTL_CSR         0x0024  /* Serial */
 #define RIO_PORT_GEN_CTL_CSR           0x003c
 #define  RIO_PORT_GEN_HOST             0x80000000
 #define  RIO_PORT_GEN_MASTER           0x40000000
 #define  RIO_PORT_GEN_DISCOVERED       0x20000000
 #define RIO_PORT_N_MNT_REQ_CSR(x)      (0x0040 + x*0x20)       /* 0x0002 */
 #define RIO_PORT_N_MNT_RSP_CSR(x)      (0x0044 + x*0x20)       /* 0x0002 */
+#define  RIO_PORT_N_MNT_RSP_RVAL       0x80000000 /* Response Valid */
+#define  RIO_PORT_N_MNT_RSP_ASTAT      0x000003e0 /* ackID Status */
+#define  RIO_PORT_N_MNT_RSP_LSTAT      0x0000001f /* Link Status */
 #define RIO_PORT_N_ACK_STS_CSR(x)      (0x0048 + x*0x20)       /* 0x0002 */
-#define RIO_PORT_N_ERR_STS_CSR(x)      (0x58 + x*0x20)
-#define PORT_N_ERR_STS_PORT_OK 0x00000002
-#define RIO_PORT_N_CTL_CSR(x)          (0x5c + x*0x20)
+#define  RIO_PORT_N_ACK_CLEAR          0x80000000
+#define  RIO_PORT_N_ACK_INBOUND                0x1f000000
+#define  RIO_PORT_N_ACK_OUTSTAND       0x00001f00
+#define  RIO_PORT_N_ACK_OUTBOUND       0x0000001f
+#define RIO_PORT_N_ERR_STS_CSR(x)      (0x0058 + x*0x20)
+#define  RIO_PORT_N_ERR_STS_PW_OUT_ES  0x00010000 /* Output Error-stopped */
+#define  RIO_PORT_N_ERR_STS_PW_INP_ES  0x00000100 /* Input Error-stopped */
+#define  RIO_PORT_N_ERR_STS_PW_PEND    0x00000010 /* Port-Write Pending */
+#define  RIO_PORT_N_ERR_STS_PORT_ERR   0x00000004
+#define  RIO_PORT_N_ERR_STS_PORT_OK    0x00000002
+#define  RIO_PORT_N_ERR_STS_PORT_UNINIT        0x00000001
+#define  RIO_PORT_N_ERR_STS_CLR_MASK   0x07120204
+#define RIO_PORT_N_CTL_CSR(x)          (0x005c + x*0x20)
+#define  RIO_PORT_N_CTL_PWIDTH         0xc0000000
+#define  RIO_PORT_N_CTL_PWIDTH_1       0x00000000
+#define  RIO_PORT_N_CTL_PWIDTH_4       0x40000000
+#define  RIO_PORT_N_CTL_P_TYP_SER      0x00000001
+#define  RIO_PORT_N_CTL_LOCKOUT                0x00000002
+#define  RIO_PORT_N_CTL_EN_RX_SER      0x00200000
+#define  RIO_PORT_N_CTL_EN_TX_SER      0x00400000
+#define  RIO_PORT_N_CTL_EN_RX_PAR      0x08000000
+#define  RIO_PORT_N_CTL_EN_TX_PAR      0x40000000
+
+/*
+ * Error Management Extensions (RapidIO 1.3+, Part 8)
+ *
+ * Extended Features Block ID=0x0007
+ */
+
+/* General EM Registers (Common for all Ports) */
+
+#define RIO_EM_EFB_HEADER      0x000   /* Error Management Extensions Block Header */
+#define RIO_EM_LTL_ERR_DETECT  0x008   /* Logical/Transport Layer Error Detect CSR */
+#define RIO_EM_LTL_ERR_EN      0x00c   /* Logical/Transport Layer Error Enable CSR */
+#define RIO_EM_LTL_HIADDR_CAP  0x010   /* Logical/Transport Layer High Address Capture CSR */
+#define RIO_EM_LTL_ADDR_CAP    0x014   /* Logical/Transport Layer Address Capture CSR */
+#define RIO_EM_LTL_DEVID_CAP   0x018   /* Logical/Transport Layer Device ID Capture CSR */
+#define RIO_EM_LTL_CTRL_CAP    0x01c   /* Logical/Transport Layer Control Capture CSR */
+#define RIO_EM_PW_TGT_DEVID    0x028   /* Port-write Target deviceID CSR */
+#define RIO_EM_PKT_TTL         0x02c   /* Packet Time-to-live CSR */
+
+/* Per-Port EM Registers */
+
+#define RIO_EM_PN_ERR_DETECT(x)        (0x040 + x*0x40) /* Port N Error Detect CSR */
+#define  REM_PED_IMPL_SPEC             0x80000000
+#define  REM_PED_LINK_TO               0x00000001
+#define RIO_EM_PN_ERRRATE_EN(x) (0x044 + x*0x40) /* Port N Error Rate Enable CSR */
+#define RIO_EM_PN_ATTRIB_CAP(x)        (0x048 + x*0x40) /* Port N Attributes Capture CSR */
+#define RIO_EM_PN_PKT_CAP_0(x) (0x04c + x*0x40) /* Port N Packet/Control Symbol Capture 0 CSR */
+#define RIO_EM_PN_PKT_CAP_1(x) (0x050 + x*0x40) /* Port N Packet Capture 1 CSR */
+#define RIO_EM_PN_PKT_CAP_2(x) (0x054 + x*0x40) /* Port N Packet Capture 2 CSR */
+#define RIO_EM_PN_PKT_CAP_3(x) (0x058 + x*0x40) /* Port N Packet Capture 3 CSR */
+#define RIO_EM_PN_ERRRATE(x)   (0x068 + x*0x40) /* Port N Error Rate CSR */
+#define RIO_EM_PN_ERRRATE_TR(x) (0x06c + x*0x40) /* Port N Error Rate Threshold CSR */
 
 #endif                         /* LINUX_RIO_REGS_H */
index c0151ffd35419652b5c70f16c27978a62bea0b32..f118809c953ff137b2a97e0d9e674b2836ee331a 100644 (file)
@@ -268,7 +268,6 @@ extern void init_idle(struct task_struct *idle, int cpu);
 extern void init_idle_bootup_task(struct task_struct *idle);
 
 extern int runqueue_is_locked(int cpu);
-extern void task_rq_unlock_wait(struct task_struct *p);
 
 extern cpumask_var_t nohz_cpu_mask;
 #if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ)
@@ -527,8 +526,9 @@ struct thread_group_cputimer {
  * the locking of signal_struct.
  */
 struct signal_struct {
-       atomic_t                count;
+       atomic_t                sigcnt;
        atomic_t                live;
+       int                     nr_threads;
 
        wait_queue_head_t       wait_chldexit;  /* for wait4() */
 
@@ -1423,6 +1423,7 @@ struct task_struct {
        nodemask_t mems_allowed;        /* Protected by alloc_lock */
        int mems_allowed_change_disable;
        int cpuset_mem_spread_rotor;
+       int cpuset_slab_spread_rotor;
 #endif
 #ifdef CONFIG_CGROUPS
        /* Control Group info protected by css_set_lock */
@@ -2035,7 +2036,7 @@ extern int do_notify_parent(struct task_struct *, int);
 extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent);
 extern void force_sig(int, struct task_struct *);
 extern int send_sig(int, struct task_struct *, int);
-extern void zap_other_threads(struct task_struct *p);
+extern int zap_other_threads(struct task_struct *p);
 extern struct sigqueue *sigqueue_alloc(void);
 extern void sigqueue_free(struct sigqueue *);
 extern int send_sigqueue(struct sigqueue *,  struct task_struct *, int group);
@@ -2100,7 +2101,6 @@ extern void flush_thread(void);
 extern void exit_thread(void);
 
 extern void exit_files(struct task_struct *);
-extern void __cleanup_signal(struct signal_struct *);
 extern void __cleanup_sighand(struct sighand_struct *);
 
 extern void exit_itimers(struct signal_struct *);
@@ -2147,6 +2147,11 @@ extern bool current_is_single_threaded(void);
 #define while_each_thread(g, t) \
        while ((t = next_thread(t)) != g)
 
+static inline int get_nr_threads(struct task_struct *tsk)
+{
+       return tsk->signal->nr_threads;
+}
+
 /* de_thread depends on thread_group_leader not being a pid based check */
 #define thread_group_leader(p) (p == p->group_leader)
 
@@ -2393,10 +2398,6 @@ static inline void thread_group_cputime_init(struct signal_struct *sig)
        spin_lock_init(&sig->cputimer.lock);
 }
 
-static inline void thread_group_cputime_free(struct signal_struct *sig)
-{
-}
-
 /*
  * Reevaluate whether the task has signals pending delivery.
  * Wake the task if so.
diff --git a/include/linux/sdhci-pltfm.h b/include/linux/sdhci-pltfm.h
new file mode 100644 (file)
index 0000000..0239bd7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Platform data declarations for the sdhci-pltfm driver.
+ *
+ * Copyright (c) 2010 MontaVista Software, LLC.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef _SDHCI_PLTFM_H
+#define _SDHCI_PLTFM_H
+
+struct sdhci_ops;
+struct sdhci_host;
+
+/**
+ * struct sdhci_pltfm_data - SDHCI platform-specific information & hooks
+ * @ops: optional pointer to the platform-provided SDHCI ops
+ * @quirks: optional SDHCI quirks
+ * @init: optional hook that is called during device probe, before the
+ *        driver tries to access any SDHCI registers
+ * @exit: optional hook that is called during device removal
+ */
+struct sdhci_pltfm_data {
+       struct sdhci_ops *ops;
+       unsigned int quirks;
+       int (*init)(struct sdhci_host *host);
+       void (*exit)(struct sdhci_host *host);
+};
+
+#endif /* _SDHCI_PLTFM_H */
index 8a4adbef8a0fd65b13964b780418b6d7dd84c154..f2961afa2f6657e9bbf9c79cd25b0d2c2648d86d 100644 (file)
@@ -79,6 +79,7 @@ struct  seminfo {
 #ifdef __KERNEL__
 #include <asm/atomic.h>
 #include <linux/rcupdate.h>
+#include <linux/cache.h>
 
 struct task_struct;
 
@@ -91,7 +92,8 @@ struct sem {
 
 /* One sem_array data structure for each set of semaphores in the system. */
 struct sem_array {
-       struct kern_ipc_perm    sem_perm;       /* permissions .. see ipc.h */
+       struct kern_ipc_perm    ____cacheline_aligned_in_smp
+                               sem_perm;       /* permissions .. see ipc.h */
        time_t                  sem_otime;      /* last semop time */
        time_t                  sem_ctime;      /* last change time */
        struct sem              *sem_base;      /* ptr to first semaphore in array */
index b6b614364dd8a4d450bee893b78c0b9c77b1a949..ff4acea9bbdb075e866d12770072e377d280d3ef 100644 (file)
@@ -282,6 +282,11 @@ extern void kswapd_stop(int nid);
 extern int shmem_unuse(swp_entry_t entry, struct page *page);
 #endif /* CONFIG_MMU */
 
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR
+extern void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff,
+                                       struct page **pagep, swp_entry_t *ent);
+#endif
+
 extern void swap_unplug_io_fn(struct backing_dev_info *, struct page *);
 
 #ifdef CONFIG_SWAP
index febedcf67c7ec38464add407881e0351f6352ca5..81a4e213c6cf9bd934792d0135836cc9ef8d4d36 100644 (file)
@@ -73,16 +73,6 @@ extern void
 swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
                           int nelems, enum dma_data_direction dir);
 
-extern void
-swiotlb_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
-                                 unsigned long offset, size_t size,
-                                 enum dma_data_direction dir);
-
-extern void
-swiotlb_sync_single_range_for_device(struct device *hwdev, dma_addr_t dev_addr,
-                                    unsigned long offset, size_t size,
-                                    enum dma_data_direction dir);
-
 extern int
 swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr);
 
index 052b12bec8bdabf7a4c8b7af652eb83550c01a93..383ab9592becae78187d8be345e397a6c816765e 100644 (file)
 #define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \
        (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))
 
+/*
+ * Define a minimum number of pids per cpu.  Heuristically based
+ * on original pid max of 32k for 32 cpus.  Also, increase the
+ * minimum settable value for pid_max on the running system based
+ * on similar defaults.  See kernel/pid.c:pidmap_init() for details.
+ */
+#define PIDS_PER_CPU_DEFAULT   1024
+#define PIDS_PER_CPU_MIN       8
+
 #endif
index 5b81156780b17f8bf52608ca7b8230dd638a530a..c44df50a05ab5a81e42b1a37299fb9e790298fc3 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/bitops.h>
 #include <linux/mmzone.h>
 #include <linux/smp.h>
+#include <linux/percpu.h>
 #include <asm/topology.h>
 
 #ifndef node_has_online_mem
@@ -203,8 +204,114 @@ int arch_update_cpu_topology(void);
 #ifndef SD_NODE_INIT
 #error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!!
 #endif
+
 #endif /* CONFIG_NUMA */
 
+#ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID
+DECLARE_PER_CPU(int, numa_node);
+
+#ifndef numa_node_id
+/* Returns the number of the current Node. */
+static inline int numa_node_id(void)
+{
+       return __this_cpu_read(numa_node);
+}
+#endif
+
+#ifndef cpu_to_node
+static inline int cpu_to_node(int cpu)
+{
+       return per_cpu(numa_node, cpu);
+}
+#endif
+
+#ifndef set_numa_node
+static inline void set_numa_node(int node)
+{
+       percpu_write(numa_node, node);
+}
+#endif
+
+#ifndef set_cpu_numa_node
+static inline void set_cpu_numa_node(int cpu, int node)
+{
+       per_cpu(numa_node, cpu) = node;
+}
+#endif
+
+#else  /* !CONFIG_USE_PERCPU_NUMA_NODE_ID */
+
+/* Returns the number of the current Node. */
+#ifndef numa_node_id
+static inline int numa_node_id(void)
+{
+       return cpu_to_node(raw_smp_processor_id());
+}
+#endif
+
+#endif /* [!]CONFIG_USE_PERCPU_NUMA_NODE_ID */
+
+#ifdef CONFIG_HAVE_MEMORYLESS_NODES
+
+/*
+ * N.B., Do NOT reference the '_numa_mem_' per cpu variable directly.
+ * It will not be defined when CONFIG_HAVE_MEMORYLESS_NODES is not defined.
+ * Use the accessor functions set_numa_mem(), numa_mem_id() and cpu_to_mem().
+ */
+DECLARE_PER_CPU(int, _numa_mem_);
+
+#ifndef set_numa_mem
+static inline void set_numa_mem(int node)
+{
+       percpu_write(_numa_mem_, node);
+}
+#endif
+
+#ifndef numa_mem_id
+/* Returns the number of the nearest Node with memory */
+static inline int numa_mem_id(void)
+{
+       return __this_cpu_read(_numa_mem_);
+}
+#endif
+
+#ifndef cpu_to_mem
+static inline int cpu_to_mem(int cpu)
+{
+       return per_cpu(_numa_mem_, cpu);
+}
+#endif
+
+#ifndef set_cpu_numa_mem
+static inline void set_cpu_numa_mem(int cpu, int node)
+{
+       per_cpu(_numa_mem_, cpu) = node;
+}
+#endif
+
+#else  /* !CONFIG_HAVE_MEMORYLESS_NODES */
+
+static inline void set_numa_mem(int node) {}
+
+static inline void set_cpu_numa_mem(int cpu, int node) {}
+
+#ifndef numa_mem_id
+/* Returns the number of the nearest Node with memory */
+static inline int numa_mem_id(void)
+{
+       return numa_node_id();
+}
+#endif
+
+#ifndef cpu_to_mem
+static inline int cpu_to_mem(int cpu)
+{
+       return cpu_to_node(cpu);
+}
+#endif
+
+#endif /* [!]CONFIG_HAVE_MEMORYLESS_NODES */
+
 #ifndef topology_physical_package_id
 #define topology_physical_package_id(cpu)      ((void)(cpu), -1)
 #endif
@@ -218,9 +325,4 @@ int arch_update_cpu_topology(void);
 #define topology_core_cpumask(cpu)             cpumask_of(cpu)
 #endif
 
-/* Returns the number of the current Node. */
-#ifndef numa_node_id
-#define numa_node_id()         (cpu_to_node(raw_smp_processor_id()))
-#endif
-
 #endif /* _LINUX_TOPOLOGY_H */
index 15ddd4483b09b9b94b47a9130bc0579c31468c74..60c81da77f0f36b94bde7d83562db55dfa707d92 100644 (file)
@@ -166,11 +166,11 @@ struct uinput_ff_erase {
 struct uinput_user_dev {
        char name[UINPUT_MAX_NAME_SIZE];
        struct input_id id;
-        int ff_effects_max;
-        int absmax[ABS_MAX + 1];
-        int absmin[ABS_MAX + 1];
-        int absfuzz[ABS_MAX + 1];
-        int absflat[ABS_MAX + 1];
+       int ff_effects_max;
+       int absmax[ABS_CNT];
+       int absmin[ABS_CNT];
+       int absfuzz[ABS_CNT];
+       int absflat[ABS_CNT];
 };
 #endif /* __UINPUT_H_ */
 
index dbef95b1594122c2a6276d504d206805d39879f7..506c8491a8d131761432aa306e51eef441863887 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -3,56 +3,6 @@
  * Copyright (C) 1992 Krishna Balasubramanian
  * Copyright (C) 1995 Eric Schenk, Bruno Haible
  *
- * IMPLEMENTATION NOTES ON CODE REWRITE (Eric Schenk, January 1995):
- * This code underwent a massive rewrite in order to solve some problems
- * with the original code. In particular the original code failed to
- * wake up processes that were waiting for semval to go to 0 if the
- * value went to 0 and was then incremented rapidly enough. In solving
- * this problem I have also modified the implementation so that it
- * processes pending operations in a FIFO manner, thus give a guarantee
- * that processes waiting for a lock on the semaphore won't starve
- * unless another locking process fails to unlock.
- * In addition the following two changes in behavior have been introduced:
- * - The original implementation of semop returned the value
- *   last semaphore element examined on success. This does not
- *   match the manual page specifications, and effectively
- *   allows the user to read the semaphore even if they do not
- *   have read permissions. The implementation now returns 0
- *   on success as stated in the manual page.
- * - There is some confusion over whether the set of undo adjustments
- *   to be performed at exit should be done in an atomic manner.
- *   That is, if we are attempting to decrement the semval should we queue
- *   up and wait until we can do so legally?
- *   The original implementation attempted to do this.
- *   The current implementation does not do so. This is because I don't
- *   think it is the right thing (TM) to do, and because I couldn't
- *   see a clean way to get the old behavior with the new design.
- *   The POSIX standard and SVID should be consulted to determine
- *   what behavior is mandated.
- *
- * Further notes on refinement (Christoph Rohland, December 1998):
- * - The POSIX standard says, that the undo adjustments simply should
- *   redo. So the current implementation is o.K.
- * - The previous code had two flaws:
- *   1) It actively gave the semaphore to the next waiting process
- *      sleeping on the semaphore. Since this process did not have the
- *      cpu this led to many unnecessary context switches and bad
- *      performance. Now we only check which process should be able to
- *      get the semaphore and if this process wants to reduce some
- *      semaphore value we simply wake it up without doing the
- *      operation. So it has to try to get it later. Thus e.g. the
- *      running process may reacquire the semaphore during the current
- *      time slice. If it only waits for zero or increases the semaphore,
- *      we do the operation in advance and wake it up.
- *   2) It did not wake up all zero waiting processes. We try to do
- *      better but only get the semops right which only wait for zero or
- *      increase. If there are decrement operations in the operations
- *      array we do the same as before.
- *
- * With the incarnation of O(1) scheduler, it becomes unnecessary to perform
- * check/retry algorithm for waking up blocked processes as the new scheduler
- * is better at handling thread switch than the old one.
- *
  * /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
  *
  * SMP-threaded, sysctl's added
@@ -61,6 +11,8 @@
  * (c) 2001 Red Hat Inc
  * Lockless wakeup
  * (c) 2003 Manfred Spraul <manfred@colorfullife.com>
+ * Further wakeup optimizations, documentation
+ * (c) 2010 Manfred Spraul <manfred@colorfullife.com>
  *
  * support for audit of ipc object properties and permission changes
  * Dustin Kirkland <dustin.kirkland@us.ibm.com>
  * namespaces support
  * OpenVZ, SWsoft Inc.
  * Pavel Emelianov <xemul@openvz.org>
+ *
+ * Implementation notes: (May 2010)
+ * This file implements System V semaphores.
+ *
+ * User space visible behavior:
+ * - FIFO ordering for semop() operations (just FIFO, not starvation
+ *   protection)
+ * - multiple semaphore operations that alter the same semaphore in
+ *   one semop() are handled.
+ * - sem_ctime (time of last semctl()) is updated in the IPC_SET, SETVAL and
+ *   SETALL calls.
+ * - two Linux specific semctl() commands: SEM_STAT, SEM_INFO.
+ * - undo adjustments at process exit are limited to 0..SEMVMX.
+ * - namespace are supported.
+ * - SEMMSL, SEMMNS, SEMOPM and SEMMNI can be configured at runtine by writing
+ *   to /proc/sys/kernel/sem.
+ * - statistics about the usage are reported in /proc/sysvipc/sem.
+ *
+ * Internals:
+ * - scalability:
+ *   - all global variables are read-mostly.
+ *   - semop() calls and semctl(RMID) are synchronized by RCU.
+ *   - most operations do write operations (actually: spin_lock calls) to
+ *     the per-semaphore array structure.
+ *   Thus: Perfect SMP scaling between independent semaphore arrays.
+ *         If multiple semaphores in one array are used, then cache line
+ *         trashing on the semaphore array spinlock will limit the scaling.
+ * - semncnt and semzcnt are calculated on demand in count_semncnt() and
+ *   count_semzcnt()
+ * - the task that performs a successful semop() scans the list of all
+ *   sleeping tasks and completes any pending operations that can be fulfilled.
+ *   Semaphores are actively given to waiting tasks (necessary for FIFO).
+ *   (see update_queue())
+ * - To improve the scalability, the actual wake-up calls are performed after
+ *   dropping all locks. (see wake_up_sem_queue_prepare(),
+ *   wake_up_sem_queue_do())
+ * - All work is done by the waker, the woken up task does not have to do
+ *   anything - not even acquiring a lock or dropping a refcount.
+ * - A woken up task may not even touch the semaphore array anymore, it may
+ *   have been destroyed already by a semctl(RMID).
+ * - The synchronizations between wake-ups due to a timeout/signal and a
+ *   wake-up due to a completed semaphore operation is achieved by using an
+ *   intermediate state (IN_WAKEUP).
+ * - UNDO values are stored in an array (one per process and per
+ *   semaphore array, lazily allocated). For backwards compatibility, multiple
+ *   modes for the UNDO variables are supported (per process, per thread)
+ *   (see copy_semundo, CLONE_SYSVSEM)
+ * - There are two lists of the pending operations: a per-array list
+ *   and per-semaphore list (stored in the array). This allows to achieve FIFO
+ *   ordering without always scanning all pending operations.
+ *   The worst-case behavior is nevertheless O(N^2) for N wakeups.
  */
 
 #include <linux/slab.h>
@@ -381,7 +384,6 @@ static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
                sop--;
        }
        
-       sma->sem_otime = get_seconds();
        return 0;
 
 out_of_range:
@@ -404,25 +406,51 @@ undo:
        return result;
 }
 
-/*
- * Wake up a process waiting on the sem queue with a given error.
- * The queue is invalid (may not be accessed) after the function returns.
+/** wake_up_sem_queue_prepare(q, error): Prepare wake-up
+ * @q: queue entry that must be signaled
+ * @error: Error value for the signal
+ *
+ * Prepare the wake-up of the queue entry q.
  */
-static void wake_up_sem_queue(struct sem_queue *q, int error)
+static void wake_up_sem_queue_prepare(struct list_head *pt,
+                               struct sem_queue *q, int error)
 {
-       /*
-        * Hold preempt off so that we don't get preempted and have the
-        * wakee busy-wait until we're scheduled back on. We're holding
-        * locks here so it may not strictly be needed, however if the
-        * locks become preemptible then this prevents such a problem.
-        */
-       preempt_disable();
+       if (list_empty(pt)) {
+               /*
+                * Hold preempt off so that we don't get preempted and have the
+                * wakee busy-wait until we're scheduled back on.
+                */
+               preempt_disable();
+       }
        q->status = IN_WAKEUP;
-       wake_up_process(q->sleeper);
-       /* hands-off: q can disappear immediately after writing q->status. */
-       smp_wmb();
-       q->status = error;
-       preempt_enable();
+       q->pid = error;
+
+       list_add_tail(&q->simple_list, pt);
+}
+
+/**
+ * wake_up_sem_queue_do(pt) - do the actual wake-up
+ * @pt: list of tasks to be woken up
+ *
+ * Do the actual wake-up.
+ * The function is called without any locks held, thus the semaphore array
+ * could be destroyed already and the tasks can disappear as soon as the
+ * status is set to the actual return code.
+ */
+static void wake_up_sem_queue_do(struct list_head *pt)
+{
+       struct sem_queue *q, *t;
+       int did_something;
+
+       did_something = !list_empty(pt);
+       list_for_each_entry_safe(q, t, pt, simple_list) {
+               wake_up_process(q->sleeper);
+               /* q can disappear immediately after writing q->status. */
+               smp_wmb();
+               q->status = q->pid;
+       }
+       if (did_something)
+               preempt_enable();
 }
 
 static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
@@ -434,22 +462,90 @@ static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
                sma->complex_count--;
 }
 
+/** check_restart(sma, q)
+ * @sma: semaphore array
+ * @q: the operation that just completed
+ *
+ * update_queue is O(N^2) when it restarts scanning the whole queue of
+ * waiting operations. Therefore this function checks if the restart is
+ * really necessary. It is called after a previously waiting operation
+ * was completed.
+ */
+static int check_restart(struct sem_array *sma, struct sem_queue *q)
+{
+       struct sem *curr;
+       struct sem_queue *h;
+
+       /* if the operation didn't modify the array, then no restart */
+       if (q->alter == 0)
+               return 0;
+
+       /* pending complex operations are too difficult to analyse */
+       if (sma->complex_count)
+               return 1;
+
+       /* we were a sleeping complex operation. Too difficult */
+       if (q->nsops > 1)
+               return 1;
+
+       curr = sma->sem_base + q->sops[0].sem_num;
+
+       /* No-one waits on this queue */
+       if (list_empty(&curr->sem_pending))
+               return 0;
+
+       /* the new semaphore value */
+       if (curr->semval) {
+               /* It is impossible that someone waits for the new value:
+                * - q is a previously sleeping simple operation that
+                *   altered the array. It must be a decrement, because
+                *   simple increments never sleep.
+                * - The value is not 0, thus wait-for-zero won't proceed.
+                * - If there are older (higher priority) decrements
+                *   in the queue, then they have observed the original
+                *   semval value and couldn't proceed. The operation
+                *   decremented to value - thus they won't proceed either.
+                */
+               BUG_ON(q->sops[0].sem_op >= 0);
+               return 0;
+       }
+       /*
+        * semval is 0. Check if there are wait-for-zero semops.
+        * They must be the first entries in the per-semaphore simple queue
+        */
+       h = list_first_entry(&curr->sem_pending, struct sem_queue, simple_list);
+       BUG_ON(h->nsops != 1);
+       BUG_ON(h->sops[0].sem_num != q->sops[0].sem_num);
+
+       /* Yes, there is a wait-for-zero semop. Restart */
+       if (h->sops[0].sem_op == 0)
+               return 1;
+
+       /* Again - no-one is waiting for the new value. */
+       return 0;
+}
+
 
 /**
  * update_queue(sma, semnum): Look for tasks that can be completed.
  * @sma: semaphore array.
  * @semnum: semaphore that was modified.
+ * @pt: list head for the tasks that must be woken up.
  *
  * update_queue must be called after a semaphore in a semaphore array
  * was modified. If multiple semaphore were modified, then @semnum
  * must be set to -1.
+ * The tasks that must be woken up are added to @pt. The return code
+ * is stored in q->pid.
+ * The function return 1 if at least one semop was completed successfully.
  */
-static void update_queue(struct sem_array *sma, int semnum)
+static int update_queue(struct sem_array *sma, int semnum, struct list_head *pt)
 {
        struct sem_queue *q;
        struct list_head *walk;
        struct list_head *pending_list;
        int offset;
+       int semop_completed = 0;
 
        /* if there are complex operations around, then knowing the semaphore
         * that was modified doesn't help us. Assume that multiple semaphores
@@ -469,7 +565,7 @@ static void update_queue(struct sem_array *sma, int semnum)
 again:
        walk = pending_list->next;
        while (walk != pending_list) {
-               int error, alter;
+               int error, restart;
 
                q = (struct sem_queue *)((char *)walk - offset);
                walk = walk->next;
@@ -494,22 +590,58 @@ again:
 
                unlink_queue(sma, q);
 
-               /*
-                * The next operation that must be checked depends on the type
-                * of the completed operation:
-                * - if the operation modified the array, then restart from the
-                *   head of the queue and check for threads that might be
-                *   waiting for the new semaphore values.
-                * - if the operation didn't modify the array, then just
-                *   continue.
-                */
-               alter = q->alter;
-               wake_up_sem_queue(q, error);
-               if (alter && !error)
+               if (error) {
+                       restart = 0;
+               } else {
+                       semop_completed = 1;
+                       restart = check_restart(sma, q);
+               }
+
+               wake_up_sem_queue_prepare(pt, q, error);
+               if (restart)
                        goto again;
        }
+       return semop_completed;
+}
+
+/**
+ * do_smart_update(sma, sops, nsops, otime, pt) - optimized update_queue
+ * @sma: semaphore array
+ * @sops: operations that were performed
+ * @nsops: number of operations
+ * @otime: force setting otime
+ * @pt: list head of the tasks that must be woken up.
+ *
+ * do_smart_update() does the required called to update_queue, based on the
+ * actual changes that were performed on the semaphore array.
+ * Note that the function does not do the actual wake-up: the caller is
+ * responsible for calling wake_up_sem_queue_do(@pt).
+ * It is safe to perform this call after dropping all locks.
+ */
+static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsops,
+                       int otime, struct list_head *pt)
+{
+       int i;
+
+       if (sma->complex_count || sops == NULL) {
+               if (update_queue(sma, -1, pt))
+                       otime = 1;
+               goto done;
+       }
+
+       for (i = 0; i < nsops; i++) {
+               if (sops[i].sem_op > 0 ||
+                       (sops[i].sem_op < 0 &&
+                               sma->sem_base[sops[i].sem_num].semval == 0))
+                       if (update_queue(sma, sops[i].sem_num, pt))
+                               otime = 1;
+       }
+done:
+       if (otime)
+               sma->sem_otime = get_seconds();
 }
 
+
 /* The following counts are associated to each semaphore:
  *   semncnt        number of tasks waiting on semval being nonzero
  *   semzcnt        number of tasks waiting on semval being zero
@@ -572,6 +704,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
        struct sem_undo *un, *tu;
        struct sem_queue *q, *tq;
        struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm);
+       struct list_head tasks;
 
        /* Free the existing undo structures for this semaphore set.  */
        assert_spin_locked(&sma->sem_perm.lock);
@@ -585,15 +718,17 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
        }
 
        /* Wake up all pending processes and let them fail with EIDRM. */
+       INIT_LIST_HEAD(&tasks);
        list_for_each_entry_safe(q, tq, &sma->sem_pending, list) {
                unlink_queue(sma, q);
-               wake_up_sem_queue(q, -EIDRM);
+               wake_up_sem_queue_prepare(&tasks, q, -EIDRM);
        }
 
        /* Remove the semaphore set from the IDR */
        sem_rmid(ns, sma);
        sem_unlock(sma);
 
+       wake_up_sem_queue_do(&tasks);
        ns->used_sems -= sma->sem_nsems;
        security_sem_free(sma);
        ipc_rcu_putref(sma);
@@ -715,11 +850,13 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
        ushort fast_sem_io[SEMMSL_FAST];
        ushort* sem_io = fast_sem_io;
        int nsems;
+       struct list_head tasks;
 
        sma = sem_lock_check(ns, semid);
        if (IS_ERR(sma))
                return PTR_ERR(sma);
 
+       INIT_LIST_HEAD(&tasks);
        nsems = sma->sem_nsems;
 
        err = -EACCES;
@@ -807,7 +944,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                }
                sma->sem_ctime = get_seconds();
                /* maybe some queued-up processes were waiting for this */
-               update_queue(sma, -1);
+               do_smart_update(sma, NULL, 0, 0, &tasks);
                err = 0;
                goto out_unlock;
        }
@@ -849,13 +986,15 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                curr->sempid = task_tgid_vnr(current);
                sma->sem_ctime = get_seconds();
                /* maybe some queued-up processes were waiting for this */
-               update_queue(sma, semnum);
+               do_smart_update(sma, NULL, 0, 0, &tasks);
                err = 0;
                goto out_unlock;
        }
        }
 out_unlock:
        sem_unlock(sma);
+       wake_up_sem_queue_do(&tasks);
+
 out_free:
        if(sem_io != fast_sem_io)
                ipc_free(sem_io, sizeof(ushort)*nsems);
@@ -1069,7 +1208,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        /* step 1: figure out the size of the semaphore array */
        sma = sem_lock_check(ns, semid);
        if (IS_ERR(sma))
-               return ERR_PTR(PTR_ERR(sma));
+               return ERR_CAST(sma);
 
        nsems = sma->sem_nsems;
        sem_getref_and_unlock(sma);
@@ -1129,6 +1268,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
        struct sem_queue queue;
        unsigned long jiffies_left = 0;
        struct ipc_namespace *ns;
+       struct list_head tasks;
 
        ns = current->nsproxy->ipc_ns;
 
@@ -1177,6 +1317,8 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
        } else
                un = NULL;
 
+       INIT_LIST_HEAD(&tasks);
+
        sma = sem_lock_check(ns, semid);
        if (IS_ERR(sma)) {
                if (un)
@@ -1225,7 +1367,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
        error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current));
        if (error <= 0) {
                if (alter && error == 0)
-                       update_queue(sma, (nsops == 1) ? sops[0].sem_num : -1);
+                       do_smart_update(sma, sops, nsops, 1, &tasks);
 
                goto out_unlock_free;
        }
@@ -1302,6 +1444,8 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
 
 out_unlock_free:
        sem_unlock(sma);
+
+       wake_up_sem_queue_do(&tasks);
 out_free:
        if(sops != fast_sops)
                kfree(sops);
@@ -1362,6 +1506,7 @@ void exit_sem(struct task_struct *tsk)
        for (;;) {
                struct sem_array *sma;
                struct sem_undo *un;
+               struct list_head tasks;
                int semid;
                int i;
 
@@ -1425,10 +1570,11 @@ void exit_sem(struct task_struct *tsk)
                                semaphore->sempid = task_tgid_vnr(current);
                        }
                }
-               sma->sem_otime = get_seconds();
                /* maybe some queued-up processes were waiting for this */
-               update_queue(sma, -1);
+               INIT_LIST_HEAD(&tasks);
+               do_smart_update(sma, NULL, 0, 1, &tasks);
                sem_unlock(sma);
+               wake_up_sem_queue_do(&tasks);
 
                call_rcu(&un->rcu, free_un);
        }
index 291775021b2e79ea696df3081bd3d0ec100ed9f1..422cb19f156ef9b7a6f5ab8968ade8a618ea5d88 100644 (file)
@@ -2994,7 +2994,6 @@ static void cgroup_event_remove(struct work_struct *work)
                        remove);
        struct cgroup *cgrp = event->cgrp;
 
-       /* TODO: check return code */
        event->cft->unregister_event(cgrp, event->cft, event->eventfd);
 
        eventfd_ctx_put(event->eventfd);
index 124ad9d6be1644864dda2a9eb55eea94a29c075c..63e8de13c948bb5ddac3034b5ea4e217e7ed71bc 100644 (file)
 /* Serializes the updates to cpu_online_mask, cpu_present_mask */
 static DEFINE_MUTEX(cpu_add_remove_lock);
 
+/*
+ * The following two API's must be used when attempting
+ * to serialize the updates to cpu_online_mask, cpu_present_mask.
+ */
+void cpu_maps_update_begin(void)
+{
+       mutex_lock(&cpu_add_remove_lock);
+}
+
+void cpu_maps_update_done(void)
+{
+       mutex_unlock(&cpu_add_remove_lock);
+}
+
 static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
 
 /* If set, cpu_up and cpu_down will return -EBUSY and do nothing.
@@ -27,6 +41,8 @@ static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
  */
 static int cpu_hotplug_disabled;
 
+#ifdef CONFIG_HOTPLUG_CPU
+
 static struct {
        struct task_struct *active_writer;
        struct mutex lock; /* Synchronizes accesses to refcount, */
@@ -41,8 +57,6 @@ static struct {
        .refcount = 0,
 };
 
-#ifdef CONFIG_HOTPLUG_CPU
-
 void get_online_cpus(void)
 {
        might_sleep();
@@ -67,22 +81,6 @@ void put_online_cpus(void)
 }
 EXPORT_SYMBOL_GPL(put_online_cpus);
 
-#endif /* CONFIG_HOTPLUG_CPU */
-
-/*
- * The following two API's must be used when attempting
- * to serialize the updates to cpu_online_mask, cpu_present_mask.
- */
-void cpu_maps_update_begin(void)
-{
-       mutex_lock(&cpu_add_remove_lock);
-}
-
-void cpu_maps_update_done(void)
-{
-       mutex_unlock(&cpu_add_remove_lock);
-}
-
 /*
  * This ensures that the hotplug operation can begin only when the
  * refcount goes to zero.
@@ -124,6 +122,12 @@ static void cpu_hotplug_done(void)
        cpu_hotplug.active_writer = NULL;
        mutex_unlock(&cpu_hotplug.lock);
 }
+
+#else /* #if CONFIG_HOTPLUG_CPU */
+static void cpu_hotplug_begin(void) {}
+static void cpu_hotplug_done(void) {}
+#endif /* #esle #if CONFIG_HOTPLUG_CPU */
+
 /* Need to know about CPUs going up/down? */
 int __ref register_cpu_notifier(struct notifier_block *nb)
 {
@@ -134,6 +138,30 @@ int __ref register_cpu_notifier(struct notifier_block *nb)
        return ret;
 }
 
+static int __cpu_notify(unsigned long val, void *v, int nr_to_call,
+                       int *nr_calls)
+{
+       int ret;
+
+       ret = __raw_notifier_call_chain(&cpu_chain, val, v, nr_to_call,
+                                       nr_calls);
+
+       return notifier_to_errno(ret);
+}
+
+static int cpu_notify(unsigned long val, void *v)
+{
+       return __cpu_notify(val, v, -1, NULL);
+}
+
+static void cpu_notify_nofail(unsigned long val, void *v)
+{
+       int err;
+
+       err = cpu_notify(val, v);
+       BUG_ON(err);
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 
 EXPORT_SYMBOL(register_cpu_notifier);
@@ -181,8 +209,7 @@ static int __ref take_cpu_down(void *_param)
        if (err < 0)
                return err;
 
-       raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod,
-                               param->hcpu);
+       cpu_notify(CPU_DYING | param->mod, param->hcpu);
 
        if (task_cpu(param->caller) == cpu)
                move_task_off_dead_cpu(cpu, param->caller);
@@ -212,17 +239,14 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
 
        cpu_hotplug_begin();
        set_cpu_active(cpu, false);
-       err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
-                                       hcpu, -1, &nr_calls);
-       if (err == NOTIFY_BAD) {
+       err = __cpu_notify(CPU_DOWN_PREPARE | mod, hcpu, -1, &nr_calls);
+       if (err) {
                set_cpu_active(cpu, true);
 
                nr_calls--;
-               __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
-                                         hcpu, nr_calls, NULL);
+               __cpu_notify(CPU_DOWN_FAILED | mod, hcpu, nr_calls, NULL);
                printk("%s: attempt to take down CPU %u failed\n",
                                __func__, cpu);
-               err = -EINVAL;
                goto out_release;
        }
 
@@ -230,9 +254,7 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
        if (err) {
                set_cpu_active(cpu, true);
                /* CPU didn't die: tell everyone.  Can't complain. */
-               if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
-                                           hcpu) == NOTIFY_BAD)
-                       BUG();
+               cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu);
 
                goto out_release;
        }
@@ -246,19 +268,14 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
        __cpu_die(cpu);
 
        /* CPU is completely dead: tell everyone.  Too late to complain. */
-       if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD | mod,
-                                   hcpu) == NOTIFY_BAD)
-               BUG();
+       cpu_notify_nofail(CPU_DEAD | mod, hcpu);
 
        check_for_tasks(cpu);
 
 out_release:
        cpu_hotplug_done();
-       if (!err) {
-               if (raw_notifier_call_chain(&cpu_chain, CPU_POST_DEAD | mod,
-                                           hcpu) == NOTIFY_BAD)
-                       BUG();
-       }
+       if (!err)
+               cpu_notify_nofail(CPU_POST_DEAD | mod, hcpu);
        return err;
 }
 
@@ -293,13 +310,11 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
                return -EINVAL;
 
        cpu_hotplug_begin();
-       ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,
-                                                       -1, &nr_calls);
-       if (ret == NOTIFY_BAD) {
+       ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls);
+       if (ret) {
                nr_calls--;
                printk("%s: attempt to bring up CPU %u failed\n",
                                __func__, cpu);
-               ret = -EINVAL;
                goto out_notify;
        }
 
@@ -312,12 +327,11 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
        set_cpu_active(cpu, true);
 
        /* Now call notifier in preparation. */
-       raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);
+       cpu_notify(CPU_ONLINE | mod, hcpu);
 
 out_notify:
        if (ret != 0)
-               __raw_notifier_call_chain(&cpu_chain,
-                               CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
+               __cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
        cpu_hotplug_done();
 
        return ret;
@@ -481,7 +495,7 @@ void __cpuinit notify_cpu_starting(unsigned int cpu)
        if (frozen_cpus != NULL && cpumask_test_cpu(cpu, frozen_cpus))
                val = CPU_STARTING_FROZEN;
 #endif /* CONFIG_PM_SLEEP_SMP */
-       raw_notifier_call_chain(&cpu_chain, val, (void *)(long)cpu);
+       cpu_notify(val, (void *)(long)cpu);
 }
 
 #endif /* CONFIG_SMP */
index 61d6af7fa6763c7b41ebba575780111761d0779a..02b9611eadde3ebe638b9c24ffbbb5ec8ada5c06 100644 (file)
@@ -2469,7 +2469,8 @@ void cpuset_unlock(void)
 }
 
 /**
- * cpuset_mem_spread_node() - On which node to begin search for a page
+ * cpuset_mem_spread_node() - On which node to begin search for a file page
+ * cpuset_slab_spread_node() - On which node to begin search for a slab page
  *
  * If a task is marked PF_SPREAD_PAGE or PF_SPREAD_SLAB (as for
  * tasks in a cpuset with is_spread_page or is_spread_slab set),
@@ -2494,16 +2495,27 @@ void cpuset_unlock(void)
  * See kmem_cache_alloc_node().
  */
 
-int cpuset_mem_spread_node(void)
+static int cpuset_spread_node(int *rotor)
 {
        int node;
 
-       node = next_node(current->cpuset_mem_spread_rotor, current->mems_allowed);
+       node = next_node(*rotor, current->mems_allowed);
        if (node == MAX_NUMNODES)
                node = first_node(current->mems_allowed);
-       current->cpuset_mem_spread_rotor = node;
+       *rotor = node;
        return node;
 }
+
+int cpuset_mem_spread_node(void)
+{
+       return cpuset_spread_node(&current->cpuset_mem_spread_rotor);
+}
+
+int cpuset_slab_spread_node(void)
+{
+       return cpuset_spread_node(&current->cpuset_slab_spread_rotor);
+}
+
 EXPORT_SYMBOL_GPL(cpuset_mem_spread_node);
 
 /**
index 2c24870c55d1279995379980766dd792f8671ebd..a2d5504fbcc24abb44c44a158521617933df4367 100644 (file)
@@ -346,66 +346,6 @@ struct cred *prepare_exec_creds(void)
        return new;
 }
 
-/*
- * prepare new credentials for the usermode helper dispatcher
- */
-struct cred *prepare_usermodehelper_creds(void)
-{
-#ifdef CONFIG_KEYS
-       struct thread_group_cred *tgcred = NULL;
-#endif
-       struct cred *new;
-
-#ifdef CONFIG_KEYS
-       tgcred = kzalloc(sizeof(*new->tgcred), GFP_ATOMIC);
-       if (!tgcred)
-               return NULL;
-#endif
-
-       new = kmem_cache_alloc(cred_jar, GFP_ATOMIC);
-       if (!new)
-               goto free_tgcred;
-
-       kdebug("prepare_usermodehelper_creds() alloc %p", new);
-
-       memcpy(new, &init_cred, sizeof(struct cred));
-
-       atomic_set(&new->usage, 1);
-       set_cred_subscribers(new, 0);
-       get_group_info(new->group_info);
-       get_uid(new->user);
-
-#ifdef CONFIG_KEYS
-       new->thread_keyring = NULL;
-       new->request_key_auth = NULL;
-       new->jit_keyring = KEY_REQKEY_DEFL_DEFAULT;
-
-       atomic_set(&tgcred->usage, 1);
-       spin_lock_init(&tgcred->lock);
-       new->tgcred = tgcred;
-#endif
-
-#ifdef CONFIG_SECURITY
-       new->security = NULL;
-#endif
-       if (security_prepare_creds(new, &init_cred, GFP_ATOMIC) < 0)
-               goto error;
-       validate_creds(new);
-
-       BUG_ON(atomic_read(&new->usage) != 1);
-       return new;
-
-error:
-       put_cred(new);
-       return NULL;
-
-free_tgcred:
-#ifdef CONFIG_KEYS
-       kfree(tgcred);
-#endif
-       return NULL;
-}
-
 /*
  * Copy credentials for the new process created by fork()
  *
index 019a2843bf958e6727f19c9b30ceb4b0da8e7cb9..ceffc67b564ae28eb6b46be67bfcf4f0ab7e8c6a 100644 (file)
 
 static void exit_mm(struct task_struct * tsk);
 
-static void __unhash_process(struct task_struct *p)
+static void __unhash_process(struct task_struct *p, bool group_dead)
 {
        nr_threads--;
        detach_pid(p, PIDTYPE_PID);
-       if (thread_group_leader(p)) {
+       if (group_dead) {
                detach_pid(p, PIDTYPE_PGID);
                detach_pid(p, PIDTYPE_SID);
 
@@ -79,10 +79,9 @@ static void __unhash_process(struct task_struct *p)
 static void __exit_signal(struct task_struct *tsk)
 {
        struct signal_struct *sig = tsk->signal;
+       bool group_dead = thread_group_leader(tsk);
        struct sighand_struct *sighand;
-
-       BUG_ON(!sig);
-       BUG_ON(!atomic_read(&sig->count));
+       struct tty_struct *uninitialized_var(tty);
 
        sighand = rcu_dereference_check(tsk->sighand,
                                        rcu_read_lock_held() ||
@@ -90,14 +89,16 @@ static void __exit_signal(struct task_struct *tsk)
        spin_lock(&sighand->siglock);
 
        posix_cpu_timers_exit(tsk);
-       if (atomic_dec_and_test(&sig->count))
+       if (group_dead) {
                posix_cpu_timers_exit_group(tsk);
-       else {
+               tty = sig->tty;
+               sig->tty = NULL;
+       } else {
                /*
                 * If there is any task waiting for the group exit
                 * then notify it:
                 */
-               if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count)
+               if (sig->notify_count > 0 && !--sig->notify_count)
                        wake_up_process(sig->group_exit_task);
 
                if (tsk == sig->curr_target)
@@ -123,32 +124,24 @@ static void __exit_signal(struct task_struct *tsk)
                sig->oublock += task_io_get_oublock(tsk);
                task_io_accounting_add(&sig->ioac, &tsk->ioac);
                sig->sum_sched_runtime += tsk->se.sum_exec_runtime;
-               sig = NULL; /* Marker for below. */
        }
 
-       __unhash_process(tsk);
+       sig->nr_threads--;
+       __unhash_process(tsk, group_dead);
 
        /*
         * Do this under ->siglock, we can race with another thread
         * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals.
         */
        flush_sigqueue(&tsk->pending);
-
-       tsk->signal = NULL;
        tsk->sighand = NULL;
        spin_unlock(&sighand->siglock);
 
        __cleanup_sighand(sighand);
        clear_tsk_thread_flag(tsk,TIF_SIGPENDING);
-       if (sig) {
+       if (group_dead) {
                flush_sigqueue(&sig->shared_pending);
-               taskstats_tgid_free(sig);
-               /*
-                * Make sure ->signal can't go away under rq->lock,
-                * see account_group_exec_runtime().
-                */
-               task_rq_unlock_wait(tsk);
-               __cleanup_signal(sig);
+               tty_kref_put(tty);
        }
 }
 
@@ -856,12 +849,9 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
 
        tsk->exit_state = signal == DEATH_REAP ? EXIT_DEAD : EXIT_ZOMBIE;
 
-       /* mt-exec, de_thread() is waiting for us */
-       if (thread_group_leader(tsk) &&
-           tsk->signal->group_exit_task &&
-           tsk->signal->notify_count < 0)
+       /* mt-exec, de_thread() is waiting for group leader */
+       if (unlikely(tsk->signal->notify_count < 0))
                wake_up_process(tsk->signal->group_exit_task);
-
        write_unlock_irq(&tasklist_lock);
 
        tracehook_report_death(tsk, signal, cookie, group_dead);
index 4d57d9e3a6e992a9d0a3514138008a0d8aefaeff..bf9fef6d1bfef80c39c5043943a150437028cb2e 100644 (file)
@@ -165,6 +165,18 @@ void free_task(struct task_struct *tsk)
 }
 EXPORT_SYMBOL(free_task);
 
+static inline void free_signal_struct(struct signal_struct *sig)
+{
+       taskstats_tgid_free(sig);
+       kmem_cache_free(signal_cachep, sig);
+}
+
+static inline void put_signal_struct(struct signal_struct *sig)
+{
+       if (atomic_dec_and_test(&sig->sigcnt))
+               free_signal_struct(sig);
+}
+
 void __put_task_struct(struct task_struct *tsk)
 {
        WARN_ON(!tsk->exit_state);
@@ -173,6 +185,7 @@ void __put_task_struct(struct task_struct *tsk)
 
        exit_creds(tsk);
        delayacct_tsk_free(tsk);
+       put_signal_struct(tsk->signal);
 
        if (!profile_handoff_task(tsk))
                free_task(tsk);
@@ -864,8 +877,9 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        if (!sig)
                return -ENOMEM;
 
-       atomic_set(&sig->count, 1);
+       sig->nr_threads = 1;
        atomic_set(&sig->live, 1);
+       atomic_set(&sig->sigcnt, 1);
        init_waitqueue_head(&sig->wait_chldexit);
        if (clone_flags & CLONE_NEWPID)
                sig->flags |= SIGNAL_UNKILLABLE;
@@ -889,13 +903,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        return 0;
 }
 
-void __cleanup_signal(struct signal_struct *sig)
-{
-       thread_group_cputime_free(sig);
-       tty_kref_put(sig->tty);
-       kmem_cache_free(signal_cachep, sig);
-}
-
 static void copy_flags(unsigned long clone_flags, struct task_struct *p)
 {
        unsigned long new_flags = p->flags;
@@ -1079,6 +1086,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        }
        mpol_fix_fork_child_flag(p);
 #endif
+#ifdef CONFIG_CPUSETS
+       p->cpuset_mem_spread_rotor = node_random(p->mems_allowed);
+       p->cpuset_slab_spread_rotor = node_random(p->mems_allowed);
+#endif
 #ifdef CONFIG_TRACE_IRQFLAGS
        p->irq_events = 0;
 #ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
@@ -1245,8 +1256,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
        }
 
        if (clone_flags & CLONE_THREAD) {
-               atomic_inc(&current->signal->count);
+               current->signal->nr_threads++;
                atomic_inc(&current->signal->live);
+               atomic_inc(&current->signal->sigcnt);
                p->group_leader = current->group_leader;
                list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group);
        }
@@ -1259,7 +1271,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                                p->nsproxy->pid_ns->child_reaper = p;
 
                        p->signal->leader_pid = pid;
-                       tty_kref_put(p->signal->tty);
                        p->signal->tty = tty_kref_get(current->signal->tty);
                        attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
                        attach_pid(p, PIDTYPE_SID, task_session(current));
@@ -1292,7 +1303,7 @@ bad_fork_cleanup_mm:
                mmput(p->mm);
 bad_fork_cleanup_signal:
        if (!(clone_flags & CLONE_THREAD))
-               __cleanup_signal(p->signal);
+               free_signal_struct(p->signal);
 bad_fork_cleanup_sighand:
        __cleanup_sighand(p->sighand);
 bad_fork_cleanup_fs:
@@ -1327,6 +1338,16 @@ noinline struct pt_regs * __cpuinit __attribute__((weak)) idle_regs(struct pt_re
        return regs;
 }
 
+static inline void init_idle_pids(struct pid_link *links)
+{
+       enum pid_type type;
+
+       for (type = PIDTYPE_PID; type < PIDTYPE_MAX; ++type) {
+               INIT_HLIST_NODE(&links[type].node); /* not really needed */
+               links[type].pid = &init_struct_pid;
+       }
+}
+
 struct task_struct * __cpuinit fork_idle(int cpu)
 {
        struct task_struct *task;
@@ -1334,8 +1355,10 @@ struct task_struct * __cpuinit fork_idle(int cpu)
 
        task = copy_process(CLONE_VM, 0, idle_regs(&regs), 0, NULL,
                            &init_struct_pid, 0);
-       if (!IS_ERR(task))
+       if (!IS_ERR(task)) {
+               init_idle_pids(task->pids);
                init_idle(task, cpu);
+       }
 
        return task;
 }
@@ -1506,14 +1529,6 @@ static void check_unshare_flags(unsigned long *flags_ptr)
        if (*flags_ptr & CLONE_VM)
                *flags_ptr |= CLONE_SIGHAND;
 
-       /*
-        * If unsharing signal handlers and the task was created
-        * using CLONE_THREAD, then must unshare the thread
-        */
-       if ((*flags_ptr & CLONE_SIGHAND) &&
-           (atomic_read(&current->signal->count) > 1))
-               *flags_ptr |= CLONE_THREAD;
-
        /*
         * If unsharing namespace, must also unshare filesystem information.
         */
index bf0e231d970236278380019513b19188132bb62a..6e9b19667a8d2fdff6ac3c0bf76d32d8c1fc4d87 100644 (file)
@@ -116,27 +116,16 @@ int __request_module(bool wait, const char *fmt, ...)
 
        trace_module_request(module_name, wait, _RET_IP_);
 
-       ret = call_usermodehelper(modprobe_path, argv, envp,
-                       wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
+       ret = call_usermodehelper_fns(modprobe_path, argv, envp,
+                       wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC,
+                       NULL, NULL, NULL);
+
        atomic_dec(&kmod_concurrent);
        return ret;
 }
 EXPORT_SYMBOL(__request_module);
 #endif /* CONFIG_MODULES */
 
-struct subprocess_info {
-       struct work_struct work;
-       struct completion *complete;
-       struct cred *cred;
-       char *path;
-       char **argv;
-       char **envp;
-       enum umh_wait wait;
-       int retval;
-       struct file *stdin;
-       void (*cleanup)(char **argv, char **envp);
-};
-
 /*
  * This is the task which runs the usermode application
  */
@@ -145,36 +134,10 @@ static int ____call_usermodehelper(void *data)
        struct subprocess_info *sub_info = data;
        int retval;
 
-       BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
-
-       /* Unblock all signals */
        spin_lock_irq(&current->sighand->siglock);
        flush_signal_handlers(current, 1);
-       sigemptyset(&current->blocked);
-       recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
 
-       /* Install the credentials */
-       commit_creds(sub_info->cred);
-       sub_info->cred = NULL;
-
-       /* Install input pipe when needed */
-       if (sub_info->stdin) {
-               struct files_struct *f = current->files;
-               struct fdtable *fdt;
-               /* no races because files should be private here */
-               sys_close(0);
-               fd_install(0, sub_info->stdin);
-               spin_lock(&f->file_lock);
-               fdt = files_fdtable(f);
-               FD_SET(0, fdt->open_fds);
-               FD_CLR(0, fdt->close_on_exec);
-               spin_unlock(&f->file_lock);
-
-               /* and disallow core files too */
-               current->signal->rlim[RLIMIT_CORE] = (struct rlimit){0, 0};
-       }
-
        /* We can run anywhere, unlike our parent keventd(). */
        set_cpus_allowed_ptr(current, cpu_all_mask);
 
@@ -184,9 +147,16 @@ static int ____call_usermodehelper(void *data)
         */
        set_user_nice(current, 0);
 
+       if (sub_info->init) {
+               retval = sub_info->init(sub_info);
+               if (retval)
+                       goto fail;
+       }
+
        retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp);
 
        /* Exec failed? */
+fail:
        sub_info->retval = retval;
        do_exit(0);
 }
@@ -194,9 +164,7 @@ static int ____call_usermodehelper(void *data)
 void call_usermodehelper_freeinfo(struct subprocess_info *info)
 {
        if (info->cleanup)
-               (*info->cleanup)(info->argv, info->envp);
-       if (info->cred)
-               put_cred(info->cred);
+               (*info->cleanup)(info);
        kfree(info);
 }
 EXPORT_SYMBOL(call_usermodehelper_freeinfo);
@@ -207,16 +175,16 @@ static int wait_for_helper(void *data)
        struct subprocess_info *sub_info = data;
        pid_t pid;
 
-       /* Install a handler: if SIGCLD isn't handled sys_wait4 won't
-        * populate the status, but will return -ECHILD. */
-       allow_signal(SIGCHLD);
+       /* If SIGCLD is ignored sys_wait4 won't populate the status. */
+       spin_lock_irq(&current->sighand->siglock);
+       current->sighand->action[SIGCHLD-1].sa.sa_handler = SIG_DFL;
+       spin_unlock_irq(&current->sighand->siglock);
 
        pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
        if (pid < 0) {
                sub_info->retval = pid;
        } else {
-               int ret;
-
+               int ret = -ECHILD;
                /*
                 * Normally it is bogus to call wait4() from in-kernel because
                 * wait4() wants to write the exit code to a userspace address.
@@ -237,10 +205,7 @@ static int wait_for_helper(void *data)
                        sub_info->retval = ret;
        }
 
-       if (sub_info->wait == UMH_NO_WAIT)
-               call_usermodehelper_freeinfo(sub_info);
-       else
-               complete(sub_info->complete);
+       complete(sub_info->complete);
        return 0;
 }
 
@@ -249,15 +214,13 @@ static void __call_usermodehelper(struct work_struct *work)
 {
        struct subprocess_info *sub_info =
                container_of(work, struct subprocess_info, work);
-       pid_t pid;
        enum umh_wait wait = sub_info->wait;
-
-       BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
+       pid_t pid;
 
        /* CLONE_VFORK: wait until the usermode helper has execve'd
         * successfully We need the data structures to stay around
         * until that is done.  */
-       if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
+       if (wait == UMH_WAIT_PROC)
                pid = kernel_thread(wait_for_helper, sub_info,
                                    CLONE_FS | CLONE_FILES | SIGCHLD);
        else
@@ -266,15 +229,16 @@ static void __call_usermodehelper(struct work_struct *work)
 
        switch (wait) {
        case UMH_NO_WAIT:
+               call_usermodehelper_freeinfo(sub_info);
                break;
 
        case UMH_WAIT_PROC:
                if (pid > 0)
                        break;
-               sub_info->retval = pid;
                /* FALLTHROUGH */
-
        case UMH_WAIT_EXEC:
+               if (pid < 0)
+                       sub_info->retval = pid;
                complete(sub_info->complete);
        }
 }
@@ -376,80 +340,37 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
        sub_info->path = path;
        sub_info->argv = argv;
        sub_info->envp = envp;
-       sub_info->cred = prepare_usermodehelper_creds();
-       if (!sub_info->cred) {
-               kfree(sub_info);
-               return NULL;
-       }
-
   out:
        return sub_info;
 }
 EXPORT_SYMBOL(call_usermodehelper_setup);
 
 /**
- * call_usermodehelper_setkeys - set the session keys for usermode helper
- * @info: a subprocess_info returned by call_usermodehelper_setup
- * @session_keyring: the session keyring for the process
- */
-void call_usermodehelper_setkeys(struct subprocess_info *info,
-                                struct key *session_keyring)
-{
-#ifdef CONFIG_KEYS
-       struct thread_group_cred *tgcred = info->cred->tgcred;
-       key_put(tgcred->session_keyring);
-       tgcred->session_keyring = key_get(session_keyring);
-#else
-       BUG();
-#endif
-}
-EXPORT_SYMBOL(call_usermodehelper_setkeys);
-
-/**
- * call_usermodehelper_setcleanup - set a cleanup function
+ * call_usermodehelper_setfns - set a cleanup/init function
  * @info: a subprocess_info returned by call_usermodehelper_setup
  * @cleanup: a cleanup function
+ * @init: an init function
+ * @data: arbitrary context sensitive data
  *
- * The cleanup function is just befor ethe subprocess_info is about to
+ * The init function is used to customize the helper process prior to
+ * exec.  A non-zero return code causes the process to error out, exit,
+ * and return the failure to the calling process
+ *
+ * The cleanup function is just before ethe subprocess_info is about to
  * be freed.  This can be used for freeing the argv and envp.  The
  * Function must be runnable in either a process context or the
  * context in which call_usermodehelper_exec is called.
  */
-void call_usermodehelper_setcleanup(struct subprocess_info *info,
-                                   void (*cleanup)(char **argv, char **envp))
+void call_usermodehelper_setfns(struct subprocess_info *info,
+                   int (*init)(struct subprocess_info *info),
+                   void (*cleanup)(struct subprocess_info *info),
+                   void *data)
 {
        info->cleanup = cleanup;
+       info->init = init;
+       info->data = data;
 }
-EXPORT_SYMBOL(call_usermodehelper_setcleanup);
-
-/**
- * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
- * @sub_info: a subprocess_info returned by call_usermodehelper_setup
- * @filp: set to the write-end of a pipe
- *
- * This constructs a pipe, and sets the read end to be the stdin of the
- * subprocess, and returns the write-end in *@filp.
- */
-int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
-                                 struct file **filp)
-{
-       struct file *f;
-
-       f = create_write_pipe(0);
-       if (IS_ERR(f))
-               return PTR_ERR(f);
-       *filp = f;
-
-       f = create_read_pipe(f, 0);
-       if (IS_ERR(f)) {
-               free_write_pipe(*filp);
-               return PTR_ERR(f);
-       }
-       sub_info->stdin = f;
-
-       return 0;
-}
-EXPORT_SYMBOL(call_usermodehelper_stdinpipe);
+EXPORT_SYMBOL(call_usermodehelper_setfns);
 
 /**
  * call_usermodehelper_exec - start a usermode application
@@ -469,9 +390,6 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
        DECLARE_COMPLETION_ONSTACK(done);
        int retval = 0;
 
-       BUG_ON(atomic_read(&sub_info->cred->usage) != 1);
-       validate_creds(sub_info->cred);
-
        helper_lock();
        if (sub_info->path[0] == '\0')
                goto out;
@@ -498,41 +416,6 @@ unlock:
 }
 EXPORT_SYMBOL(call_usermodehelper_exec);
 
-/**
- * call_usermodehelper_pipe - call a usermode helper process with a pipe stdin
- * @path: path to usermode executable
- * @argv: arg vector for process
- * @envp: environment for process
- * @filp: set to the write-end of a pipe
- *
- * This is a simple wrapper which executes a usermode-helper function
- * with a pipe as stdin.  It is implemented entirely in terms of
- * lower-level call_usermodehelper_* functions.
- */
-int call_usermodehelper_pipe(char *path, char **argv, char **envp,
-                            struct file **filp)
-{
-       struct subprocess_info *sub_info;
-       int ret;
-
-       sub_info = call_usermodehelper_setup(path, argv, envp, GFP_KERNEL);
-       if (sub_info == NULL)
-               return -ENOMEM;
-
-       ret = call_usermodehelper_stdinpipe(sub_info, filp);
-       if (ret < 0) {
-               call_usermodehelper_freeinfo(sub_info);
-               return ret;
-       }
-
-       ret = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC);
-       if (ret < 0)    /* Failed to execute helper, close pipe */
-               filp_close(*filp, NULL);
-
-       return ret;
-}
-EXPORT_SYMBOL(call_usermodehelper_pipe);
-
 void __init usermodehelper_init(void)
 {
        khelper_wq = create_singlethread_workqueue("khelper");
index b1c9857f8402d8ae66ae651153b917239d08d512..fdd8ae609ce337433b7c25c50eb20cd2ac9a16e7 100644 (file)
@@ -659,7 +659,7 @@ static int padata_cpu_callback(struct notifier_block *nfb,
                err = __padata_add_cpu(pinst, cpu);
                mutex_unlock(&pinst->lock);
                if (err)
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(err);
                break;
 
        case CPU_DOWN_PREPARE:
@@ -670,7 +670,7 @@ static int padata_cpu_callback(struct notifier_block *nfb,
                err = __padata_remove_cpu(pinst, cpu);
                mutex_unlock(&pinst->lock);
                if (err)
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(err);
                break;
 
        case CPU_UP_CANCELED:
index dbe13dbb057a27031f7c210ed86906bd443244a7..3b16cd93fa7de21977a53f863bae9b6462e355d1 100644 (file)
@@ -87,6 +87,7 @@ NORET_TYPE void panic(const char * fmt, ...)
         */
        preempt_disable();
 
+       console_verbose();
        bust_spinlocks(1);
        va_start(args, fmt);
        vsnprintf(buf, sizeof(buf), fmt, args);
index aebb30d9c233df40876afa35ef21cc5c306590a1..e9fd8c132d265011e00d75d00e589d83e1d6ce1c 100644 (file)
@@ -513,6 +513,13 @@ void __init pidhash_init(void)
 
 void __init pidmap_init(void)
 {
+       /* bump default and minimum pid_max based on number of cpus */
+       pid_max = min(pid_max_max, max_t(int, pid_max,
+                               PIDS_PER_CPU_DEFAULT * num_possible_cpus()));
+       pid_max_min = max_t(int, pid_max_min,
+                               PIDS_PER_CPU_MIN * num_possible_cpus());
+       pr_info("pid_max: default: %u minimum: %u\n", pid_max, pid_max_min);
+
        init_pid_ns.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL);
        /* Reserve PID 0. We never call free_pidmap(0) */
        set_bit(0, init_pid_ns.pidmap[0].page);
index 00bb252f29a29210270bc47167755f9bd8b307e0..9829646d399c5bf0304aa863f78f6f43ae1e4d5e 100644 (file)
@@ -363,7 +363,7 @@ int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp)
                                }
                        } else {
                                read_lock(&tasklist_lock);
-                               if (thread_group_leader(p) && p->signal) {
+                               if (thread_group_leader(p) && p->sighand) {
                                        error =
                                            cpu_clock_sample_group(which_clock,
                                                                   p, &rtn);
@@ -439,7 +439,7 @@ int posix_cpu_timer_del(struct k_itimer *timer)
 
        if (likely(p != NULL)) {
                read_lock(&tasklist_lock);
-               if (unlikely(p->signal == NULL)) {
+               if (unlikely(p->sighand == NULL)) {
                        /*
                         * We raced with the reaping of the task.
                         * The deletion should have cleared us off the list.
@@ -691,10 +691,10 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags,
        read_lock(&tasklist_lock);
        /*
         * We need the tasklist_lock to protect against reaping that
-        * clears p->signal.  If p has just been reaped, we can no
+        * clears p->sighand.  If p has just been reaped, we can no
         * longer get any information about it at all.
         */
-       if (unlikely(p->signal == NULL)) {
+       if (unlikely(p->sighand == NULL)) {
                read_unlock(&tasklist_lock);
                put_task_struct(p);
                timer->it.cpu.task = NULL;
@@ -863,7 +863,7 @@ void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
                clear_dead = p->exit_state;
        } else {
                read_lock(&tasklist_lock);
-               if (unlikely(p->signal == NULL)) {
+               if (unlikely(p->sighand == NULL)) {
                        /*
                         * The process has been reaped.
                         * We can't even collect a sample any more.
@@ -1199,7 +1199,7 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
                spin_lock(&p->sighand->siglock);
        } else {
                read_lock(&tasklist_lock);
-               if (unlikely(p->signal == NULL)) {
+               if (unlikely(p->sighand == NULL)) {
                        /*
                         * The process has been reaped.
                         * We can't even collect a sample any more.
index dfadc5b729f194905ded52faef8b2d2564dfd2ce..b22a899934cc4fe1669f4599f50ce8f54ca46632 100644 (file)
@@ -365,14 +365,14 @@ static int __cpuinit profile_cpu_callback(struct notifier_block *info,
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               node = cpu_to_node(cpu);
+               node = cpu_to_mem(cpu);
                per_cpu(cpu_profile_flip, cpu) = 0;
                if (!per_cpu(cpu_profile_hits, cpu)[1]) {
                        page = alloc_pages_exact_node(node,
                                        GFP_KERNEL | __GFP_ZERO,
                                        0);
                        if (!page)
-                               return NOTIFY_BAD;
+                               return notifier_from_errno(-ENOMEM);
                        per_cpu(cpu_profile_hits, cpu)[1] = page_address(page);
                }
                if (!per_cpu(cpu_profile_hits, cpu)[0]) {
@@ -388,7 +388,7 @@ out_free:
                page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
                per_cpu(cpu_profile_hits, cpu)[1] = NULL;
                __free_page(page);
-               return NOTIFY_BAD;
+               return notifier_from_errno(-ENOMEM);
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
                if (prof_cpu_mask != NULL)
@@ -567,7 +567,7 @@ static int create_hash_tables(void)
        int cpu;
 
        for_each_online_cpu(cpu) {
-               int node = cpu_to_node(cpu);
+               int node = cpu_to_mem(cpu);
                struct page *page;
 
                page = alloc_pages_exact_node(node,
index 6af9cdd558b7b28b5d7e44cc78e3e7cced8582d5..74a3d693c196810f9eed784a2825ea50a7f9db83 100644 (file)
@@ -594,6 +594,32 @@ int ptrace_request(struct task_struct *child, long request,
                ret = ptrace_detach(child, data);
                break;
 
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+       case PTRACE_GETFDPIC: {
+               struct mm_struct *mm = get_task_mm(child);
+               unsigned long tmp = 0;
+
+               ret = -ESRCH;
+               if (!mm)
+                       break;
+
+               switch (addr) {
+               case PTRACE_GETFDPIC_EXEC:
+                       tmp = mm->context.exec_fdpic_loadmap;
+                       break;
+               case PTRACE_GETFDPIC_INTERP:
+                       tmp = mm->context.interp_fdpic_loadmap;
+                       break;
+               default:
+                       break;
+               }
+               mmput(mm);
+
+               ret = put_user(tmp, (unsigned long __user *) data);
+               break;
+       }
+#endif
+
 #ifdef PTRACE_SINGLESTEP
        case PTRACE_SINGLESTEP:
 #endif
index 4268287148c17c34543194ce9ab987d83ee65410..c7cf397fb92958bbcbd2772e13a8d4a4d9c00b6d 100644 (file)
@@ -539,7 +539,7 @@ static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb,
                                        "relay_hotcpu_callback: cpu %d buffer "
                                        "creation failed\n", hotcpu);
                                mutex_unlock(&relay_channels_mutex);
-                               return NOTIFY_BAD;
+                               return notifier_from_errno(-ENOMEM);
                        }
                }
                mutex_unlock(&relay_channels_mutex);
index 054a6012de99b7298d5f92c4b137be17a37335f3..15b93f617fd79219b7d210df086158e176fba477 100644 (file)
@@ -969,14 +969,6 @@ static struct rq *task_rq_lock(struct task_struct *p, unsigned long *flags)
        }
 }
 
-void task_rq_unlock_wait(struct task_struct *p)
-{
-       struct rq *rq = task_rq(p);
-
-       smp_mb(); /* spin-unlock-wait is not a full memory barrier */
-       raw_spin_unlock_wait(&rq->lock);
-}
-
 static void __task_rq_unlock(struct rq *rq)
        __releases(rq->lock)
 {
index 87a330a7185fd7c145a341e2d417c5778c4538f6..35565395d00d32c7c295d3c36fa722ecdadda097 100644 (file)
@@ -381,15 +381,9 @@ __initcall(init_sched_debug_procfs);
 void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
 {
        unsigned long nr_switches;
-       unsigned long flags;
-       int num_threads = 1;
-
-       if (lock_task_sighand(p, &flags)) {
-               num_threads = atomic_read(&p->signal->count);
-               unlock_task_sighand(p, &flags);
-       }
 
-       SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid, num_threads);
+       SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid,
+                                               get_nr_threads(p));
        SEQ_printf(m,
                "---------------------------------------------------------\n");
 #define __P(F) \
index 825a3f24ad760d88018f21710a882a2b8fe36cb0..906ae5a1779c8104b14b6cb2ee774d29330145a0 100644 (file)
@@ -642,7 +642,7 @@ static inline bool si_fromuser(const struct siginfo *info)
 static int check_kill_permission(int sig, struct siginfo *info,
                                 struct task_struct *t)
 {
-       const struct cred *cred = current_cred(), *tcred;
+       const struct cred *cred, *tcred;
        struct pid *sid;
        int error;
 
@@ -656,8 +656,10 @@ static int check_kill_permission(int sig, struct siginfo *info,
        if (error)
                return error;
 
+       cred = current_cred();
        tcred = __task_cred(t);
-       if ((cred->euid ^ tcred->suid) &&
+       if (!same_thread_group(current, t) &&
+           (cred->euid ^ tcred->suid) &&
            (cred->euid ^ tcred->uid) &&
            (cred->uid  ^ tcred->suid) &&
            (cred->uid  ^ tcred->uid) &&
@@ -1083,23 +1085,24 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
 /*
  * Nuke all other threads in the group.
  */
-void zap_other_threads(struct task_struct *p)
+int zap_other_threads(struct task_struct *p)
 {
-       struct task_struct *t;
+       struct task_struct *t = p;
+       int count = 0;
 
        p->signal->group_stop_count = 0;
 
-       for (t = next_thread(p); t != p; t = next_thread(t)) {
-               /*
-                * Don't bother with already dead threads
-                */
+       while_each_thread(p, t) {
+               count++;
+
+               /* Don't bother with already dead threads */
                if (t->exit_state)
                        continue;
-
-               /* SIGKILL will be handled before any pending SIGSTOP */
                sigaddset(&t->pending.signal, SIGKILL);
                signal_wake_up(t, 1);
        }
+
+       return count;
 }
 
 struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long *flags)
index 3fc697336183a79bffd175efdd98a7663ecf3691..75c970c715d399f1385d72e92e0c47c509e568dc 100644 (file)
@@ -52,7 +52,7 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
        case CPU_UP_PREPARE_FROZEN:
                if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL,
                                cpu_to_node(cpu)))
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
                break;
 
 #ifdef CONFIG_HOTPLUG_CPU
index 0db913a5c60f4751067e668a80cb8d5c054957f0..825e1126008f374e5d9d2650a5bb29fe2106424d 100644 (file)
@@ -808,7 +808,7 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
                p = kthread_create(run_ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
                if (IS_ERR(p)) {
                        printk("ksoftirqd for %i failed\n", hotcpu);
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(PTR_ERR(p));
                }
                kthread_bind(p, hotcpu);
                per_cpu(ksoftirqd, hotcpu) = p;
index 0d36d889c74d277799ae409f396a49c6d2c15415..e83ddbbaf89d1eb4fed500696c39aa0305ba106e 100644 (file)
@@ -1632,9 +1632,9 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
 
 char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
 
-static void argv_cleanup(char **argv, char **envp)
+static void argv_cleanup(struct subprocess_info *info)
 {
-       argv_free(argv);
+       argv_free(info->argv);
 }
 
 /**
@@ -1668,7 +1668,7 @@ int orderly_poweroff(bool force)
                goto out;
        }
 
-       call_usermodehelper_setcleanup(info, argv_cleanup);
+       call_usermodehelper_setfns(info, NULL, argv_cleanup, NULL);
 
        ret = call_usermodehelper_exec(info, UMH_NO_WAIT);
 
index be394af5bc22c9eee0e65953141cca231f001d9f..e3b8c697bde44b75b76fb23c059a4b4a3942411d 100644 (file)
@@ -1680,11 +1680,14 @@ static int __cpuinit timer_cpu_notify(struct notifier_block *self,
                                unsigned long action, void *hcpu)
 {
        long cpu = (long)hcpu;
+       int err;
+
        switch(action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               if (init_timers_cpu(cpu) < 0)
-                       return NOTIFY_BAD;
+               err = init_timers_cpu(cpu);
+               if (err < 0)
+                       return notifier_from_errno(err);
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_DEAD:
index 77dabbf64b8fd45acdab9eb33cde54bad83cba62..327d2deb44515b438c8e43cec56415d85b22342d 100644 (file)
@@ -1110,7 +1110,7 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
        unsigned int cpu = (unsigned long)hcpu;
        struct cpu_workqueue_struct *cwq;
        struct workqueue_struct *wq;
-       int ret = NOTIFY_OK;
+       int err = 0;
 
        action &= ~CPU_TASKS_FROZEN;
 
@@ -1124,12 +1124,13 @@ undo:
 
                switch (action) {
                case CPU_UP_PREPARE:
-                       if (!create_workqueue_thread(cwq, cpu))
+                       err = create_workqueue_thread(cwq, cpu);
+                       if (!err)
                                break;
                        printk(KERN_ERR "workqueue [%s] for %i failed\n",
                                wq->name, cpu);
                        action = CPU_UP_CANCELED;
-                       ret = NOTIFY_BAD;
+                       err = -ENOMEM;
                        goto undo;
 
                case CPU_ONLINE:
@@ -1150,7 +1151,7 @@ undo:
                cpumask_clear_cpu(cpu, cpu_populated_map);
        }
 
-       return ret;
+       return notifier_from_errno(err);
 }
 
 #ifdef CONFIG_SMP
index 2312089483633c64dde14736a4f6da89e9d41bd7..e722e9d62221d40560176b5f8d2cabdcf74a5e2d 100644 (file)
@@ -898,6 +898,18 @@ config LKDTM
        Documentation on how to use the module can be found in
        Documentation/fault-injection/provoke-crashes.txt
 
+config CPU_NOTIFIER_ERROR_INJECT
+       tristate "CPU notifier error injection module"
+       depends on HOTPLUG_CPU && DEBUG_KERNEL
+       help
+         This option provides a kernel module that can be used to test
+         the error handling of the cpu notifiers
+
+         To compile this code as a module, choose M here: the module will
+         be called cpu-notifier-error-inject.
+
+         If unsure, say N.
+
 config FAULT_INJECTION
        bool "Fault-injection framework"
        depends on DEBUG_KERNEL
index 9e6d3c29d73a15a7db63728928e234361d48977f..c8567a59d316ab04628580ec92a02d1141042084 100644 (file)
@@ -85,6 +85,7 @@ obj-$(CONFIG_AUDIT_GENERIC) += audit.o
 obj-$(CONFIG_SWIOTLB) += swiotlb.o
 obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
 obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o
+obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o
 
 lib-$(CONFIG_GENERIC_BUG) += bug.o
 
index ffb78c916ccdf85ffb0d8ec7d0f3f1e4f41ab3ef..d7137e7e06e8b082c29fd1a186d07afbb8f32b16 100644 (file)
@@ -672,7 +672,7 @@ static int bitmap_pos_to_ord(const unsigned long *buf, int pos, int bits)
  *
  * The bit positions 0 through @bits are valid positions in @buf.
  */
-static int bitmap_ord_to_pos(const unsigned long *buf, int ord, int bits)
+int bitmap_ord_to_pos(const unsigned long *buf, int ord, int bits)
 {
        int pos = 0;
 
diff --git a/lib/cpu-notifier-error-inject.c b/lib/cpu-notifier-error-inject.c
new file mode 100644 (file)
index 0000000..4dc2032
--- /dev/null
@@ -0,0 +1,63 @@
+#include <linux/kernel.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+
+static int priority;
+static int cpu_up_prepare_error;
+static int cpu_down_prepare_error;
+
+module_param(priority, int, 0);
+MODULE_PARM_DESC(priority, "specify cpu notifier priority");
+
+module_param(cpu_up_prepare_error, int, 0644);
+MODULE_PARM_DESC(cpu_up_prepare_error,
+               "specify error code to inject CPU_UP_PREPARE action");
+
+module_param(cpu_down_prepare_error, int, 0644);
+MODULE_PARM_DESC(cpu_down_prepare_error,
+               "specify error code to inject CPU_DOWN_PREPARE action");
+
+static int err_inject_cpu_callback(struct notifier_block *nfb,
+                               unsigned long action, void *hcpu)
+{
+       int err = 0;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
+               err = cpu_up_prepare_error;
+               break;
+       case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
+               err = cpu_down_prepare_error;
+               break;
+       }
+       if (err)
+               printk(KERN_INFO "Injecting error (%d) at cpu notifier\n", err);
+
+       return notifier_from_errno(err);
+}
+
+static struct notifier_block err_inject_cpu_notifier = {
+       .notifier_call = err_inject_cpu_callback,
+};
+
+static int err_inject_init(void)
+{
+       err_inject_cpu_notifier.priority = priority;
+
+       return register_hotcpu_notifier(&err_inject_cpu_notifier);
+}
+
+static void err_inject_exit(void)
+{
+       unregister_hotcpu_notifier(&err_inject_cpu_notifier);
+}
+
+module_init(err_inject_init);
+module_exit(err_inject_exit);
+
+MODULE_DESCRIPTION("CPU notifier error injection module");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
index 3087ed899ee34c48f71249eeb98c4880bcd3a87f..4855995fcde9dc1b57a853549beb45ada94b013d 100644 (file)
@@ -50,7 +50,7 @@ MODULE_LICENSE("GPL");
 static inline u32
 crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
 {
-# if __BYTE_ORDER == __LITTLE_ENDIAN
+# ifdef __LITTLE_ENDIAN
 #  define DO_CRC(x) crc = tab[0][(crc ^ (x)) & 255] ^ (crc >> 8)
 #  define DO_CRC4 crc = tab[3][(crc) & 255] ^ \
                tab[2][(crc >> 8) & 255] ^ \
index 422a9d5069cc3389986ebcf98ebc3861e1535180..c1a2069017614e6f95a7c2a892fcca1c9c2a7ff1 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -445,6 +445,7 @@ EXPORT_SYMBOL(idr_remove);
 void idr_remove_all(struct idr *idp)
 {
        int n, id, max;
+       int bt_mask;
        struct idr_layer *p;
        struct idr_layer *pa[MAX_LEVEL];
        struct idr_layer **paa = &pa[0];
@@ -462,8 +463,10 @@ void idr_remove_all(struct idr *idp)
                        p = p->ary[(id >> n) & IDR_MASK];
                }
 
+               bt_mask = id;
                id += 1 << n;
-               while (n < fls(id)) {
+               /* Get the highest bit that the above add changed from 0->1. */
+               while (n < fls(id ^ bt_mask)) {
                        if (p)
                                free_layer(p);
                        n += IDR_BITS;
index 2a087e0f98633cf00724ef0ef7b411d9f60b609e..05da38bcc2986c296726981483b05dfc5b12109e 100644 (file)
@@ -656,7 +656,7 @@ EXPORT_SYMBOL(radix_tree_next_hole);
  *
  *     Returns: the index of the hole if found, otherwise returns an index
  *     outside of the set specified (in which case 'index - return >= max_scan'
- *     will be true). In rare cases of wrap-around, LONG_MAX will be returned.
+ *     will be true). In rare cases of wrap-around, ULONG_MAX will be returned.
  *
  *     radix_tree_next_hole may be called under rcu_read_lock. However, like
  *     radix_tree_gang_lookup, this will not atomically search a snapshot of
@@ -674,7 +674,7 @@ unsigned long radix_tree_prev_hole(struct radix_tree_root *root,
                if (!radix_tree_lookup(root, index))
                        break;
                index--;
-               if (index == LONG_MAX)
+               if (index == ULONG_MAX)
                        break;
        }
 
index 217d5c4b666d22e4f309ad363c157580c2810bf8..870dc3fc0f0f6c33a5fef027459387964ad58bbc 100644 (file)
 #include <linux/jiffies.h>
 #include <linux/random.h>
 
-struct rnd_state {
-       u32 s1, s2, s3;
-};
-
 static DEFINE_PER_CPU(struct rnd_state, net_rand_state);
 
-static u32 __random32(struct rnd_state *state)
+/**
+ *     prandom32 - seeded pseudo-random number generator.
+ *     @state: pointer to state structure holding seeded state.
+ *
+ *     This is used for pseudo-randomness with no outside seeding.
+ *     For more random results, use random32().
+ */
+u32 prandom32(struct rnd_state *state)
 {
 #define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b)
 
@@ -55,14 +58,7 @@ static u32 __random32(struct rnd_state *state)
 
        return (state->s1 ^ state->s2 ^ state->s3);
 }
-
-/*
- * Handle minimum values for seeds
- */
-static inline u32 __seed(u32 x, u32 m)
-{
-       return (x < m) ? x + m : x;
-}
+EXPORT_SYMBOL(prandom32);
 
 /**
  *     random32 - pseudo random number generator
@@ -75,7 +71,7 @@ u32 random32(void)
 {
        unsigned long r;
        struct rnd_state *state = &get_cpu_var(net_rand_state);
-       r = __random32(state);
+       r = prandom32(state);
        put_cpu_var(state);
        return r;
 }
@@ -118,12 +114,12 @@ static int __init random32_init(void)
                state->s3 = __seed(LCG(state->s2), 15);
 
                /* "warm it up" */
-               __random32(state);
-               __random32(state);
-               __random32(state);
-               __random32(state);
-               __random32(state);
-               __random32(state);
+               prandom32(state);
+               prandom32(state);
+               prandom32(state);
+               prandom32(state);
+               prandom32(state);
+               prandom32(state);
        }
        return 0;
 }
@@ -147,7 +143,7 @@ static int __init random32_reseed(void)
                state->s3 = __seed(seeds[2], 15);
 
                /* mix it in */
-               __random32(state);
+               prandom32(state);
        }
        return 0;
 }
index 5fddf720da73e42b6568b80f64234e47033bc142..a009055140ecf7a798625d3fee7cd856c0bb8d4c 100644 (file)
@@ -756,37 +756,6 @@ swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr,
 }
 EXPORT_SYMBOL(swiotlb_sync_single_for_device);
 
-/*
- * Same as above, but for a sub-range of the mapping.
- */
-static void
-swiotlb_sync_single_range(struct device *hwdev, dma_addr_t dev_addr,
-                         unsigned long offset, size_t size,
-                         int dir, int target)
-{
-       swiotlb_sync_single(hwdev, dev_addr + offset, size, dir, target);
-}
-
-void
-swiotlb_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
-                                 unsigned long offset, size_t size,
-                                 enum dma_data_direction dir)
-{
-       swiotlb_sync_single_range(hwdev, dev_addr, offset, size, dir,
-                                 SYNC_FOR_CPU);
-}
-EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_cpu);
-
-void
-swiotlb_sync_single_range_for_device(struct device *hwdev, dma_addr_t dev_addr,
-                                    unsigned long offset, size_t size,
-                                    enum dma_data_direction dir)
-{
-       swiotlb_sync_single_range(hwdev, dev_addr, offset, size, dir,
-                                 SYNC_FOR_DEVICE);
-}
-EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device);
-
 /*
  * Map a set of buffers described by scatterlist in streaming mode for DMA.
  * This is the scatter-gather version of the above swiotlb_map_page
index 88d719665a28e8f28b66a9fadffa933ae46b1875..35e12d1865666717f09094090bd5032995b7e63b 100644 (file)
@@ -1105,6 +1105,12 @@ page_not_up_to_date_locked:
                }
 
 readpage:
+               /*
+                * A previous I/O error may have been due to temporary
+                * failures, eg. multipath errors.
+                * PG_error will be set again if readpage fails.
+                */
+               ClearPageError(page);
                /* Start the actual read. The read will unlock the page. */
                error = mapping->a_ops->readpage(filp, page);
 
index c8569bc298ffc77c5a2627b5a4d2fd2a42b91742..c6ece0a5759595bf1ddbbe4a95e4b76713ea4b06 100644 (file)
@@ -149,16 +149,35 @@ struct mem_cgroup_threshold {
        u64 threshold;
 };
 
+/* For threshold */
 struct mem_cgroup_threshold_ary {
        /* An array index points to threshold just below usage. */
-       atomic_t current_threshold;
+       int current_threshold;
        /* Size of entries[] */
        unsigned int size;
        /* Array of thresholds */
        struct mem_cgroup_threshold entries[0];
 };
 
+struct mem_cgroup_thresholds {
+       /* Primary thresholds array */
+       struct mem_cgroup_threshold_ary *primary;
+       /*
+        * Spare threshold array.
+        * This is needed to make mem_cgroup_unregister_event() "never fail".
+        * It must be able to store at least primary->size - 1 entries.
+        */
+       struct mem_cgroup_threshold_ary *spare;
+};
+
+/* for OOM */
+struct mem_cgroup_eventfd_list {
+       struct list_head list;
+       struct eventfd_ctx *eventfd;
+};
+
 static void mem_cgroup_threshold(struct mem_cgroup *mem);
+static void mem_cgroup_oom_notify(struct mem_cgroup *mem);
 
 /*
  * The memory controller data structure. The memory controller controls both
@@ -207,6 +226,8 @@ struct mem_cgroup {
        atomic_t        refcnt;
 
        unsigned int    swappiness;
+       /* OOM-Killer disable */
+       int             oom_kill_disable;
 
        /* set when res.limit == memsw.limit */
        bool            memsw_is_minimum;
@@ -215,17 +236,19 @@ struct mem_cgroup {
        struct mutex thresholds_lock;
 
        /* thresholds for memory usage. RCU-protected */
-       struct mem_cgroup_threshold_ary *thresholds;
+       struct mem_cgroup_thresholdthresholds;
 
        /* thresholds for mem+swap usage. RCU-protected */
-       struct mem_cgroup_threshold_ary *memsw_thresholds;
+       struct mem_cgroup_thresholds memsw_thresholds;
+
+       /* For oom notifier event fd */
+       struct list_head oom_notify;
 
        /*
         * Should we move charges of a task when a task is moved into this
         * mem_cgroup ? And what type of charges should we move ?
         */
        unsigned long   move_charge_at_immigrate;
-
        /*
         * percpu counter.
         */
@@ -239,6 +262,7 @@ struct mem_cgroup {
  */
 enum move_type {
        MOVE_CHARGE_TYPE_ANON,  /* private anonymous page and swap of it */
+       MOVE_CHARGE_TYPE_FILE,  /* file page(including tmpfs) and swap of it */
        NR_MOVE_TYPE,
 };
 
@@ -255,6 +279,18 @@ static struct move_charge_struct {
        .waitq = __WAIT_QUEUE_HEAD_INITIALIZER(mc.waitq),
 };
 
+static bool move_anon(void)
+{
+       return test_bit(MOVE_CHARGE_TYPE_ANON,
+                                       &mc.to->move_charge_at_immigrate);
+}
+
+static bool move_file(void)
+{
+       return test_bit(MOVE_CHARGE_TYPE_FILE,
+                                       &mc.to->move_charge_at_immigrate);
+}
+
 /*
  * Maximum loops in mem_cgroup_hierarchical_reclaim(), used for soft
  * limit reclaim to prevent infinite loops, if they ever occur.
@@ -282,9 +318,12 @@ enum charge_type {
 /* for encoding cft->private value on file */
 #define _MEM                   (0)
 #define _MEMSWAP               (1)
+#define _OOM_TYPE              (2)
 #define MEMFILE_PRIVATE(x, val)        (((x) << 16) | (val))
 #define MEMFILE_TYPE(val)      (((val) >> 16) & 0xffff)
 #define MEMFILE_ATTR(val)      ((val) & 0xffff)
+/* Used for OOM nofiier */
+#define OOM_CONTROL            (0)
 
 /*
  * Reclaim flags for mem_cgroup_hierarchical_reclaim
@@ -1293,14 +1332,62 @@ static void mem_cgroup_oom_unlock(struct mem_cgroup *mem)
 static DEFINE_MUTEX(memcg_oom_mutex);
 static DECLARE_WAIT_QUEUE_HEAD(memcg_oom_waitq);
 
+struct oom_wait_info {
+       struct mem_cgroup *mem;
+       wait_queue_t    wait;
+};
+
+static int memcg_oom_wake_function(wait_queue_t *wait,
+       unsigned mode, int sync, void *arg)
+{
+       struct mem_cgroup *wake_mem = (struct mem_cgroup *)arg;
+       struct oom_wait_info *oom_wait_info;
+
+       oom_wait_info = container_of(wait, struct oom_wait_info, wait);
+
+       if (oom_wait_info->mem == wake_mem)
+               goto wakeup;
+       /* if no hierarchy, no match */
+       if (!oom_wait_info->mem->use_hierarchy || !wake_mem->use_hierarchy)
+               return 0;
+       /*
+        * Both of oom_wait_info->mem and wake_mem are stable under us.
+        * Then we can use css_is_ancestor without taking care of RCU.
+        */
+       if (!css_is_ancestor(&oom_wait_info->mem->css, &wake_mem->css) &&
+           !css_is_ancestor(&wake_mem->css, &oom_wait_info->mem->css))
+               return 0;
+
+wakeup:
+       return autoremove_wake_function(wait, mode, sync, arg);
+}
+
+static void memcg_wakeup_oom(struct mem_cgroup *mem)
+{
+       /* for filtering, pass "mem" as argument. */
+       __wake_up(&memcg_oom_waitq, TASK_NORMAL, 0, mem);
+}
+
+static void memcg_oom_recover(struct mem_cgroup *mem)
+{
+       if (mem->oom_kill_disable && atomic_read(&mem->oom_lock))
+               memcg_wakeup_oom(mem);
+}
+
 /*
  * try to call OOM killer. returns false if we should exit memory-reclaim loop.
  */
 bool mem_cgroup_handle_oom(struct mem_cgroup *mem, gfp_t mask)
 {
-       DEFINE_WAIT(wait);
-       bool locked;
+       struct oom_wait_info owait;
+       bool locked, need_to_kill;
 
+       owait.mem = mem;
+       owait.wait.flags = 0;
+       owait.wait.func = memcg_oom_wake_function;
+       owait.wait.private = current;
+       INIT_LIST_HEAD(&owait.wait.task_list);
+       need_to_kill = true;
        /* At first, try to OOM lock hierarchy under mem.*/
        mutex_lock(&memcg_oom_mutex);
        locked = mem_cgroup_oom_lock(mem);
@@ -1309,32 +1396,23 @@ bool mem_cgroup_handle_oom(struct mem_cgroup *mem, gfp_t mask)
         * accounting. So, UNINTERRUPTIBLE is appropriate. But SIGKILL
         * under OOM is always welcomed, use TASK_KILLABLE here.
         */
-       if (!locked)
-               prepare_to_wait(&memcg_oom_waitq, &wait, TASK_KILLABLE);
+       prepare_to_wait(&memcg_oom_waitq, &owait.wait, TASK_KILLABLE);
+       if (!locked || mem->oom_kill_disable)
+               need_to_kill = false;
+       if (locked)
+               mem_cgroup_oom_notify(mem);
        mutex_unlock(&memcg_oom_mutex);
 
-       if (locked)
+       if (need_to_kill) {
+               finish_wait(&memcg_oom_waitq, &owait.wait);
                mem_cgroup_out_of_memory(mem, mask);
-       else {
+       else {
                schedule();
-               finish_wait(&memcg_oom_waitq, &wait);
+               finish_wait(&memcg_oom_waitq, &owait.wait);
        }
        mutex_lock(&memcg_oom_mutex);
        mem_cgroup_oom_unlock(mem);
-       /*
-        * Here, we use global waitq .....more fine grained waitq ?
-        * Assume following hierarchy.
-        * A/
-        *   01
-        *   02
-        * assume OOM happens both in A and 01 at the same time. Tthey are
-        * mutually exclusive by lock. (kill in 01 helps A.)
-        * When we use per memcg waitq, we have to wake up waiters on A and 02
-        * in addtion to waiters on 01. We use global waitq for avoiding mess.
-        * It will not be a big problem.
-        * (And a task may be moved to other groups while it's waiting for OOM.)
-        */
-       wake_up_all(&memcg_oom_waitq);
+       memcg_wakeup_oom(mem);
        mutex_unlock(&memcg_oom_mutex);
 
        if (test_thread_flag(TIF_MEMDIE) || fatal_signal_pending(current))
@@ -2118,15 +2196,6 @@ __do_uncharge(struct mem_cgroup *mem, const enum charge_type ctype)
        /* If swapout, usage of swap doesn't decrease */
        if (!do_swap_account || ctype == MEM_CGROUP_CHARGE_TYPE_SWAPOUT)
                uncharge_memsw = false;
-       /*
-        * do_batch > 0 when unmapping pages or inode invalidate/truncate.
-        * In those cases, all pages freed continously can be expected to be in
-        * the same cgroup and we have chance to coalesce uncharges.
-        * But we do uncharge one by one if this is killed by OOM(TIF_MEMDIE)
-        * because we want to do uncharge as soon as possible.
-        */
-       if (!current->memcg_batch.do_batch || test_thread_flag(TIF_MEMDIE))
-               goto direct_uncharge;
 
        batch = &current->memcg_batch;
        /*
@@ -2136,6 +2205,17 @@ __do_uncharge(struct mem_cgroup *mem, const enum charge_type ctype)
         */
        if (!batch->memcg)
                batch->memcg = mem;
+       /*
+        * do_batch > 0 when unmapping pages or inode invalidate/truncate.
+        * In those cases, all pages freed continously can be expected to be in
+        * the same cgroup and we have chance to coalesce uncharges.
+        * But we do uncharge one by one if this is killed by OOM(TIF_MEMDIE)
+        * because we want to do uncharge as soon as possible.
+        */
+
+       if (!batch->do_batch || test_thread_flag(TIF_MEMDIE))
+               goto direct_uncharge;
+
        /*
         * In typical case, batch->memcg == mem. This means we can
         * merge a series of uncharges to an uncharge of res_counter.
@@ -2152,6 +2232,8 @@ direct_uncharge:
        res_counter_uncharge(&mem->res, PAGE_SIZE);
        if (uncharge_memsw)
                res_counter_uncharge(&mem->memsw, PAGE_SIZE);
+       if (unlikely(batch->memcg != mem))
+               memcg_oom_recover(mem);
        return;
 }
 
@@ -2188,7 +2270,8 @@ __mem_cgroup_uncharge_common(struct page *page, enum charge_type ctype)
        switch (ctype) {
        case MEM_CGROUP_CHARGE_TYPE_MAPPED:
        case MEM_CGROUP_CHARGE_TYPE_DROP:
-               if (page_mapped(page))
+               /* See mem_cgroup_prepare_migration() */
+               if (page_mapped(page) || PageCgroupMigration(pc))
                        goto unlock_out;
                break;
        case MEM_CGROUP_CHARGE_TYPE_SWAPOUT:
@@ -2288,6 +2371,7 @@ void mem_cgroup_uncharge_end(void)
                res_counter_uncharge(&batch->memcg->res, batch->bytes);
        if (batch->memsw_bytes)
                res_counter_uncharge(&batch->memcg->memsw, batch->memsw_bytes);
+       memcg_oom_recover(batch->memcg);
        /* forget this pointer (for sanity check) */
        batch->memcg = NULL;
 }
@@ -2410,10 +2494,12 @@ static inline int mem_cgroup_move_swap_account(swp_entry_t entry,
  * Before starting migration, account PAGE_SIZE to mem_cgroup that the old
  * page belongs to.
  */
-int mem_cgroup_prepare_migration(struct page *page, struct mem_cgroup **ptr)
+int mem_cgroup_prepare_migration(struct page *page,
+       struct page *newpage, struct mem_cgroup **ptr)
 {
        struct page_cgroup *pc;
        struct mem_cgroup *mem = NULL;
+       enum charge_type ctype;
        int ret = 0;
 
        if (mem_cgroup_disabled())
@@ -2424,69 +2510,125 @@ int mem_cgroup_prepare_migration(struct page *page, struct mem_cgroup **ptr)
        if (PageCgroupUsed(pc)) {
                mem = pc->mem_cgroup;
                css_get(&mem->css);
+               /*
+                * At migrating an anonymous page, its mapcount goes down
+                * to 0 and uncharge() will be called. But, even if it's fully
+                * unmapped, migration may fail and this page has to be
+                * charged again. We set MIGRATION flag here and delay uncharge
+                * until end_migration() is called
+                *
+                * Corner Case Thinking
+                * A)
+                * When the old page was mapped as Anon and it's unmap-and-freed
+                * while migration was ongoing.
+                * If unmap finds the old page, uncharge() of it will be delayed
+                * until end_migration(). If unmap finds a new page, it's
+                * uncharged when it make mapcount to be 1->0. If unmap code
+                * finds swap_migration_entry, the new page will not be mapped
+                * and end_migration() will find it(mapcount==0).
+                *
+                * B)
+                * When the old page was mapped but migraion fails, the kernel
+                * remaps it. A charge for it is kept by MIGRATION flag even
+                * if mapcount goes down to 0. We can do remap successfully
+                * without charging it again.
+                *
+                * C)
+                * The "old" page is under lock_page() until the end of
+                * migration, so, the old page itself will not be swapped-out.
+                * If the new page is swapped out before end_migraton, our
+                * hook to usual swap-out path will catch the event.
+                */
+               if (PageAnon(page))
+                       SetPageCgroupMigration(pc);
        }
        unlock_page_cgroup(pc);
+       /*
+        * If the page is not charged at this point,
+        * we return here.
+        */
+       if (!mem)
+               return 0;
 
        *ptr = mem;
-       if (mem) {
-               ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, ptr, false);
-               css_put(&mem->css);
+       ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, ptr, false);
+       css_put(&mem->css);/* drop extra refcnt */
+       if (ret || *ptr == NULL) {
+               if (PageAnon(page)) {
+                       lock_page_cgroup(pc);
+                       ClearPageCgroupMigration(pc);
+                       unlock_page_cgroup(pc);
+                       /*
+                        * The old page may be fully unmapped while we kept it.
+                        */
+                       mem_cgroup_uncharge_page(page);
+               }
+               return -ENOMEM;
        }
+       /*
+        * We charge new page before it's used/mapped. So, even if unlock_page()
+        * is called before end_migration, we can catch all events on this new
+        * page. In the case new page is migrated but not remapped, new page's
+        * mapcount will be finally 0 and we call uncharge in end_migration().
+        */
+       pc = lookup_page_cgroup(newpage);
+       if (PageAnon(page))
+               ctype = MEM_CGROUP_CHARGE_TYPE_MAPPED;
+       else if (page_is_file_cache(page))
+               ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
+       else
+               ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM;
+       __mem_cgroup_commit_charge(mem, pc, ctype);
        return ret;
 }
 
 /* remove redundant charge if migration failed*/
 void mem_cgroup_end_migration(struct mem_cgroup *mem,
-               struct page *oldpage, struct page *newpage)
+       struct page *oldpage, struct page *newpage)
 {
-       struct page *target, *unused;
+       struct page *used, *unused;
        struct page_cgroup *pc;
-       enum charge_type ctype;
 
        if (!mem)
                return;
+       /* blocks rmdir() */
        cgroup_exclude_rmdir(&mem->css);
        /* at migration success, oldpage->mapping is NULL. */
        if (oldpage->mapping) {
-               target = oldpage;
-               unused = NULL;
+               used = oldpage;
+               unused = newpage;
        } else {
-               target = newpage;
+               used = newpage;
                unused = oldpage;
        }
-
-       if (PageAnon(target))
-               ctype = MEM_CGROUP_CHARGE_TYPE_MAPPED;
-       else if (page_is_file_cache(target))
-               ctype = MEM_CGROUP_CHARGE_TYPE_CACHE;
-       else
-               ctype = MEM_CGROUP_CHARGE_TYPE_SHMEM;
-
-       /* unused page is not on radix-tree now. */
-       if (unused)
-               __mem_cgroup_uncharge_common(unused, ctype);
-
-       pc = lookup_page_cgroup(target);
        /*
-        * __mem_cgroup_commit_charge() check PCG_USED bit of page_cgroup.
-        * So, double-counting is effectively avoided.
+        * We disallowed uncharge of pages under migration because mapcount
+        * of the page goes down to zero, temporarly.
+        * Clear the flag and check the page should be charged.
         */
-       __mem_cgroup_commit_charge(mem, pc, ctype);
+       pc = lookup_page_cgroup(oldpage);
+       lock_page_cgroup(pc);
+       ClearPageCgroupMigration(pc);
+       unlock_page_cgroup(pc);
+
+       if (unused != oldpage)
+               pc = lookup_page_cgroup(unused);
+       __mem_cgroup_uncharge_common(unused, MEM_CGROUP_CHARGE_TYPE_FORCE);
 
+       pc = lookup_page_cgroup(used);
        /*
-        * Both of oldpage and newpage are still under lock_page().
-        * Then, we don't have to care about race in radix-tree.
-        * But we have to be careful that this page is unmapped or not.
-        *
-        * There is a case for !page_mapped(). At the start of
-        * migration, oldpage was mapped. But now, it's zapped.
-        * But we know *target* page is not freed/reused under us.
-        * mem_cgroup_uncharge_page() does all necessary checks.
+        * If a page is a file cache, radix-tree replacement is very atomic
+        * and we can skip this check. When it was an Anon page, its mapcount
+        * goes down to 0. But because we added MIGRATION flage, it's not
+        * uncharged yet. There are several case but page->mapcount check
+        * and USED bit check in mem_cgroup_uncharge_page() will do enough
+        * check. (see prepare_charge() also)
         */
-       if (ctype == MEM_CGROUP_CHARGE_TYPE_MAPPED)
-               mem_cgroup_uncharge_page(target);
+       if (PageAnon(used))
+               mem_cgroup_uncharge_page(used);
        /*
-        * At migration, we may charge account against cgroup which has no tasks
+        * At migration, we may charge account against cgroup which has no
+        * tasks.
         * So, rmdir()->pre_destroy() can be called while we do this charge.
         * In that case, we need to call pre_destroy() again. check it here.
         */
@@ -2524,10 +2666,11 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                                unsigned long long val)
 {
        int retry_count;
-       u64 memswlimit;
+       u64 memswlimit, memlimit;
        int ret = 0;
        int children = mem_cgroup_count_children(memcg);
        u64 curusage, oldusage;
+       int enlarge;
 
        /*
         * For keeping hierarchical_reclaim simple, how long we should retry
@@ -2538,6 +2681,7 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
 
        oldusage = res_counter_read_u64(&memcg->res, RES_USAGE);
 
+       enlarge = 0;
        while (retry_count) {
                if (signal_pending(current)) {
                        ret = -EINTR;
@@ -2555,6 +2699,11 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                        mutex_unlock(&set_limit_mutex);
                        break;
                }
+
+               memlimit = res_counter_read_u64(&memcg->res, RES_LIMIT);
+               if (memlimit < val)
+                       enlarge = 1;
+
                ret = res_counter_set_limit(&memcg->res, val);
                if (!ret) {
                        if (memswlimit == val)
@@ -2576,6 +2725,8 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                else
                        oldusage = curusage;
        }
+       if (!ret && enlarge)
+               memcg_oom_recover(memcg);
 
        return ret;
 }
@@ -2584,9 +2735,10 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                                        unsigned long long val)
 {
        int retry_count;
-       u64 memlimit, oldusage, curusage;
+       u64 memlimit, memswlimit, oldusage, curusage;
        int children = mem_cgroup_count_children(memcg);
        int ret = -EBUSY;
+       int enlarge = 0;
 
        /* see mem_cgroup_resize_res_limit */
        retry_count = children * MEM_CGROUP_RECLAIM_RETRIES;
@@ -2608,6 +2760,9 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                        mutex_unlock(&set_limit_mutex);
                        break;
                }
+               memswlimit = res_counter_read_u64(&memcg->memsw, RES_LIMIT);
+               if (memswlimit < val)
+                       enlarge = 1;
                ret = res_counter_set_limit(&memcg->memsw, val);
                if (!ret) {
                        if (memlimit == val)
@@ -2630,6 +2785,8 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
                else
                        oldusage = curusage;
        }
+       if (!ret && enlarge)
+               memcg_oom_recover(memcg);
        return ret;
 }
 
@@ -2821,6 +2978,7 @@ move_account:
                        if (ret)
                                break;
                }
+               memcg_oom_recover(mem);
                /* it seems parent cgroup doesn't have enough mem */
                if (ret == -ENOMEM)
                        goto try_to_free;
@@ -3311,9 +3469,9 @@ static void __mem_cgroup_threshold(struct mem_cgroup *memcg, bool swap)
 
        rcu_read_lock();
        if (!swap)
-               t = rcu_dereference(memcg->thresholds);
+               t = rcu_dereference(memcg->thresholds.primary);
        else
-               t = rcu_dereference(memcg->memsw_thresholds);
+               t = rcu_dereference(memcg->memsw_thresholds.primary);
 
        if (!t)
                goto unlock;
@@ -3325,7 +3483,7 @@ static void __mem_cgroup_threshold(struct mem_cgroup *memcg, bool swap)
         * If it's not true, a threshold was crossed after last
         * call of __mem_cgroup_threshold().
         */
-       i = atomic_read(&t->current_threshold);
+       i = t->current_threshold;
 
        /*
         * Iterate backward over array of thresholds starting from
@@ -3349,7 +3507,7 @@ static void __mem_cgroup_threshold(struct mem_cgroup *memcg, bool swap)
                eventfd_signal(t->entries[i].eventfd, 1);
 
        /* Update current_threshold */
-       atomic_set(&t->current_threshold, i - 1);
+       t->current_threshold = i - 1;
 unlock:
        rcu_read_unlock();
 }
@@ -3369,106 +3527,117 @@ static int compare_thresholds(const void *a, const void *b)
        return _a->threshold - _b->threshold;
 }
 
-static int mem_cgroup_register_event(struct cgroup *cgrp, struct cftype *cft,
-               struct eventfd_ctx *eventfd, const char *args)
+static int mem_cgroup_oom_notify_cb(struct mem_cgroup *mem, void *data)
+{
+       struct mem_cgroup_eventfd_list *ev;
+
+       list_for_each_entry(ev, &mem->oom_notify, list)
+               eventfd_signal(ev->eventfd, 1);
+       return 0;
+}
+
+static void mem_cgroup_oom_notify(struct mem_cgroup *mem)
+{
+       mem_cgroup_walk_tree(mem, NULL, mem_cgroup_oom_notify_cb);
+}
+
+static int mem_cgroup_usage_register_event(struct cgroup *cgrp,
+       struct cftype *cft, struct eventfd_ctx *eventfd, const char *args)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
-       struct mem_cgroup_threshold_ary *thresholds, *thresholds_new;
+       struct mem_cgroup_thresholds *thresholds;
+       struct mem_cgroup_threshold_ary *new;
        int type = MEMFILE_TYPE(cft->private);
        u64 threshold, usage;
-       int size;
-       int i, ret;
+       int i, size, ret;
 
        ret = res_counter_memparse_write_strategy(args, &threshold);
        if (ret)
                return ret;
 
        mutex_lock(&memcg->thresholds_lock);
+
        if (type == _MEM)
-               thresholds = memcg->thresholds;
+               thresholds = &memcg->thresholds;
        else if (type == _MEMSWAP)
-               thresholds = memcg->memsw_thresholds;
+               thresholds = &memcg->memsw_thresholds;
        else
                BUG();
 
        usage = mem_cgroup_usage(memcg, type == _MEMSWAP);
 
        /* Check if a threshold crossed before adding a new one */
-       if (thresholds)
+       if (thresholds->primary)
                __mem_cgroup_threshold(memcg, type == _MEMSWAP);
 
-       if (thresholds)
-               size = thresholds->size + 1;
-       else
-               size = 1;
+       size = thresholds->primary ? thresholds->primary->size + 1 : 1;
 
        /* Allocate memory for new array of thresholds */
-       thresholds_new = kmalloc(sizeof(*thresholds_new) +
-                       size * sizeof(struct mem_cgroup_threshold),
+       new = kmalloc(sizeof(*new) + size * sizeof(struct mem_cgroup_threshold),
                        GFP_KERNEL);
-       if (!thresholds_new) {
+       if (!new) {
                ret = -ENOMEM;
                goto unlock;
        }
-       thresholds_new->size = size;
+       new->size = size;
 
        /* Copy thresholds (if any) to new array */
-       if (thresholds)
-               memcpy(thresholds_new->entries, thresholds->entries,
-                               thresholds->size *
+       if (thresholds->primary) {
+               memcpy(new->entries, thresholds->primary->entries, (size - 1) *
                                sizeof(struct mem_cgroup_threshold));
+       }
+
        /* Add new threshold */
-       thresholds_new->entries[size - 1].eventfd = eventfd;
-       thresholds_new->entries[size - 1].threshold = threshold;
+       new->entries[size - 1].eventfd = eventfd;
+       new->entries[size - 1].threshold = threshold;
 
        /* Sort thresholds. Registering of new threshold isn't time-critical */
-       sort(thresholds_new->entries, size,
-                       sizeof(struct mem_cgroup_threshold),
+       sort(new->entries, size, sizeof(struct mem_cgroup_threshold),
                        compare_thresholds, NULL);
 
        /* Find current threshold */
-       atomic_set(&thresholds_new->current_threshold, -1);
+       new->current_threshold = -1;
        for (i = 0; i < size; i++) {
-               if (thresholds_new->entries[i].threshold < usage) {
+               if (new->entries[i].threshold < usage) {
                        /*
-                        * thresholds_new->current_threshold will not be used
-                        * until rcu_assign_pointer(), so it's safe to increment
+                        * new->current_threshold will not be used until
+                        * rcu_assign_pointer(), so it's safe to increment
                         * it here.
                         */
-                       atomic_inc(&thresholds_new->current_threshold);
+                       ++new->current_threshold;
                }
        }
 
-       if (type == _MEM)
-               rcu_assign_pointer(memcg->thresholds, thresholds_new);
-       else
-               rcu_assign_pointer(memcg->memsw_thresholds, thresholds_new);
+       /* Free old spare buffer and save old primary buffer as spare */
+       kfree(thresholds->spare);
+       thresholds->spare = thresholds->primary;
+
+       rcu_assign_pointer(thresholds->primary, new);
 
-       /* To be sure that nobody uses thresholds before freeing it */
+       /* To be sure that nobody uses thresholds */
        synchronize_rcu();
 
-       kfree(thresholds);
 unlock:
        mutex_unlock(&memcg->thresholds_lock);
 
        return ret;
 }
 
-static int mem_cgroup_unregister_event(struct cgroup *cgrp, struct cftype *cft,
-               struct eventfd_ctx *eventfd)
+static void mem_cgroup_usage_unregister_event(struct cgroup *cgrp,
+       struct cftype *cft, struct eventfd_ctx *eventfd)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
-       struct mem_cgroup_threshold_ary *thresholds, *thresholds_new;
+       struct mem_cgroup_thresholds *thresholds;
+       struct mem_cgroup_threshold_ary *new;
        int type = MEMFILE_TYPE(cft->private);
        u64 usage;
-       int size = 0;
-       int i, j, ret;
+       int i, j, size;
 
        mutex_lock(&memcg->thresholds_lock);
        if (type == _MEM)
-               thresholds = memcg->thresholds;
+               thresholds = &memcg->thresholds;
        else if (type == _MEMSWAP)
-               thresholds = memcg->memsw_thresholds;
+               thresholds = &memcg->memsw_thresholds;
        else
                BUG();
 
@@ -3484,59 +3653,136 @@ static int mem_cgroup_unregister_event(struct cgroup *cgrp, struct cftype *cft,
        __mem_cgroup_threshold(memcg, type == _MEMSWAP);
 
        /* Calculate new number of threshold */
-       for (i = 0; i < thresholds->size; i++) {
-               if (thresholds->entries[i].eventfd != eventfd)
+       size = 0;
+       for (i = 0; i < thresholds->primary->size; i++) {
+               if (thresholds->primary->entries[i].eventfd != eventfd)
                        size++;
        }
 
+       new = thresholds->spare;
+
        /* Set thresholds array to NULL if we don't have thresholds */
        if (!size) {
-               thresholds_new = NULL;
-               goto assign;
+               kfree(new);
+               new = NULL;
+               goto swap_buffers;
        }
 
-       /* Allocate memory for new array of thresholds */
-       thresholds_new = kmalloc(sizeof(*thresholds_new) +
-                       size * sizeof(struct mem_cgroup_threshold),
-                       GFP_KERNEL);
-       if (!thresholds_new) {
-               ret = -ENOMEM;
-               goto unlock;
-       }
-       thresholds_new->size = size;
+       new->size = size;
 
        /* Copy thresholds and find current threshold */
-       atomic_set(&thresholds_new->current_threshold, -1);
-       for (i = 0, j = 0; i < thresholds->size; i++) {
-               if (thresholds->entries[i].eventfd == eventfd)
+       new->current_threshold = -1;
+       for (i = 0, j = 0; i < thresholds->primary->size; i++) {
+               if (thresholds->primary->entries[i].eventfd == eventfd)
                        continue;
 
-               thresholds_new->entries[j] = thresholds->entries[i];
-               if (thresholds_new->entries[j].threshold < usage) {
+               new->entries[j] = thresholds->primary->entries[i];
+               if (new->entries[j].threshold < usage) {
                        /*
-                        * thresholds_new->current_threshold will not be used
+                        * new->current_threshold will not be used
                         * until rcu_assign_pointer(), so it's safe to increment
                         * it here.
                         */
-                       atomic_inc(&thresholds_new->current_threshold);
+                       ++new->current_threshold;
                }
                j++;
        }
 
-assign:
-       if (type == _MEM)
-               rcu_assign_pointer(memcg->thresholds, thresholds_new);
-       else
-               rcu_assign_pointer(memcg->memsw_thresholds, thresholds_new);
+swap_buffers:
+       /* Swap primary and spare array */
+       thresholds->spare = thresholds->primary;
+       rcu_assign_pointer(thresholds->primary, new);
 
-       /* To be sure that nobody uses thresholds before freeing it */
+       /* To be sure that nobody uses thresholds */
        synchronize_rcu();
 
-       kfree(thresholds);
-unlock:
        mutex_unlock(&memcg->thresholds_lock);
+}
 
-       return ret;
+static int mem_cgroup_oom_register_event(struct cgroup *cgrp,
+       struct cftype *cft, struct eventfd_ctx *eventfd, const char *args)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
+       struct mem_cgroup_eventfd_list *event;
+       int type = MEMFILE_TYPE(cft->private);
+
+       BUG_ON(type != _OOM_TYPE);
+       event = kmalloc(sizeof(*event), GFP_KERNEL);
+       if (!event)
+               return -ENOMEM;
+
+       mutex_lock(&memcg_oom_mutex);
+
+       event->eventfd = eventfd;
+       list_add(&event->list, &memcg->oom_notify);
+
+       /* already in OOM ? */
+       if (atomic_read(&memcg->oom_lock))
+               eventfd_signal(eventfd, 1);
+       mutex_unlock(&memcg_oom_mutex);
+
+       return 0;
+}
+
+static void mem_cgroup_oom_unregister_event(struct cgroup *cgrp,
+       struct cftype *cft, struct eventfd_ctx *eventfd)
+{
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cgrp);
+       struct mem_cgroup_eventfd_list *ev, *tmp;
+       int type = MEMFILE_TYPE(cft->private);
+
+       BUG_ON(type != _OOM_TYPE);
+
+       mutex_lock(&memcg_oom_mutex);
+
+       list_for_each_entry_safe(ev, tmp, &mem->oom_notify, list) {
+               if (ev->eventfd == eventfd) {
+                       list_del(&ev->list);
+                       kfree(ev);
+               }
+       }
+
+       mutex_unlock(&memcg_oom_mutex);
+}
+
+static int mem_cgroup_oom_control_read(struct cgroup *cgrp,
+       struct cftype *cft,  struct cgroup_map_cb *cb)
+{
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cgrp);
+
+       cb->fill(cb, "oom_kill_disable", mem->oom_kill_disable);
+
+       if (atomic_read(&mem->oom_lock))
+               cb->fill(cb, "under_oom", 1);
+       else
+               cb->fill(cb, "under_oom", 0);
+       return 0;
+}
+
+/*
+ */
+static int mem_cgroup_oom_control_write(struct cgroup *cgrp,
+       struct cftype *cft, u64 val)
+{
+       struct mem_cgroup *mem = mem_cgroup_from_cont(cgrp);
+       struct mem_cgroup *parent;
+
+       /* cannot set to root cgroup and only 0 and 1 are allowed */
+       if (!cgrp->parent || !((val == 0) || (val == 1)))
+               return -EINVAL;
+
+       parent = mem_cgroup_from_cont(cgrp->parent);
+
+       cgroup_lock();
+       /* oom-kill-disable is a flag for subhierarchy. */
+       if ((parent->use_hierarchy) ||
+           (mem->use_hierarchy && !list_empty(&cgrp->children))) {
+               cgroup_unlock();
+               return -EINVAL;
+       }
+       mem->oom_kill_disable = val;
+       cgroup_unlock();
+       return 0;
 }
 
 static struct cftype mem_cgroup_files[] = {
@@ -3544,8 +3790,8 @@ static struct cftype mem_cgroup_files[] = {
                .name = "usage_in_bytes",
                .private = MEMFILE_PRIVATE(_MEM, RES_USAGE),
                .read_u64 = mem_cgroup_read,
-               .register_event = mem_cgroup_register_event,
-               .unregister_event = mem_cgroup_unregister_event,
+               .register_event = mem_cgroup_usage_register_event,
+               .unregister_event = mem_cgroup_usage_unregister_event,
        },
        {
                .name = "max_usage_in_bytes",
@@ -3594,6 +3840,14 @@ static struct cftype mem_cgroup_files[] = {
                .read_u64 = mem_cgroup_move_charge_read,
                .write_u64 = mem_cgroup_move_charge_write,
        },
+       {
+               .name = "oom_control",
+               .read_map = mem_cgroup_oom_control_read,
+               .write_u64 = mem_cgroup_oom_control_write,
+               .register_event = mem_cgroup_oom_register_event,
+               .unregister_event = mem_cgroup_oom_unregister_event,
+               .private = MEMFILE_PRIVATE(_OOM_TYPE, OOM_CONTROL),
+       },
 };
 
 #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
@@ -3602,8 +3856,8 @@ static struct cftype memsw_cgroup_files[] = {
                .name = "memsw.usage_in_bytes",
                .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE),
                .read_u64 = mem_cgroup_read,
-               .register_event = mem_cgroup_register_event,
-               .unregister_event = mem_cgroup_unregister_event,
+               .register_event = mem_cgroup_usage_register_event,
+               .unregister_event = mem_cgroup_usage_unregister_event,
        },
        {
                .name = "memsw.max_usage_in_bytes",
@@ -3831,6 +4085,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
        } else {
                parent = mem_cgroup_from_cont(cont->parent);
                mem->use_hierarchy = parent->use_hierarchy;
+               mem->oom_kill_disable = parent->oom_kill_disable;
        }
 
        if (parent && parent->use_hierarchy) {
@@ -3849,6 +4104,7 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
        }
        mem->last_scanned_child = 0;
        spin_lock_init(&mem->reclaim_param_lock);
+       INIT_LIST_HEAD(&mem->oom_notify);
 
        if (parent)
                mem->swappiness = get_swappiness(parent);
@@ -3976,6 +4232,80 @@ enum mc_target_type {
        MC_TARGET_SWAP,
 };
 
+static struct page *mc_handle_present_pte(struct vm_area_struct *vma,
+                                               unsigned long addr, pte_t ptent)
+{
+       struct page *page = vm_normal_page(vma, addr, ptent);
+
+       if (!page || !page_mapped(page))
+               return NULL;
+       if (PageAnon(page)) {
+               /* we don't move shared anon */
+               if (!move_anon() || page_mapcount(page) > 2)
+                       return NULL;
+       } else if (!move_file())
+               /* we ignore mapcount for file pages */
+               return NULL;
+       if (!get_page_unless_zero(page))
+               return NULL;
+
+       return page;
+}
+
+static struct page *mc_handle_swap_pte(struct vm_area_struct *vma,
+                       unsigned long addr, pte_t ptent, swp_entry_t *entry)
+{
+       int usage_count;
+       struct page *page = NULL;
+       swp_entry_t ent = pte_to_swp_entry(ptent);
+
+       if (!move_anon() || non_swap_entry(ent))
+               return NULL;
+       usage_count = mem_cgroup_count_swap_user(ent, &page);
+       if (usage_count > 1) { /* we don't move shared anon */
+               if (page)
+                       put_page(page);
+               return NULL;
+       }
+       if (do_swap_account)
+               entry->val = ent.val;
+
+       return page;
+}
+
+static struct page *mc_handle_file_pte(struct vm_area_struct *vma,
+                       unsigned long addr, pte_t ptent, swp_entry_t *entry)
+{
+       struct page *page = NULL;
+       struct inode *inode;
+       struct address_space *mapping;
+       pgoff_t pgoff;
+
+       if (!vma->vm_file) /* anonymous vma */
+               return NULL;
+       if (!move_file())
+               return NULL;
+
+       inode = vma->vm_file->f_path.dentry->d_inode;
+       mapping = vma->vm_file->f_mapping;
+       if (pte_none(ptent))
+               pgoff = linear_page_index(vma, addr);
+       else /* pte_file(ptent) is true */
+               pgoff = pte_to_pgoff(ptent);
+
+       /* page is moved even if it's not RSS of this task(page-faulted). */
+       if (!mapping_cap_swap_backed(mapping)) { /* normal file */
+               page = find_get_page(mapping, pgoff);
+       } else { /* shmem/tmpfs file. we should take account of swap too. */
+               swp_entry_t ent;
+               mem_cgroup_get_shmem_target(inode, pgoff, &page, &ent);
+               if (do_swap_account)
+                       entry->val = ent.val;
+       }
+
+       return page;
+}
+
 static int is_target_pte_for_mc(struct vm_area_struct *vma,
                unsigned long addr, pte_t ptent, union mc_target *target)
 {
@@ -3983,43 +4313,16 @@ static int is_target_pte_for_mc(struct vm_area_struct *vma,
        struct page_cgroup *pc;
        int ret = 0;
        swp_entry_t ent = { .val = 0 };
-       int usage_count = 0;
-       bool move_anon = test_bit(MOVE_CHARGE_TYPE_ANON,
-                                       &mc.to->move_charge_at_immigrate);
 
-       if (!pte_present(ptent)) {
-               /* TODO: handle swap of shmes/tmpfs */
-               if (pte_none(ptent) || pte_file(ptent))
-                       return 0;
-               else if (is_swap_pte(ptent)) {
-                       ent = pte_to_swp_entry(ptent);
-                       if (!move_anon || non_swap_entry(ent))
-                               return 0;
-                       usage_count = mem_cgroup_count_swap_user(ent, &page);
-               }
-       } else {
-               page = vm_normal_page(vma, addr, ptent);
-               if (!page || !page_mapped(page))
-                       return 0;
-               /*
-                * TODO: We don't move charges of file(including shmem/tmpfs)
-                * pages for now.
-                */
-               if (!move_anon || !PageAnon(page))
-                       return 0;
-               if (!get_page_unless_zero(page))
-                       return 0;
-               usage_count = page_mapcount(page);
-       }
-       if (usage_count > 1) {
-               /*
-                * TODO: We don't move charges of shared(used by multiple
-                * processes) pages for now.
-                */
-               if (page)
-                       put_page(page);
+       if (pte_present(ptent))
+               page = mc_handle_present_pte(vma, addr, ptent);
+       else if (is_swap_pte(ptent))
+               page = mc_handle_swap_pte(vma, addr, ptent, &ent);
+       else if (pte_none(ptent) || pte_file(ptent))
+               page = mc_handle_file_pte(vma, addr, ptent, &ent);
+
+       if (!page && !ent.val)
                return 0;
-       }
        if (page) {
                pc = lookup_page_cgroup(page);
                /*
@@ -4035,8 +4338,8 @@ static int is_target_pte_for_mc(struct vm_area_struct *vma,
                if (!ret || !target)
                        put_page(page);
        }
-       /* throught */
-       if (ent.val && do_swap_account && !ret &&
+       /* There is a swap entry and a page doesn't exist or isn't charged */
+       if (ent.val && !ret &&
                        css_id(&mc.from->css) == lookup_swap_cgroup(ent)) {
                ret = MC_TARGET_SWAP;
                if (target)
@@ -4077,9 +4380,6 @@ static unsigned long mem_cgroup_count_precharge(struct mm_struct *mm)
                };
                if (is_vm_hugetlb_page(vma))
                        continue;
-               /* TODO: We don't move charges of shmem/tmpfs pages for now. */
-               if (vma->vm_flags & VM_SHARED)
-                       continue;
                walk_page_range(vma->vm_start, vma->vm_end,
                                        &mem_cgroup_count_precharge_walk);
        }
@@ -4102,6 +4402,7 @@ static void mem_cgroup_clear_mc(void)
        if (mc.precharge) {
                __mem_cgroup_cancel_charge(mc.to, mc.precharge);
                mc.precharge = 0;
+               memcg_oom_recover(mc.to);
        }
        /*
         * we didn't uncharge from mc.from at mem_cgroup_move_account(), so
@@ -4110,6 +4411,7 @@ static void mem_cgroup_clear_mc(void)
        if (mc.moved_charge) {
                __mem_cgroup_cancel_charge(mc.from, mc.moved_charge);
                mc.moved_charge = 0;
+               memcg_oom_recover(mc.from);
        }
        /* we must fixup refcnts and charges */
        if (mc.moved_swap) {
@@ -4274,9 +4576,6 @@ static void mem_cgroup_move_charge(struct mm_struct *mm)
                };
                if (is_vm_hugetlb_page(vma))
                        continue;
-               /* TODO: We don't move charges of shmem/tmpfs pages for now. */
-               if (vma->vm_flags & VM_SHARED)
-                       continue;
                ret = walk_page_range(vma->vm_start, vma->vm_end,
                                                &mem_cgroup_move_charge_walk);
                if (ret)
index 75751012c552066f3e5f53329933d3f751cacb10..5d6fb339de038945424733d5128846a1a1a7e352 100644 (file)
@@ -2098,7 +2098,7 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
                /* contextualize the tmpfs mount point mempolicy */
                new = mpol_new(mpol->mode, mpol->flags, &mpol->w.user_nodemask);
                if (IS_ERR(new))
-                       goto put_free; /* no valid nodemask intersection */
+                       goto free_scratch; /* no valid nodemask intersection */
 
                task_lock(current);
                ret = mpol_set_nodemask(new, &mpol->w.user_nodemask, scratch);
@@ -2114,6 +2114,7 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
 
 put_free:
                mpol_put(new);                  /* drop initial ref */
+free_scratch:
                NODEMASK_SCRATCH_FREE(scratch);
        }
 }
index 09e2471afa0f7f4ab658adca783c9a2bd1eadc4f..4205b1d6049ed2f6a07da22c0a100d52d6ccd0f8 100644 (file)
@@ -590,7 +590,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        }
 
        /* charge against new page */
-       charge = mem_cgroup_prepare_migration(page, &mem);
+       charge = mem_cgroup_prepare_migration(page, newpage, &mem);
        if (charge == -ENOMEM) {
                rc = -ENOMEM;
                goto unlock;
index 63fa17d121f027ca5c75f09eab994db346316d2b..b76f3ee0abe015a85f36ff4b2599cff21d3c3efd 100644 (file)
@@ -918,14 +918,6 @@ static int validate_mmap_request(struct file *file,
                        if (!(capabilities & BDI_CAP_MAP_DIRECT))
                                return -ENODEV;
 
-                       if (((prot & PROT_READ)  && !(capabilities & BDI_CAP_READ_MAP))  ||
-                           ((prot & PROT_WRITE) && !(capabilities & BDI_CAP_WRITE_MAP)) ||
-                           ((prot & PROT_EXEC)  && !(capabilities & BDI_CAP_EXEC_MAP))
-                           ) {
-                               printk("MAP_SHARED not completely supported on !MMU\n");
-                               return -EINVAL;
-                       }
-
                        /* we mustn't privatise shared mappings */
                        capabilities &= ~BDI_CAP_MAP_COPY;
                }
@@ -941,6 +933,20 @@ static int validate_mmap_request(struct file *file,
                                capabilities &= ~BDI_CAP_MAP_DIRECT;
                }
 
+               if (capabilities & BDI_CAP_MAP_DIRECT) {
+                       if (((prot & PROT_READ)  && !(capabilities & BDI_CAP_READ_MAP))  ||
+                           ((prot & PROT_WRITE) && !(capabilities & BDI_CAP_WRITE_MAP)) ||
+                           ((prot & PROT_EXEC)  && !(capabilities & BDI_CAP_EXEC_MAP))
+                           ) {
+                               capabilities &= ~BDI_CAP_MAP_DIRECT;
+                               if (flags & MAP_SHARED) {
+                                       printk(KERN_WARNING
+                                              "MAP_SHARED not completely supported on !MMU\n");
+                                       return -EINVAL;
+                               }
+                       }
+               }
+
                /* handle executable mappings and implied executable
                 * mappings */
                if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) {
@@ -996,22 +1002,20 @@ static unsigned long determine_vm_flags(struct file *file,
        unsigned long vm_flags;
 
        vm_flags = calc_vm_prot_bits(prot) | calc_vm_flag_bits(flags);
-       vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
        /* vm_flags |= mm->def_flags; */
 
        if (!(capabilities & BDI_CAP_MAP_DIRECT)) {
                /* attempt to share read-only copies of mapped file chunks */
+               vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
                if (file && !(prot & PROT_WRITE))
                        vm_flags |= VM_MAYSHARE;
-       }
-       else {
+       } else {
                /* overlay a shareable mapping on the backing device or inode
                 * if possible - used for chardevs, ramfs/tmpfs/shmfs and
                 * romfs/cramfs */
+               vm_flags |= VM_MAYSHARE | (capabilities & BDI_CAP_VMFLAGS);
                if (flags & MAP_SHARED)
-                       vm_flags |= VM_MAYSHARE | VM_SHARED;
-               else if ((((vm_flags & capabilities) ^ vm_flags) & BDI_CAP_VMFLAGS) == 0)
-                       vm_flags |= VM_MAYSHARE;
+                       vm_flags |= VM_SHARED;
        }
 
        /* refuse to let anyone share private mappings with this process if
index b68e802a7a7d6961a0c1f7709a9cc606d022371c..709aedfaa014946664f2b83857b749d92f79752f 100644 (file)
@@ -479,12 +479,9 @@ void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask)
        read_lock(&tasklist_lock);
 retry:
        p = select_bad_process(&points, mem);
-       if (PTR_ERR(p) == -1UL)
+       if (!p || PTR_ERR(p) == -1UL)
                goto out;
 
-       if (!p)
-               p = current;
-
        if (oom_kill_process(p, gfp_mask, 0, points, mem,
                                "Memory cgroup out of memory"))
                goto retry;
index 08b349931ebc6bffef8be14c1d5d890750a88038..431214b941acec39f68e171e468a59f74b9b749e 100644 (file)
 #include <asm/div64.h>
 #include "internal.h"
 
+#ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID
+DEFINE_PER_CPU(int, numa_node);
+EXPORT_PER_CPU_SYMBOL(numa_node);
+#endif
+
+#ifdef CONFIG_HAVE_MEMORYLESS_NODES
+/*
+ * N.B., Do NOT reference the '_numa_mem_' per cpu variable directly.
+ * It will not be defined when CONFIG_HAVE_MEMORYLESS_NODES is not defined.
+ * Use the accessor functions set_numa_mem(), numa_mem_id() and cpu_to_mem()
+ * defined in <linux/topology.h>.
+ */
+DEFINE_PER_CPU(int, _numa_mem_);               /* Kernel "local memory" node */
+EXPORT_PER_CPU_SYMBOL(_numa_mem_);
+#endif
+
 /*
  * Array of node states.
  */
@@ -2856,6 +2872,24 @@ static void build_zonelist_cache(pg_data_t *pgdat)
                zlc->z_to_n[z - zonelist->_zonerefs] = zonelist_node_idx(z);
 }
 
+#ifdef CONFIG_HAVE_MEMORYLESS_NODES
+/*
+ * Return node id of node used for "local" allocations.
+ * I.e., first node id of first zone in arg node's generic zonelist.
+ * Used for initializing percpu 'numa_mem', which is used primarily
+ * for kernel allocations, so use GFP_KERNEL flags to locate zonelist.
+ */
+int local_memory_node(int node)
+{
+       struct zone *zone;
+
+       (void)first_zones_zonelist(node_zonelist(node, GFP_KERNEL),
+                                  gfp_zone(GFP_KERNEL),
+                                  NULL,
+                                  &zone);
+       return zone->node;
+}
+#endif
 
 #else  /* CONFIG_NUMA */
 
@@ -2970,9 +3004,23 @@ static __init_refok int __build_all_zonelists(void *data)
         * needs the percpu allocator in order to allocate its pagesets
         * (a chicken-egg dilemma).
         */
-       for_each_possible_cpu(cpu)
+       for_each_possible_cpu(cpu) {
                setup_pageset(&per_cpu(boot_pageset, cpu), 0);
 
+#ifdef CONFIG_HAVE_MEMORYLESS_NODES
+               /*
+                * We now know the "local memory node" for each node--
+                * i.e., the node of the first zone in the generic zonelist.
+                * Set up numa_mem percpu variable for on-line cpus.  During
+                * boot, only the boot cpu should be on-line;  we'll init the
+                * secondary cpus' numa_mem as they come on-line.  During
+                * node/memory hotplug, we'll fixup all on-line cpus.
+                */
+               if (cpu_online(cpu))
+                       set_cpu_numa_mem(cpu, local_memory_node(cpu_to_node(cpu)));
+#endif
+       }
+
        return 0;
 }
 
index 4ef9797bd430a9b0b79ebd7bffc1a3fcb3a1ee1f..855eaf5b8d5bd964d4af0f6d1280d347b9490e8d 100644 (file)
@@ -2559,6 +2559,45 @@ out4:
        return error;
 }
 
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR
+/**
+ * mem_cgroup_get_shmem_target - find a page or entry assigned to the shmem file
+ * @inode: the inode to be searched
+ * @pgoff: the offset to be searched
+ * @pagep: the pointer for the found page to be stored
+ * @ent: the pointer for the found swap entry to be stored
+ *
+ * If a page is found, refcount of it is incremented. Callers should handle
+ * these refcount.
+ */
+void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff,
+                                       struct page **pagep, swp_entry_t *ent)
+{
+       swp_entry_t entry = { .val = 0 }, *ptr;
+       struct page *page = NULL;
+       struct shmem_inode_info *info = SHMEM_I(inode);
+
+       if ((pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode))
+               goto out;
+
+       spin_lock(&info->lock);
+       ptr = shmem_swp_entry(info, pgoff, NULL);
+#ifdef CONFIG_SWAP
+       if (ptr && ptr->val) {
+               entry.val = ptr->val;
+               page = find_get_page(&swapper_space, entry.val);
+       } else
+#endif
+               page = find_get_page(inode->i_mapping, pgoff);
+       if (ptr)
+               shmem_swp_unmap(ptr);
+       spin_unlock(&info->lock);
+out:
+       *pagep = page;
+       *ent = entry;
+}
+#endif
+
 #else /* !CONFIG_SHMEM */
 
 /*
@@ -2598,6 +2637,31 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user)
        return 0;
 }
 
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR
+/**
+ * mem_cgroup_get_shmem_target - find a page or entry assigned to the shmem file
+ * @inode: the inode to be searched
+ * @pgoff: the offset to be searched
+ * @pagep: the pointer for the found page to be stored
+ * @ent: the pointer for the found swap entry to be stored
+ *
+ * If a page is found, refcount of it is incremented. Callers should handle
+ * these refcount.
+ */
+void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff,
+                                       struct page **pagep, swp_entry_t *ent)
+{
+       struct page *page = NULL;
+
+       if ((pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode))
+               goto out;
+       page = find_get_page(inode->i_mapping, pgoff);
+out:
+       *pagep = page;
+       *ent = (swp_entry_t){ .val = 0 };
+}
+#endif
+
 #define shmem_vm_ops                           generic_file_vm_ops
 #define shmem_file_operations                  ramfs_file_operations
 #define shmem_get_inode(sb, dir, mode, dev, flags)     ramfs_get_inode(sb, dir, mode, dev)
index 02786e1a32d26952d66c2dfff80013adf51ccb9e..e49f8f46f46d6878dba427dae10fc9b5fb153a9f 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -821,7 +821,7 @@ static void init_reap_node(int cpu)
 {
        int node;
 
-       node = next_node(cpu_to_node(cpu), node_online_map);
+       node = next_node(cpu_to_mem(cpu), node_online_map);
        if (node == MAX_NUMNODES)
                node = first_node(node_online_map);
 
@@ -1050,7 +1050,7 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
        struct array_cache *alien = NULL;
        int node;
 
-       node = numa_node_id();
+       node = numa_mem_id();
 
        /*
         * Make sure we are not freeing a object from another node to the array
@@ -1129,7 +1129,7 @@ static void __cpuinit cpuup_canceled(long cpu)
 {
        struct kmem_cache *cachep;
        struct kmem_list3 *l3 = NULL;
-       int node = cpu_to_node(cpu);
+       int node = cpu_to_mem(cpu);
        const struct cpumask *mask = cpumask_of_node(node);
 
        list_for_each_entry(cachep, &cache_chain, next) {
@@ -1194,7 +1194,7 @@ static int __cpuinit cpuup_prepare(long cpu)
 {
        struct kmem_cache *cachep;
        struct kmem_list3 *l3 = NULL;
-       int node = cpu_to_node(cpu);
+       int node = cpu_to_mem(cpu);
        int err;
 
        /*
@@ -1321,7 +1321,7 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
                mutex_unlock(&cache_chain_mutex);
                break;
        }
-       return err ? NOTIFY_BAD : NOTIFY_OK;
+       return notifier_from_errno(err);
 }
 
 static struct notifier_block __cpuinitdata cpucache_notifier = {
@@ -1479,7 +1479,7 @@ void __init kmem_cache_init(void)
         * 6) Resize the head arrays of the kmalloc caches to their final sizes.
         */
 
-       node = numa_node_id();
+       node = numa_mem_id();
 
        /* 1) create the cache_cache */
        INIT_LIST_HEAD(&cache_chain);
@@ -2121,7 +2121,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
                        }
                }
        }
-       cachep->nodelists[numa_node_id()]->next_reap =
+       cachep->nodelists[numa_mem_id()]->next_reap =
                        jiffies + REAPTIMEOUT_LIST3 +
                        ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
 
@@ -2452,7 +2452,7 @@ static void check_spinlock_acquired(struct kmem_cache *cachep)
 {
 #ifdef CONFIG_SMP
        check_irq_off();
-       assert_spin_locked(&cachep->nodelists[numa_node_id()]->list_lock);
+       assert_spin_locked(&cachep->nodelists[numa_mem_id()]->list_lock);
 #endif
 }
 
@@ -2479,7 +2479,7 @@ static void do_drain(void *arg)
 {
        struct kmem_cache *cachep = arg;
        struct array_cache *ac;
-       int node = numa_node_id();
+       int node = numa_mem_id();
 
        check_irq_off();
        ac = cpu_cache_get(cachep);
@@ -3012,7 +3012,7 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
 
 retry:
        check_irq_off();
-       node = numa_node_id();
+       node = numa_mem_id();
        ac = cpu_cache_get(cachep);
        batchcount = ac->batchcount;
        if (!ac->touched && batchcount > BATCHREFILL_LIMIT) {
@@ -3216,10 +3216,10 @@ static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags)
 
        if (in_interrupt() || (flags & __GFP_THISNODE))
                return NULL;
-       nid_alloc = nid_here = numa_node_id();
+       nid_alloc = nid_here = numa_mem_id();
        get_mems_allowed();
        if (cpuset_do_slab_mem_spread() && (cachep->flags & SLAB_MEM_SPREAD))
-               nid_alloc = cpuset_mem_spread_node();
+               nid_alloc = cpuset_slab_spread_node();
        else if (current->mempolicy)
                nid_alloc = slab_node(current->mempolicy);
        put_mems_allowed();
@@ -3281,7 +3281,7 @@ retry:
                if (local_flags & __GFP_WAIT)
                        local_irq_enable();
                kmem_flagcheck(cache, flags);
-               obj = kmem_getpages(cache, local_flags, numa_node_id());
+               obj = kmem_getpages(cache, local_flags, numa_mem_id());
                if (local_flags & __GFP_WAIT)
                        local_irq_disable();
                if (obj) {
@@ -3389,6 +3389,7 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
 {
        unsigned long save_flags;
        void *ptr;
+       int slab_node = numa_mem_id();
 
        flags &= gfp_allowed_mask;
 
@@ -3401,7 +3402,7 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
        local_irq_save(save_flags);
 
        if (nodeid == -1)
-               nodeid = numa_node_id();
+               nodeid = slab_node;
 
        if (unlikely(!cachep->nodelists[nodeid])) {
                /* Node not bootstrapped yet */
@@ -3409,7 +3410,7 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
                goto out;
        }
 
-       if (nodeid == numa_node_id()) {
+       if (nodeid == slab_node) {
                /*
                 * Use the locally cached objects if possible.
                 * However ____cache_alloc does not allow fallback
@@ -3453,8 +3454,8 @@ __do_cache_alloc(struct kmem_cache *cache, gfp_t flags)
         * We may just have run out of memory on the local node.
         * ____cache_alloc_node() knows how to locate memory on other nodes
         */
-       if (!objp)
-               objp = ____cache_alloc_node(cache, flags, numa_node_id());
+       if (!objp)
+               objp = ____cache_alloc_node(cache, flags, numa_mem_id());
 
   out:
        return objp;
@@ -3551,7 +3552,7 @@ static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac)
 {
        int batchcount;
        struct kmem_list3 *l3;
-       int node = numa_node_id();
+       int node = numa_mem_id();
 
        batchcount = ac->batchcount;
 #if DEBUG
@@ -3985,7 +3986,7 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
                return -ENOMEM;
 
        for_each_online_cpu(i) {
-               new->new[i] = alloc_arraycache(cpu_to_node(i), limit,
+               new->new[i] = alloc_arraycache(cpu_to_mem(i), limit,
                                                batchcount, gfp);
                if (!new->new[i]) {
                        for (i--; i >= 0; i--)
@@ -4007,9 +4008,9 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit,
                struct array_cache *ccold = new->new[i];
                if (!ccold)
                        continue;
-               spin_lock_irq(&cachep->nodelists[cpu_to_node(i)]->list_lock);
-               free_block(cachep, ccold->entry, ccold->avail, cpu_to_node(i));
-               spin_unlock_irq(&cachep->nodelists[cpu_to_node(i)]->list_lock);
+               spin_lock_irq(&cachep->nodelists[cpu_to_mem(i)]->list_lock);
+               free_block(cachep, ccold->entry, ccold->avail, cpu_to_mem(i));
+               spin_unlock_irq(&cachep->nodelists[cpu_to_mem(i)]->list_lock);
                kfree(ccold);
        }
        kfree(new);
@@ -4115,7 +4116,7 @@ static void cache_reap(struct work_struct *w)
 {
        struct kmem_cache *searchp;
        struct kmem_list3 *l3;
-       int node = numa_node_id();
+       int node = numa_mem_id();
        struct delayed_work *work = to_delayed_work(w);
 
        if (!mutex_trylock(&cache_chain_mutex))
index fd8b28361a6415eaf4d98251a7be40fbc478f7bc..f28ad2cc8428b0f02071c44f1e1b793609183bba 100644 (file)
@@ -632,13 +632,14 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
                iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data),
                                        GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
                if (!iucv_irq_data[cpu])
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
+
                iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param),
                                     GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
                if (!iucv_param[cpu]) {
                        kfree(iucv_irq_data[cpu]);
                        iucv_irq_data[cpu] = NULL;
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
                }
                iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param),
                                        GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
@@ -647,7 +648,7 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
                        iucv_param[cpu] = NULL;
                        kfree(iucv_irq_data[cpu]);
                        iucv_irq_data[cpu] = NULL;
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-ENOMEM);
                }
                break;
        case CPU_UP_CANCELED:
@@ -677,7 +678,7 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
                cpu_clear(cpu, cpumask);
                if (cpus_empty(cpumask))
                        /* Can't offline last IUCV enabled cpu. */
-                       return NOTIFY_BAD;
+                       return notifier_from_errno(-EINVAL);
                smp_call_function_single(cpu, iucv_retrieve_cpu, NULL, 1);
                if (cpus_empty(iucv_irq_cpumask))
                        smp_call_function_single(first_cpu(iucv_buffer_cpumask),
index b7cd8cccbe72c3dc12320e65af18f22104d5df5d..2a9675136c68e487adcf02849c54680ed7fd0e98 100644 (file)
@@ -2293,6 +2293,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
        struct sockaddr *addr = args->dstaddr;
        struct rpc_xprt *xprt;
        struct sock_xprt *transport;
+       struct rpc_xprt *ret;
 
        xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries);
        if (IS_ERR(xprt))
@@ -2330,8 +2331,8 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
                xs_format_peer_addresses(xprt, "udp", RPCBIND_NETID_UDP6);
                break;
        default:
-               kfree(xprt);
-               return ERR_PTR(-EAFNOSUPPORT);
+               ret = ERR_PTR(-EAFNOSUPPORT);
+               goto out_err;
        }
 
        if (xprt_bound(xprt))
@@ -2346,10 +2347,11 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
 
        if (try_module_get(THIS_MODULE))
                return xprt;
-
+       ret = ERR_PTR(-EINVAL);
+out_err:
        kfree(xprt->slot);
        kfree(xprt);
-       return ERR_PTR(-EINVAL);
+       return ret;
 }
 
 static const struct rpc_timeout xs_tcp_default_timeout = {
@@ -2368,6 +2370,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
        struct sockaddr *addr = args->dstaddr;
        struct rpc_xprt *xprt;
        struct sock_xprt *transport;
+       struct rpc_xprt *ret;
 
        xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
        if (IS_ERR(xprt))
@@ -2403,8 +2406,8 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
                xs_format_peer_addresses(xprt, "tcp", RPCBIND_NETID_TCP6);
                break;
        default:
-               kfree(xprt);
-               return ERR_PTR(-EAFNOSUPPORT);
+               ret = ERR_PTR(-EAFNOSUPPORT);
+               goto out_err;
        }
 
        if (xprt_bound(xprt))
@@ -2420,10 +2423,11 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
 
        if (try_module_get(THIS_MODULE))
                return xprt;
-
+       ret = ERR_PTR(-EINVAL);
+out_err:
        kfree(xprt->slot);
        kfree(xprt);
-       return ERR_PTR(-EINVAL);
+       return ret;
 }
 
 /**
@@ -2437,6 +2441,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
        struct rpc_xprt *xprt;
        struct sock_xprt *transport;
        struct svc_sock *bc_sock;
+       struct rpc_xprt *ret;
 
        xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
        if (IS_ERR(xprt))
@@ -2476,8 +2481,8 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
                                   RPCBIND_NETID_TCP6);
                break;
        default:
-               kfree(xprt);
-               return ERR_PTR(-EAFNOSUPPORT);
+               ret = ERR_PTR(-EAFNOSUPPORT);
+               goto out_err;
        }
 
        if (xprt_bound(xprt))
@@ -2499,9 +2504,11 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
 
        if (try_module_get(THIS_MODULE))
                return xprt;
+       ret = ERR_PTR(-EINVAL);
+out_err:
        kfree(xprt->slot);
        kfree(xprt);
-       return ERR_PTR(-EINVAL);
+       return ret;
 }
 
 static struct xprt_class       xs_udp_transport = {
index 76af5f9623e3a41027e20c68fcd21610529bf4b4..a932ae52f921b5967b705432d0ef972f60c73c24 100644 (file)
@@ -242,6 +242,7 @@ case "$arg" in
                echo "$output_file" | grep -q "\.gz$" && compr="gzip -9 -f"
                echo "$output_file" | grep -q "\.bz2$" && compr="bzip2 -9 -f"
                echo "$output_file" | grep -q "\.lzma$" && compr="lzma -9 -f"
+               echo "$output_file" | grep -q "\.lzo$" && compr="lzop -9 -f"
                echo "$output_file" | grep -q "\.cpio$" && compr="cat"
                shift
                ;;
index 5d4402a1161aba1110108ece6b6161793746c55b..38783dcf6c61fb6e380131c40c8abbbf1414a5dd 100644 (file)
@@ -124,6 +124,7 @@ extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check);
 extern int install_user_keyrings(void);
 extern int install_thread_keyring_to_cred(struct cred *);
 extern int install_process_keyring_to_cred(struct cred *);
+extern int install_session_keyring_to_cred(struct cred *, struct key *);
 
 extern struct key *request_key_and_link(struct key_type *type,
                                        const char *description,
index 8f4dce1987c492c59a9e2a6870b1bebaeaac09a8..13074b4547433ab20929fa493114b507c9e4389f 100644 (file)
@@ -1269,7 +1269,7 @@ long keyctl_session_to_parent(void)
                goto not_permitted;
 
        /* the parent must be single threaded */
-       if (atomic_read(&parent->signal->count) != 1)
+       if (!thread_group_empty(parent))
                goto not_permitted;
 
        /* the parent and the child must have different session keyrings or
index 20a38fed61b1efb812799bc83ff31db78c1411ac..6b8e4ff4cc68cfebe2bb845dda44d8d4b8542635 100644 (file)
@@ -216,8 +216,7 @@ static int install_process_keyring(void)
 /*
  * install a session keyring directly to a credentials struct
  */
-static int install_session_keyring_to_cred(struct cred *cred,
-                                          struct key *keyring)
+int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
 {
        unsigned long flags;
        struct key *old;
index f656e9c069e3ec31f64d8a4a2ec9d9add862a4cb..f5ec9ac5d57cf6af80f90eb90427ecb98385ae4f 100644 (file)
@@ -58,6 +58,38 @@ void complete_request_key(struct key_construction *cons, int error)
 }
 EXPORT_SYMBOL(complete_request_key);
 
+static int umh_keys_init(struct subprocess_info *info)
+{
+       struct cred *cred = (struct cred*)current_cred();
+       struct key *keyring = info->data;
+       /*
+        * This is called in context of freshly forked kthread before
+        * kernel_execve(), we can just change our ->session_keyring.
+        */
+       return install_session_keyring_to_cred(cred, keyring);
+}
+
+static void umh_keys_cleanup(struct subprocess_info *info)
+{
+       struct key *keyring = info->data;
+       key_put(keyring);
+}
+
+static int call_usermodehelper_keys(char *path, char **argv, char **envp,
+                        struct key *session_keyring, enum umh_wait wait)
+{
+       gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
+       struct subprocess_info *info =
+               call_usermodehelper_setup(path, argv, envp, gfp_mask);
+
+       if (!info)
+               return -ENOMEM;
+
+       call_usermodehelper_setfns(info, umh_keys_init, umh_keys_cleanup,
+                                       key_get(session_keyring));
+       return call_usermodehelper_exec(info, wait);
+}
+
 /*
  * request userspace finish the construction of a key
  * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
index a2ff86189d2a583ad208c8e61beed816d3f23a67..e9d98be190c58db786c53ea8adc9770bd808d5ec 100644 (file)
@@ -345,7 +345,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                new_hw_ptr = hw_base + pos;
        }
       __delta:
-       delta = (new_hw_ptr - old_hw_ptr) % runtime->boundary;
+       delta = new_hw_ptr - old_hw_ptr;
+       if (delta < 0)
+               delta += runtime->boundary;
        if (xrun_debug(substream, in_interrupt ?
                        XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
                char name[16];
@@ -439,8 +441,13 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
                snd_pcm_playback_silence(substream, new_hw_ptr);
 
        if (in_interrupt) {
-               runtime->hw_ptr_interrupt = new_hw_ptr -
-                               (new_hw_ptr % runtime->period_size);
+               delta = new_hw_ptr - runtime->hw_ptr_interrupt;
+               if (delta < 0)
+                       delta += runtime->boundary;
+               delta -= (snd_pcm_uframes_t)delta % runtime->period_size;
+               runtime->hw_ptr_interrupt += delta;
+               if (runtime->hw_ptr_interrupt >= runtime->boundary)
+                       runtime->hw_ptr_interrupt -= runtime->boundary;
        }
        runtime->hw_ptr_base = hw_base;
        runtime->status->hw_ptr = new_hw_ptr;
index 644c2bb17b86270e3c7fd88307858095470b1bb4..303ac04ff6e427066bf95fe0932361efd7a94ea3 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/pm_qos_params.h>
 #include <linux/uio.h>
 #include <linux/dma-mapping.h>
-#include <linux/math64.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -370,38 +369,6 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
        return usecs;
 }
 
-static int calc_boundary(struct snd_pcm_runtime *runtime)
-{
-       u_int64_t boundary;
-
-       boundary = (u_int64_t)runtime->buffer_size *
-                  (u_int64_t)runtime->period_size;
-#if BITS_PER_LONG < 64
-       /* try to find lowest common multiple for buffer and period */
-       if (boundary > LONG_MAX - runtime->buffer_size) {
-               u_int32_t remainder = -1;
-               u_int32_t divident = runtime->buffer_size;
-               u_int32_t divisor = runtime->period_size;
-               while (remainder) {
-                       remainder = divident % divisor;
-                       if (remainder) {
-                               divident = divisor;
-                               divisor = remainder;
-                       }
-               }
-               boundary = div_u64(boundary, divisor);
-               if (boundary > LONG_MAX - runtime->buffer_size)
-                       return -ERANGE;
-       }
-#endif
-       if (boundary == 0)
-               return -ERANGE;
-       runtime->boundary = boundary;
-       while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
-               runtime->boundary *= 2;
-       return 0;
-}
-
 static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
 {
@@ -477,9 +444,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        runtime->stop_threshold = runtime->buffer_size;
        runtime->silence_threshold = 0;
        runtime->silence_size = 0;
-       err = calc_boundary(runtime);
-       if (err < 0)
-               goto _error;
+       runtime->boundary = runtime->buffer_size;
+       while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
+               runtime->boundary *= 2;
 
        snd_pcm_timer_resolution_change(substream);
        runtime->status->state = SNDRV_PCM_STATE_SETUP;
index 67921f93a41e08eefc0a2899537d6a5fe071a4e7..c15002242d98863f945fc026e6c3feb49768aace 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
@@ -44,9 +44,6 @@ MODULE_LICENSE("GPL");
 /*********************************
  * DEFINES
  ********************************/
-#define PCI_VENDOR_ID_SAA7146            0x1131
-#define PCI_DEVICE_ID_SAA7146            0x7146
-
 #define CTL_ROUTE_ANALOG 0
 #define CTL_ROUTE_DIGITAL 1
 
@@ -165,7 +162,7 @@ module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard.");
 
 static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = {
-       {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0,
+       {PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0, 0,
         0, 0, 0},
        {0}
 };
@@ -419,7 +416,7 @@ static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       snd_printdd(KERN_DEBUG "aw2: Playback_open \n");
+       snd_printdd(KERN_DEBUG "aw2: Playback_open\n");
        runtime->hw = snd_aw2_playback_hw;
        return 0;
 }
@@ -435,7 +432,7 @@ static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
 
-       snd_printdd(KERN_DEBUG "aw2: Capture_open \n");
+       snd_printdd(KERN_DEBUG "aw2: Capture_open\n");
        runtime->hw = snd_aw2_capture_hw;
        return 0;
 }
index 4b302d86f5f26dbd547c8af4f9dc1705440f5b18..7a9401462c1c698a0a8f21e2135a613d1efb5a0b 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
+#include <linux/moduleparam.h>
 
 #include <sound/core.h>
 #include <sound/tlv.h>
 #define EMU10K1_CENTER_LFE_FROM_FRONT
 #endif
 
+static bool high_res_gpr_volume;
+module_param(high_res_gpr_volume, bool, 0444);
+MODULE_PARM_DESC(high_res_gpr_volume, "GPR mixer controls use 31-bit range.");
+
 /*
  *  Tables
  */ 
@@ -296,6 +301,7 @@ static const u32 db_table[101] = {
 
 /* EMU10k1/EMU10k2 DSP control db gain */
 static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
+static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0);
 
 static const u32 onoff_table[2] = {
        0x00000000, 0x00000001
@@ -1072,10 +1078,17 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
        strcpy(ctl->id.name, name);
        ctl->vcount = ctl->count = 1;
        ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
-       ctl->min = 0;
-       ctl->max = 100;
-       ctl->tlv = snd_emu10k1_db_scale1;
-       ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;    
+       if (high_res_gpr_volume) {
+               ctl->min = 0;
+               ctl->max = 0x7fffffff;
+               ctl->tlv = snd_emu10k1_db_linear;
+               ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
+       } else {
+               ctl->min = 0;
+               ctl->max = 100;
+               ctl->tlv = snd_emu10k1_db_scale1;
+               ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+       }
 }
 
 static void __devinit
@@ -1087,10 +1100,17 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
        ctl->vcount = ctl->count = 2;
        ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
        ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
-       ctl->min = 0;
-       ctl->max = 100;
-       ctl->tlv = snd_emu10k1_db_scale1;
-       ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+       if (high_res_gpr_volume) {
+               ctl->min = 0;
+               ctl->max = 0x7fffffff;
+               ctl->tlv = snd_emu10k1_db_linear;
+               ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
+       } else {
+               ctl->min = 0;
+               ctl->max = 100;
+               ctl->tlv = snd_emu10k1_db_scale1;
+               ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
+       }
 }
 
 static void __devinit
index 170610e1d7da4d8a2a89bf46ae01085743dee840..77e22c2a8caa66f9e1e2547ce8a61cc3ce6fd967 100644 (file)
@@ -1097,6 +1097,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        struct azx *chip = dev_id;
        struct azx_dev *azx_dev;
        u32 status;
+       u8 sd_status;
        int i, ok;
 
        spin_lock(&chip->reg_lock);
@@ -1110,8 +1111,10 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
        for (i = 0; i < chip->num_streams; i++) {
                azx_dev = &chip->azx_dev[i];
                if (status & azx_dev->sd_int_sta_mask) {
+                       sd_status = azx_sd_readb(azx_dev, SD_STS);
                        azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
-                       if (!azx_dev->substream || !azx_dev->running)
+                       if (!azx_dev->substream || !azx_dev->running ||
+                           !(sd_status & SD_INT_COMPLETE))
                                continue;
                        /* check whether this IRQ is really acceptable */
                        ok = azx_position_ok(chip, azx_dev);
@@ -2279,12 +2282,14 @@ static int azx_dev_free(struct snd_device *device)
  * white/black-listing for position_fix
  */
 static struct snd_pci_quirk position_fix_list[] __devinitdata = {
+       SND_PCI_QUIRK(0x1025, 0x009f, "Acer Aspire 5110", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
index 53538b0f999129ad66937f617a168679e3598aaf..17d4548cc353f72402693b0b39461226467a00d9 100644 (file)
@@ -7025,6 +7025,14 @@ static struct hda_input_mux alc889A_mb31_capture_source = {
        },
 };
 
+static struct hda_input_mux alc889A_imac91_capture_source = {
+       .num_items = 2,
+       .items = {
+               { "Mic", 0x01 },
+               { "Line", 0x2 }, /* Not sure! */
+       },
+};
+
 /*
  * 2ch mode
  */
@@ -7486,15 +7494,8 @@ static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
 };
 
 static struct snd_kcontrol_new alc885_imac91_mixer[] = {
-       HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
-       HDA_BIND_MUTE   ("Line-Out Playback Switch", 0x0c, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_MUTE  ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
-       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
        { } /* end */
 };
 
@@ -7995,61 +7996,56 @@ static struct hda_verb alc885_mbp3_init_verbs[] = {
 
 /* iMac 9,1 */
 static struct hda_verb alc885_imac91_init_verbs[] = {
-       /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* Rear mixer */
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       /* HP Pin: output 0 (0x0c) */
+       /* Internal Speaker Pin (0x0c) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* HP Pin: Rear */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
-       /* Internal Speakers: output 0 (0x0d) */
-       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
+       /* Line in Rear */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
        {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* Mic (rear) pin: input vref at 80% */
-       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
-       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
        /* Front Mic pin: input vref at 80% */
        {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
        {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       /* Line In pin: use output 1 when in LineOut mode */
-       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
-
-       /* FIXME: use matrix-type input source selection */
-       /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
-       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       /* Rear mixer */
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
        {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
        {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
        {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Input mixer2 */
+       /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
        {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* Input mixer3 */
+       /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
        {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
-       /* ADC1: mute amp left and right */
+       /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* ADC2: mute amp left and right */
+       /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
        {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* ADC3: mute amp left and right */
+       /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
        {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
-
        { }
 };
 
@@ -8118,7 +8114,7 @@ static void alc885_imac91_setup(struct hda_codec *codec)
        struct alc_spec *spec = codec->spec;
 
        spec->autocfg.hp_pins[0] = 0x14;
-       spec->autocfg.speaker_pins[0] = 0x15;
+       spec->autocfg.speaker_pins[0] = 0x18;
        spec->autocfg.speaker_pins[1] = 0x1a;
 }
 
@@ -9627,14 +9623,14 @@ static struct alc_config_preset alc882_presets[] = {
                .init_hook = alc885_imac24_init_hook,
        },
        [ALC885_IMAC91] = {
-               .mixers = { alc885_imac91_mixer, alc882_chmode_mixer },
+               .mixers = {alc885_imac91_mixer},
                .init_verbs = { alc885_imac91_init_verbs,
                                alc880_gpio1_init_verbs },
                .num_dacs = ARRAY_SIZE(alc882_dac_nids),
                .dac_nids = alc882_dac_nids,
-               .channel_mode = alc885_mbp_4ch_modes,
-               .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
-               .input_mux = &alc882_capture_source,
+               .channel_mode = alc885_mba21_ch_modes,
+               .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
+               .input_mux = &alc889A_imac91_capture_source,
                .dig_out_nid = ALC882_DIGOUT_NID,
                .dig_in_nid = ALC882_DIGIN_NID,
                .unsol_event = alc_automute_amp_unsol_event,
index a0e06d82da1f8c27d50d8a2b1fd5d75927db4ca9..f1e7babd6920048b5238b21e5a31ee936ab4b3a0 100644 (file)
@@ -2078,12 +2078,12 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2000,
                           "Intel D965", STAC_D965_3ST),
        /* Dell 3 stack systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01ed, "Dell     ", STAC_DELL_3ST),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f4, "Dell     ", STAC_DELL_3ST),
        /* Dell 3 stack systems with verb table in BIOS */
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0227, "Dell Vostro 1400  ", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022e, "Dell     ", STAC_DELL_BIOS),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS),
index 8bbfbfd4c65805dd3087e96631c07f5385db50b5..dcb620796d9ef5c14ba7f52ab3686b1ae0c1969a 100644 (file)
@@ -171,7 +171,7 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
                input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8)  | buf[5]);
                input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]);
                input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8)  | buf[3]);
-               input_report_abs(input_dev, ABS_HAT2X, (buf[15] << 8) | buf[15]);
+               input_report_abs(input_dev, ABS_HAT2X, (buf[14] << 8) | buf[15]);
                input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8)  | buf[1]);
                input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]);
                input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8)  | buf[7]);
index 8b1e4b124a9f65281fa3bf488c5f17f7c5c34a35..46785643c66dfa507bd41bb8f1368bdba75afd93 100644 (file)
@@ -644,6 +644,105 @@ static struct usb_protocol_ops snd_usbmidi_cme_ops = {
        .output_packet = snd_usbmidi_output_standard_packet,
 };
 
+/*
+ * AKAI MPD16 protocol:
+ *
+ * For control port (endpoint 1):
+ * ==============================
+ * One or more chunks consisting of first byte of (0x10 | msg_len) and then a
+ * SysEx message (msg_len=9 bytes long).
+ *
+ * For data port (endpoint 2):
+ * ===========================
+ * One or more chunks consisting of first byte of (0x20 | msg_len) and then a
+ * MIDI message (msg_len bytes long)
+ *
+ * Messages sent: Active Sense, Note On, Poly Pressure, Control Change.
+ */
+static void snd_usbmidi_akai_input(struct snd_usb_midi_in_endpoint *ep,
+                                  uint8_t *buffer, int buffer_length)
+{
+       unsigned int pos = 0;
+       unsigned int len = (unsigned int)buffer_length;
+       while (pos < len) {
+               unsigned int port = (buffer[pos] >> 4) - 1;
+               unsigned int msg_len = buffer[pos] & 0x0f;
+               pos++;
+               if (pos + msg_len <= len && port < 2)
+                       snd_usbmidi_input_data(ep, 0, &buffer[pos], msg_len);
+               pos += msg_len;
+       }
+}
+
+#define MAX_AKAI_SYSEX_LEN 9
+
+static void snd_usbmidi_akai_output(struct snd_usb_midi_out_endpoint *ep,
+                                   struct urb *urb)
+{
+       uint8_t *msg;
+       int pos, end, count, buf_end;
+       uint8_t tmp[MAX_AKAI_SYSEX_LEN];
+       struct snd_rawmidi_substream *substream = ep->ports[0].substream;
+
+       if (!ep->ports[0].active)
+               return;
+
+       msg = urb->transfer_buffer + urb->transfer_buffer_length;
+       buf_end = ep->max_transfer - MAX_AKAI_SYSEX_LEN - 1;
+
+       /* only try adding more data when there's space for at least 1 SysEx */
+       while (urb->transfer_buffer_length < buf_end) {
+               count = snd_rawmidi_transmit_peek(substream,
+                                                 tmp, MAX_AKAI_SYSEX_LEN);
+               if (!count) {
+                       ep->ports[0].active = 0;
+                       return;
+               }
+               /* try to skip non-SysEx data */
+               for (pos = 0; pos < count && tmp[pos] != 0xF0; pos++)
+                       ;
+
+               if (pos > 0) {
+                       snd_rawmidi_transmit_ack(substream, pos);
+                       continue;
+               }
+
+               /* look for the start or end marker */
+               for (end = 1; end < count && tmp[end] < 0xF0; end++)
+                       ;
+
+               /* next SysEx started before the end of current one */
+               if (end < count && tmp[end] == 0xF0) {
+                       /* it's incomplete - drop it */
+                       snd_rawmidi_transmit_ack(substream, end);
+                       continue;
+               }
+               /* SysEx complete */
+               if (end < count && tmp[end] == 0xF7) {
+                       /* queue it, ack it, and get the next one */
+                       count = end + 1;
+                       msg[0] = 0x10 | count;
+                       memcpy(&msg[1], tmp, count);
+                       snd_rawmidi_transmit_ack(substream, count);
+                       urb->transfer_buffer_length += count + 1;
+                       msg += count + 1;
+                       continue;
+               }
+               /* less than 9 bytes and no end byte - wait for more */
+               if (count < MAX_AKAI_SYSEX_LEN) {
+                       ep->ports[0].active = 0;
+                       return;
+               }
+               /* 9 bytes and no end marker in sight - malformed, skip it */
+               snd_rawmidi_transmit_ack(substream, count);
+       }
+}
+
+static struct usb_protocol_ops snd_usbmidi_akai_ops = {
+       .input = snd_usbmidi_akai_input,
+       .output = snd_usbmidi_akai_output,
+};
+
 /*
  * Novation USB MIDI protocol: number of data bytes is in the first byte
  * (when receiving) (+1!) or in the second byte (when sending); data begins
@@ -1434,6 +1533,11 @@ static struct port_info {
        EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"),
        EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"),
        EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"),
+       /* Akai MPD16 */
+       CONTROL_PORT(0x09e8, 0x0062, 0, "%s Control"),
+       PORT_INFO(0x09e8, 0x0062, 1, "%s MIDI", 0,
+               SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
+               SNDRV_SEQ_PORT_TYPE_HARDWARE),
        /* Access Music Virus TI */
        EXTERNAL_PORT(0x133e, 0x0815, 0, "%s MIDI"),
        PORT_INFO(0x133e, 0x0815, 1, "%s Synth", 0,
@@ -2035,6 +2139,12 @@ int snd_usbmidi_create(struct snd_card *card,
                umidi->usb_protocol_ops = &snd_usbmidi_cme_ops;
                err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
                break;
+       case QUIRK_MIDI_AKAI:
+               umidi->usb_protocol_ops = &snd_usbmidi_akai_ops;
+               err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
+               /* endpoint 1 is input-only */
+               endpoints[1].out_cables = 0;
+               break;
        default:
                snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
                err = -ENXIO;
index 2089ec987c66f17fcefac5259ed0c750e5735247..2fca80b744c0a5476d191512e3e909fa744f8d77 100644 (file)
@@ -37,6 +37,8 @@ struct snd_usb_midi_endpoint_info {
 
 /* for QUIRK_MIDI_CME, data is NULL */
 
+/* for QUIRK_MIDI_AKAI, data is NULL */
+
 int snd_usbmidi_create(struct snd_card *card,
                       struct usb_interface *iface,
                       struct list_head *midi_list,
index 91ddef31bcbddc5fa512134890ee2e36846dfa3f..f8797f61a24b52d8091f2a20b12b243f458b3865 100644 (file)
@@ -1973,6 +1973,17 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
 
+/* AKAI devices */
+{
+       USB_DEVICE(0x09e8, 0x0062),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "AKAI",
+               .product_name = "MPD16",
+               .ifnum = 0,
+               .type = QUIRK_MIDI_AKAI,
+       }
+},
+
 /* TerraTec devices */
 {
        USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012),
index 136e5b4cf6de4fda961a9f1d61c8543d1069bd76..b45e54c09ba2d91dd4c14432f4f8b246ca6fedbf 100644 (file)
@@ -289,6 +289,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
                [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk,
                [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
                [QUIRK_MIDI_CME] = create_any_midi_quirk,
+               [QUIRK_MIDI_AKAI] = create_any_midi_quirk,
                [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
                [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
                [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
index d679e72a3e5c921184fbea1d0cbffc94393b176b..06ebf24d3a4d504e61840f5abca7a30a87b5d5e1 100644 (file)
@@ -74,6 +74,7 @@ enum quirk_type {
        QUIRK_MIDI_FASTLANE,
        QUIRK_MIDI_EMAGIC,
        QUIRK_MIDI_CME,
+       QUIRK_MIDI_AKAI,
        QUIRK_MIDI_US122L,
        QUIRK_AUDIO_STANDARD_INTERFACE,
        QUIRK_AUDIO_FIXED_ENDPOINT,
index 1e6a9e4a72cc627fb4d0e4863dabdbc15f709274..6b4b6da0b67d948d8b027622a486a3e1d8b49bc1 100644 (file)
@@ -15,6 +15,9 @@ suffix_$(CONFIG_INITRAMFS_COMPRESSION_BZIP2)  = .bz2
 # Lzma
 suffix_$(CONFIG_INITRAMFS_COMPRESSION_LZMA)   = .lzma
 
+# Lzo
+suffix_$(CONFIG_INITRAMFS_COMPRESSION_LZO)   = .lzo
+
 # Generate builtin.o based on initramfs_data.o
 obj-$(CONFIG_BLK_DEV_INITRD) := initramfs_data$(suffix_y).o
 
@@ -45,7 +48,7 @@ endif
 quiet_cmd_initfs = GEN     $@
       cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input)
 
-targets := initramfs_data.cpio.gz initramfs_data.cpio.bz2 initramfs_data.cpio.lzma initramfs_data.cpio
+targets := initramfs_data.cpio.gz initramfs_data.cpio.bz2 initramfs_data.cpio.lzma initramfs_data.cpio.lzo initramfs_data.cpio
 # do not try to update files included in initramfs
 $(deps_initramfs): ;
 
diff --git a/usr/initramfs_data.lzo.S b/usr/initramfs_data.lzo.S
new file mode 100644 (file)
index 0000000..5921190
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+  initramfs_data includes the compressed binary that is the
+  filesystem used for early user space.
+  Note: Older versions of "as" (prior to binutils 2.11.90.0.23
+  released on 2001-07-14) dit not support .incbin.
+  If you are forced to use older binutils than that then the
+  following trick can be applied to create the resulting binary:
+
+
+  ld -m elf_i386  --format binary --oformat elf32-i386 -r \
+  -T initramfs_data.scr initramfs_data.cpio.gz -o initramfs_data.o
+   ld -m elf_i386  -r -o built-in.o initramfs_data.o
+
+  initramfs_data.scr looks like this:
+SECTIONS
+{
+       .init.ramfs : { *(.data) }
+}
+
+  The above example is for i386 - the parameters vary from architectures.
+  Eventually look up LDFLAGS_BLOB in an older version of the
+  arch/$(ARCH)/Makefile to see the flags used before .incbin was introduced.
+
+  Using .incbin has the advantage over ld that the correct flags are set
+  in the ELF header, as required by certain architectures.
+*/
+
+.section .init.ramfs,"a"
+.incbin "usr/initramfs_data.cpio.lzo"