Merge branch 'for-2.6.37' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 Nov 2010 15:59:41 +0000 (07:59 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 12 Nov 2010 15:59:41 +0000 (07:59 -0800)
* 'for-2.6.37' of git://linux-nfs.org/~bfields/linux:
  locks: remove dead lease error-handling code
  locks: fix leak on merging leases
  nfsd4: fix 4.1 connection registration race

263 files changed:
Documentation/ABI/obsolete/proc-pid-oom_adj [new file with mode: 0644]
Documentation/leds-class.txt
Documentation/leds/leds-lp5521.txt [new file with mode: 0644]
Documentation/leds/leds-lp5523.txt [new file with mode: 0644]
Documentation/sysctl/kernel.txt
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/include/mach/gpio.h
arch/arm/mach-shmobile/include/mach/sh7372.h
arch/m68k/include/asm/irqflags.h
arch/m68k/include/asm/machdep.h
arch/powerpc/kernel/kvm.c
arch/powerpc/kvm/booke_interrupts.S
arch/powerpc/kvm/e500.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/kvm/timing.c
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boards/Kconfig
arch/sh/boards/Makefile
arch/sh/boards/board-edosk7705.c [new file with mode: 0644]
arch/sh/boards/board-secureedge5410.c [moved from arch/sh/boards/mach-snapgear/setup.c with 70% similarity]
arch/sh/boards/mach-edosk7705/Makefile [deleted file]
arch/sh/boards/mach-edosk7705/io.c [deleted file]
arch/sh/boards/mach-edosk7705/setup.c [deleted file]
arch/sh/boards/mach-microdev/io.c
arch/sh/boards/mach-microdev/setup.c
arch/sh/boards/mach-se/7206/Makefile
arch/sh/boards/mach-se/7206/io.c [deleted file]
arch/sh/boards/mach-se/7206/irq.c
arch/sh/boards/mach-se/7206/setup.c
arch/sh/boards/mach-se/770x/Makefile
arch/sh/boards/mach-se/770x/io.c [deleted file]
arch/sh/boards/mach-se/770x/setup.c
arch/sh/boards/mach-se/7751/Makefile
arch/sh/boards/mach-se/7751/io.c [deleted file]
arch/sh/boards/mach-se/7751/setup.c
arch/sh/boards/mach-snapgear/Makefile [deleted file]
arch/sh/boards/mach-snapgear/io.c [deleted file]
arch/sh/boards/mach-systemh/Makefile [deleted file]
arch/sh/boards/mach-systemh/io.c [deleted file]
arch/sh/boards/mach-systemh/irq.c [deleted file]
arch/sh/boards/mach-systemh/setup.c [deleted file]
arch/sh/configs/secureedge5410_defconfig [moved from arch/sh/configs/snapgear_defconfig with 100% similarity]
arch/sh/configs/systemh_defconfig [deleted file]
arch/sh/include/asm/addrspace.h
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/system.h
arch/sh/include/asm/system_32.h
arch/sh/include/asm/system_64.h
arch/sh/include/asm/uncached.h
arch/sh/include/mach-common/mach/edosk7705.h [deleted file]
arch/sh/include/mach-common/mach/microdev.h
arch/sh/include/mach-common/mach/secureedge5410.h [moved from arch/sh/include/mach-common/mach/snapgear.h with 79% similarity]
arch/sh/include/mach-common/mach/systemh7751.h [deleted file]
arch/sh/kernel/cpu/sh4a/clock-sh7724.c
arch/sh/mm/Kconfig
arch/sh/mm/consistent.c
arch/sh/mm/uncached.c
arch/sh/tools/mach-types
arch/tile/include/asm/highmem.h
arch/tile/include/asm/kmap_types.h
arch/tile/include/asm/pgtable.h
arch/tile/include/asm/stat.h
arch/tile/include/asm/unistd.h
arch/tile/kernel/compat.c
arch/tile/kernel/early_printk.c
arch/tile/kernel/hardwall.c
arch/tile/kernel/irq.c
arch/tile/kernel/machine_kexec.c
arch/tile/kernel/messaging.c
arch/tile/kernel/ptrace.c
arch/tile/kernel/reboot.c
arch/tile/kernel/setup.c
arch/tile/kernel/signal.c
arch/tile/kernel/smp.c
arch/tile/kernel/time.c
arch/tile/lib/memcpy_tile64.c
arch/tile/mm/highmem.c
arch/tile/mm/init.c
arch/tile/mm/pgtable.c
arch/um/include/asm/ptrace-generic.h
arch/um/kernel/ptrace.c
arch/x86/kvm/mmu.c
arch/x86/kvm/x86.c
crypto/pcrypt.c
drivers/Makefile
drivers/block/floppy.c
drivers/char/Makefile
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_mtu2.c
drivers/clocksource/sh_tmu.c
drivers/firewire/ohci.c
drivers/hwmon/ltc4261.c
drivers/isdn/hisax/isar.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/led-class.c
drivers/leds/led-triggers.c
drivers/leds/leds-gpio.c
drivers/leds/leds-lp5521.c [new file with mode: 0644]
drivers/leds/leds-lp5523.c [new file with mode: 0644]
drivers/leds/leds-net5501.c
drivers/leds/ledtrig-timer.c
drivers/macintosh/adb-iop.c
drivers/misc/apds9802als.c
drivers/misc/bh1770glc.c
drivers/misc/isl29020.c
drivers/net/atlx/atl1.c
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_hsi.h
drivers/net/bnx2x/bnx2x_link.c
drivers/net/caif/caif_spi.c
drivers/net/caif/caif_spi_slave.c
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb4/cxgb4_main.c
drivers/net/cxgb4vf/cxgb4vf_main.c
drivers/net/ibm_newemac/core.c
drivers/net/jme.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/qlcnic/qlcnic_main.c
drivers/net/smsc911x.h
drivers/net/tulip/de2104x.c
drivers/net/usb/usbnet.c
drivers/net/wireless/ipw2x00/libipw_module.c
drivers/net/wireless/rt2x00/Kconfig
drivers/rapidio/rio.c
drivers/rtc/rtc-ds1302.c
drivers/sh/clk/core.c
drivers/sh/intc/core.c
drivers/sh/intc/dynamic.c
drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c
drivers/staging/ath6kl/os/linux/include/athendpack_linux.h [deleted file]
drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h [deleted file]
drivers/staging/solo6x10/solo6010-v4l2-enc.c
drivers/staging/solo6x10/solo6010-v4l2.c
drivers/tty/Makefile [new file with mode: 0644]
drivers/tty/n_gsm.c [moved from drivers/char/n_gsm.c with 100% similarity]
drivers/tty/n_hdlc.c [moved from drivers/char/n_hdlc.c with 100% similarity]
drivers/tty/n_r3964.c [moved from drivers/char/n_r3964.c with 100% similarity]
drivers/tty/n_tty.c [moved from drivers/char/n_tty.c with 100% similarity]
drivers/tty/pty.c [moved from drivers/char/pty.c with 100% similarity]
drivers/tty/sysrq.c [moved from drivers/char/sysrq.c with 100% similarity]
drivers/tty/tty_audit.c [moved from drivers/char/tty_audit.c with 100% similarity]
drivers/tty/tty_buffer.c [moved from drivers/char/tty_buffer.c with 100% similarity]
drivers/tty/tty_io.c [moved from drivers/char/tty_io.c with 100% similarity]
drivers/tty/tty_ioctl.c [moved from drivers/char/tty_ioctl.c with 100% similarity]
drivers/tty/tty_ldisc.c [moved from drivers/char/tty_ldisc.c with 100% similarity]
drivers/tty/tty_mutex.c [moved from drivers/char/tty_mutex.c with 100% similarity]
drivers/tty/tty_port.c [moved from drivers/char/tty_port.c with 100% similarity]
drivers/tty/vt/.gitignore [moved from drivers/char/.gitignore with 100% similarity]
drivers/tty/vt/Makefile [new file with mode: 0644]
drivers/tty/vt/consolemap.c [moved from drivers/char/consolemap.c with 100% similarity]
drivers/tty/vt/cp437.uni [moved from drivers/char/cp437.uni with 100% similarity]
drivers/tty/vt/defkeymap.c_shipped [moved from drivers/char/defkeymap.c_shipped with 100% similarity]
drivers/tty/vt/defkeymap.map [moved from drivers/char/defkeymap.map with 100% similarity]
drivers/tty/vt/keyboard.c [moved from drivers/char/keyboard.c with 100% similarity]
drivers/tty/vt/selection.c [moved from drivers/char/selection.c with 100% similarity]
drivers/tty/vt/vc_screen.c [moved from drivers/char/vc_screen.c with 100% similarity]
drivers/tty/vt/vt.c [moved from drivers/char/vt.c with 100% similarity]
drivers/tty/vt/vt_ioctl.c [moved from drivers/char/vt_ioctl.c with 100% similarity]
drivers/usb/gadget/u_ether.c
drivers/video/backlight/adp8860_bl.c
drivers/video/backlight/l4f00242t03.c
drivers/video/backlight/lms283gf05.c
drivers/video/backlight/mbp_nvidia_bl.c
drivers/video/backlight/pwm_bl.c
drivers/video/backlight/s6e63m0.c
fs/cifs/TODO
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/ioctl.c
fs/cifs/misc.c
fs/ext4/ext4.h
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/page-io.c
fs/ext4/super.c
fs/hugetlbfs/inode.c
fs/logfs/logfs.h
fs/openpromfs/inode.c
include/asm-generic/stat.h
include/linux/atomic.h [new file with mode: 0644]
include/linux/hardirq.h
include/linux/highmem.h
include/linux/kernel.h
include/linux/leds-lp5521.h [new file with mode: 0644]
include/linux/leds-lp5523.h [new file with mode: 0644]
include/linux/leds.h
include/linux/mmc/sh_mmcif.h
include/linux/pwm_backlight.h
include/linux/radix-tree.h
include/linux/resource.h
include/linux/sh_clk.h
include/linux/sh_timer.h
include/net/caif/caif_dev.h
include/net/caif/caif_spi.h
include/net/caif/cfcnfg.h
include/net/netlink.h
include/trace/events/ext4.h
kernel/exit.c
kernel/latencytop.c
kernel/printk.c
kernel/range.c
kernel/relay.c
kernel/sysctl.c
kernel/watchdog.c
lib/radix-tree.c
mm/filemap.c
mm/memcontrol.c
mm/mprotect.c
mm/vmscan.c
mm/vmstat.c
net/caif/caif_config_util.c
net/caif/caif_dev.c
net/caif/caif_socket.c
net/caif/cfcnfg.c
net/caif/cfctrl.c
net/caif/cfdbgl.c
net/caif/cfrfml.c
net/core/dev.c
net/ipv4/fib_lookup.h
net/ipv4/inet_diag.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/nf_nat_core.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/route.c
net/l2tp/l2tp_debugfs.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_proto.c
net/rds/loop.c
net/rds/tcp.c
net/sched/cls_cgroup.c
net/sched/em_text.c
net/x25/x25_facilities.c
net/x25/x25_in.c
scripts/kconfig/symbol.c
security/Kconfig
security/commoncap.c
sound/pci/asihpi/hpi6000.c
sound/pci/asihpi/hpi6205.c
sound/pci/asihpi/hpicmn.c
sound/pci/cs46xx/dsp_spos.c
sound/pci/hda/patch_cirrus.c
sound/pci/lx6464es/lx6464es.c
sound/pci/lx6464es/lx6464es.h
sound/pci/lx6464es/lx_core.c
sound/soc/codecs/Kconfig
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm_hubs.c
sound/soc/pxa/tosa.c
sound/soc/soc-core.c
sound/usb/mixer_quirks.c
sound/usb/pcm.c

diff --git a/Documentation/ABI/obsolete/proc-pid-oom_adj b/Documentation/ABI/obsolete/proc-pid-oom_adj
new file mode 100644 (file)
index 0000000..cf63f26
--- /dev/null
@@ -0,0 +1,22 @@
+What:  /proc/<pid>/oom_adj
+When:  August 2012
+Why:   /proc/<pid>/oom_adj allows userspace to influence the oom killer's
+       badness heuristic used to determine which task to kill when the kernel
+       is out of memory.
+
+       The badness heuristic has since been rewritten since the introduction of
+       this tunable such that its meaning is deprecated.  The value was
+       implemented as a bitshift on a score generated by the badness()
+       function that did not have any precise units of measure.  With the
+       rewrite, the score is given as a proportion of available memory to the
+       task allocating pages, so using a bitshift which grows the score
+       exponentially is, thus, impossible to tune with fine granularity.
+
+       A much more powerful interface, /proc/<pid>/oom_score_adj, was
+       introduced with the oom killer rewrite that allows users to increase or
+       decrease the badness() score linearly.  This interface will replace
+       /proc/<pid>/oom_adj.
+
+       A warning will be emitted to the kernel log if an application uses this
+       deprecated interface.  After it is printed once, future warnings will be
+       suppressed until the kernel is rebooted.
index 8fd5ca2..58b266b 100644 (file)
@@ -60,15 +60,18 @@ Hardware accelerated blink of LEDs
 
 Some LEDs can be programmed to blink without any CPU interaction. To
 support this feature, a LED driver can optionally implement the
-blink_set() function (see <linux/leds.h>). If implemented, triggers can
-attempt to use it before falling back to software timers. The blink_set()
-function should return 0 if the blink setting is supported, or -EINVAL
-otherwise, which means that LED blinking will be handled by software.
-
-The blink_set() function should choose a user friendly blinking
-value if it is called with *delay_on==0 && *delay_off==0 parameters. In
-this case the driver should give back the chosen value through delay_on
-and delay_off parameters to the leds subsystem.
+blink_set() function (see <linux/leds.h>). To set an LED to blinking,
+however, it is better to use use the API function led_blink_set(),
+as it will check and implement software fallback if necessary.
+
+To turn off blinking again, use the API function led_brightness_set()
+as that will not just set the LED brightness but also stop any software
+timers that may have been required for blinking.
+
+The blink_set() function should choose a user friendly blinking value
+if it is called with *delay_on==0 && *delay_off==0 parameters. In this
+case the driver should give back the chosen value through delay_on and
+delay_off parameters to the leds subsystem.
 
 Setting the brightness to zero with brightness_set() callback function
 should completely turn off the LED and cancel the previously programmed
diff --git a/Documentation/leds/leds-lp5521.txt b/Documentation/leds/leds-lp5521.txt
new file mode 100644 (file)
index 0000000..c4d8d15
--- /dev/null
@@ -0,0 +1,88 @@
+Kernel driver for lp5521
+========================
+
+* National Semiconductor LP5521 led driver chip
+* Datasheet: http://www.national.com/pf/LP/LP5521.html
+
+Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo
+Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com)
+
+Description
+-----------
+
+LP5521 can drive up to 3 channels. Leds can be controlled directly via
+the led class control interface. Channels have generic names:
+lp5521:channelx, where x is 0 .. 2
+
+All three channels can be also controlled using the engine micro programs.
+More details of the instructions can be found from the public data sheet.
+
+Control interface for the engines:
+x is 1 .. 3
+enginex_mode : disabled, load, run
+enginex_load : store program (visible only in engine load mode)
+
+Example (start to blink the channel 2 led):
+cd   /sys/class/leds/lp5521:channel2/device
+echo "load" > engine3_mode
+echo "037f4d0003ff6000" > engine3_load
+echo "run" > engine3_mode
+
+stop the engine:
+echo "disabled" > engine3_mode
+
+sysfs contains a selftest entry.
+The test communicates with the chip and checks that
+the clock mode is automatically set to the requested one.
+
+Each channel has its own led current settings.
+/sys/class/leds/lp5521:channel0/led_current - RW
+/sys/class/leds/lp5521:channel0/max_current - RO
+Format: 10x mA i.e 10 means 1.0 mA
+
+example platform data:
+
+Note: chan_nr can have values between 0 and 2.
+
+static struct lp5521_led_config lp5521_led_config[] = {
+        {
+                .chan_nr        = 0,
+                .led_current    = 50,
+               .max_current    = 130,
+        }, {
+                .chan_nr        = 1,
+                .led_current    = 0,
+               .max_current    = 130,
+        }, {
+                .chan_nr        = 2,
+                .led_current    = 0,
+               .max_current    = 130,
+        }
+};
+
+static int lp5521_setup(void)
+{
+       /* setup HW resources */
+}
+
+static void lp5521_release(void)
+{
+       /* Release HW resources */
+}
+
+static void lp5521_enable(bool state)
+{
+       /* Control of chip enable signal */
+}
+
+static struct lp5521_platform_data lp5521_platform_data = {
+        .led_config     = lp5521_led_config,
+        .num_channels   = ARRAY_SIZE(lp5521_led_config),
+        .clock_mode     = LP5521_CLOCK_EXT,
+        .setup_resources   = lp5521_setup,
+        .release_resources = lp5521_release,
+        .enable            = lp5521_enable,
+};
+
+If the current is set to 0 in the platform data, that channel is
+disabled and it is not visible in the sysfs.
diff --git a/Documentation/leds/leds-lp5523.txt b/Documentation/leds/leds-lp5523.txt
new file mode 100644 (file)
index 0000000..fad2feb
--- /dev/null
@@ -0,0 +1,83 @@
+Kernel driver for lp5523
+========================
+
+* National Semiconductor LP5523 led driver chip
+* Datasheet: http://www.national.com/pf/LP/LP5523.html
+
+Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo
+Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com)
+
+Description
+-----------
+LP5523 can drive up to 9 channels. Leds can be controlled directly via
+the led class control interface. Channels have generic names:
+lp5523:channelx where x is 0...8
+
+The chip provides 3 engines. Each engine can control channels without
+interaction from the main CPU. Details of the micro engine code can be found
+from the public data sheet. Leds can be muxed to different channels.
+
+Control interface for the engines:
+x is 1 .. 3
+enginex_mode : disabled, load, run
+enginex_load : microcode load (visible only in load mode)
+enginex_leds : led mux control (visible only in load mode)
+
+cd /sys/class/leds/lp5523:channel2/device
+echo "load" > engine3_mode
+echo "9d80400004ff05ff437f0000" > engine3_load
+echo "111111111" > engine3_leds
+echo "run" > engine3_mode
+
+sysfs contains a selftest entry. It measures each channel
+voltage level and checks if it looks reasonable. If the level is too high,
+the led is missing; if the level is too low, there is a short circuit.
+
+Selftest uses always the current from the platform data.
+
+Each channel contains led current settings.
+/sys/class/leds/lp5523:channel2/led_current - RW
+/sys/class/leds/lp5523:channel2/max_current - RO
+Format: 10x mA i.e 10 means 1.0 mA
+
+Example platform data:
+
+Note - chan_nr can have values between 0 and 8.
+
+static struct lp5523_led_config lp5523_led_config[] = {
+        {
+                .chan_nr        = 0,
+                .led_current    = 50,
+               .max_current    = 130,
+        },
+...
+        }, {
+                .chan_nr        = 8,
+                .led_current    = 50,
+               .max_current    = 130,
+        }
+};
+
+static int lp5523_setup(void)
+{
+       /* Setup HW resources */
+}
+
+static void lp5523_release(void)
+{
+       /* Release HW resources */
+}
+
+static void lp5523_enable(bool state)
+{
+       /* Control chip enable signal */
+}
+
+static struct lp5523_platform_data lp5523_platform_data = {
+        .led_config     = lp5523_led_config,
+        .num_channels   = ARRAY_SIZE(lp5523_led_config),
+        .clock_mode     = LP5523_CLOCK_EXT,
+        .setup_resources   = lp5523_setup,
+        .release_resources = lp5523_release,
+        .enable            = lp5523_enable,
+};
index 3894eaa..209e158 100644 (file)
@@ -28,6 +28,7 @@ show up in /proc/sys/kernel:
 - core_uses_pid
 - ctrl-alt-del
 - dentry-state
+- dmesg_restrict
 - domainname
 - hostname
 - hotplug
@@ -213,6 +214,19 @@ to decide what to do with it.
 
 ==============================================================
 
+dmesg_restrict:
+
+This toggle indicates whether unprivileged users are prevented from using
+dmesg(8) to view messages from the kernel's log buffer.  When
+dmesg_restrict is set to (0) there are no restrictions.  When
+dmesg_restrict is set set to (1), users must have CAP_SYS_ADMIN to use
+dmesg(8).
+
+The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the default
+value of dmesg_restrict.
+
+==============================================================
+
 domainname & hostname:
 
 These files can be used to set the NIS/YP domainname and the
index 54b479c..51dcd59 100644 (file)
@@ -116,4 +116,6 @@ endmenu
 config SH_CLK_CPG
        bool
 
+source "drivers/sh/Kconfig"
+
 endif
index 46ca4d4..32d9e28 100644 (file)
@@ -565,12 +565,50 @@ static struct platform_device *qhd_devices[] __initdata = {
 
 /* FSI */
 #define IRQ_FSI                evt2irq(0x1840)
+
+static int fsi_set_rate(int is_porta, int rate)
+{
+       struct clk *fsib_clk;
+       struct clk *fdiv_clk = &sh7372_fsidivb_clk;
+       int ret;
+
+       /* set_rate is not needed if port A */
+       if (is_porta)
+               return 0;
+
+       fsib_clk = clk_get(NULL, "fsib_clk");
+       if (IS_ERR(fsib_clk))
+               return -EINVAL;
+
+       switch (rate) {
+       case 48000:
+               clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 85428000));
+               clk_set_rate(fdiv_clk, clk_round_rate(fdiv_clk, 12204000));
+               ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
+               break;
+       default:
+               pr_err("unsupported rate in FSI2 port B\n");
+               ret = -EINVAL;
+               break;
+       }
+
+       clk_put(fsib_clk);
+
+       return ret;
+}
+
 static struct sh_fsi_platform_info fsi_info = {
        .porta_flags = SH_FSI_BRS_INV |
                       SH_FSI_OUT_SLAVE_MODE |
                       SH_FSI_IN_SLAVE_MODE |
                       SH_FSI_OFMT(PCM) |
                       SH_FSI_IFMT(PCM),
+
+       .portb_flags = SH_FSI_BRS_INV |
+                      SH_FSI_BRM_INV |
+                      SH_FSI_LRS_INV |
+                      SH_FSI_OFMT(SPDIF),
+       .set_rate = fsi_set_rate,
 };
 
 static struct resource fsi_resources[] = {
@@ -634,6 +672,7 @@ static struct platform_device lcdc1_device = {
 static struct sh_mobile_hdmi_info hdmi_info = {
        .lcd_chan = &sh_mobile_lcdc1_info.ch[0],
        .lcd_dev = &lcdc1_device.dev,
+       .flags = HDMI_SND_SRC_SPDIF,
 };
 
 static struct resource hdmi_resources[] = {
@@ -992,6 +1031,7 @@ static void __init ap4evb_map_io(void)
 
 #define GPIO_PORT9CR   0xE6051009
 #define GPIO_PORT10CR  0xE605100A
+#define USCCR1         0xE6058144
 static void __init ap4evb_init(void)
 {
        u32 srcr4;
@@ -1062,7 +1102,7 @@ static void __init ap4evb_init(void)
        /* setup USB phy */
        __raw_writew(0x8a0a, 0xE6058130);       /* USBCR2 */
 
-       /* enable FSI2 */
+       /* enable FSI2 port A (ak4643) */
        gpio_request(GPIO_FN_FSIAIBT,   NULL);
        gpio_request(GPIO_FN_FSIAILR,   NULL);
        gpio_request(GPIO_FN_FSIAISLD,  NULL);
@@ -1079,6 +1119,10 @@ static void __init ap4evb_init(void)
        gpio_request(GPIO_PORT41, NULL);
        gpio_direction_input(GPIO_PORT41);
 
+       /* setup FSI2 port B (HDMI) */
+       gpio_request(GPIO_FN_FSIBCK, NULL);
+       __raw_writew(__raw_readw(USCCR1) & ~(1 << 6), USCCR1); /* use SPDIF */
+
        /* set SPU2 clock to 119.6 MHz */
        clk = clk_get(NULL, "spu_clk");
        if (!IS_ERR(clk)) {
index 8565aef..7db31e6 100644 (file)
@@ -50,6 +50,9 @@
 #define SMSTPCR3       0xe615013c
 #define SMSTPCR4       0xe6150140
 
+#define FSIDIVA                0xFE1F8000
+#define FSIDIVB                0xFE1F8008
+
 /* Platforms must set frequency on their DV_CLKI pin */
 struct clk sh7372_dv_clki_clk = {
 };
@@ -288,6 +291,7 @@ struct clk sh7372_pllc2_clk = {
        .ops            = &pllc2_clk_ops,
        .parent         = &extal1_div2_clk,
        .freq_table     = pllc2_freq_table,
+       .nr_freqs       = ARRAY_SIZE(pllc2_freq_table) - 1,
        .parent_table   = pllc2_parent,
        .parent_num     = ARRAY_SIZE(pllc2_parent),
 };
@@ -417,6 +421,101 @@ static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
                                      fsibckcr_parent, ARRAY_SIZE(fsibckcr_parent), 6, 2),
 };
 
+/* FSI DIV */
+static unsigned long fsidiv_recalc(struct clk *clk)
+{
+       unsigned long value;
+
+       value = __raw_readl(clk->mapping->base);
+
+       if ((value & 0x3) != 0x3)
+               return 0;
+
+       value >>= 16;
+       if (value < 2)
+               return 0;
+
+       return clk->parent->rate / value;
+}
+
+static long fsidiv_round_rate(struct clk *clk, unsigned long rate)
+{
+       return clk_rate_div_range_round(clk, 2, 0xffff, rate);
+}
+
+static void fsidiv_disable(struct clk *clk)
+{
+       __raw_writel(0, clk->mapping->base);
+}
+
+static int fsidiv_enable(struct clk *clk)
+{
+       unsigned long value;
+
+       value  = __raw_readl(clk->mapping->base) >> 16;
+       if (value < 2) {
+               fsidiv_disable(clk);
+               return -ENOENT;
+       }
+
+       __raw_writel((value << 16) | 0x3, clk->mapping->base);
+
+       return 0;
+}
+
+static int fsidiv_set_rate(struct clk *clk,
+                          unsigned long rate, int algo_id)
+{
+       int idx;
+
+       if (clk->parent->rate == rate) {
+               fsidiv_disable(clk);
+               return 0;
+       }
+
+       idx = (clk->parent->rate / rate) & 0xffff;
+       if (idx < 2)
+               return -ENOENT;
+
+       __raw_writel(idx << 16, clk->mapping->base);
+       return fsidiv_enable(clk);
+}
+
+static struct clk_ops fsidiv_clk_ops = {
+       .recalc         = fsidiv_recalc,
+       .round_rate     = fsidiv_round_rate,
+       .set_rate       = fsidiv_set_rate,
+       .enable         = fsidiv_enable,
+       .disable        = fsidiv_disable,
+};
+
+static struct clk_mapping sh7372_fsidiva_clk_mapping = {
+       .phys   = FSIDIVA,
+       .len    = 8,
+};
+
+struct clk sh7372_fsidiva_clk = {
+       .ops            = &fsidiv_clk_ops,
+       .parent         = &div6_reparent_clks[DIV6_FSIA], /* late install */
+       .mapping        = &sh7372_fsidiva_clk_mapping,
+};
+
+static struct clk_mapping sh7372_fsidivb_clk_mapping = {
+       .phys   = FSIDIVB,
+       .len    = 8,
+};
+
+struct clk sh7372_fsidivb_clk = {
+       .ops            = &fsidiv_clk_ops,
+       .parent         = &div6_reparent_clks[DIV6_FSIB],  /* late install */
+       .mapping        = &sh7372_fsidivb_clk_mapping,
+};
+
+static struct clk *late_main_clks[] = {
+       &sh7372_fsidiva_clk,
+       &sh7372_fsidivb_clk,
+};
+
 enum { MSTP001,
        MSTP131, MSTP130,
        MSTP129, MSTP128, MSTP127, MSTP126, MSTP125,
@@ -585,6 +684,9 @@ void __init sh7372_clock_init(void)
        if (!ret)
                ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
 
+       for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++)
+               ret = clk_register(late_main_clks[k]);
+
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        if (!ret)
index 5bc6bd4..2b1bb9e 100644 (file)
@@ -35,12 +35,12 @@ static inline int gpio_cansleep(unsigned gpio)
 
 static inline int gpio_to_irq(unsigned gpio)
 {
-       return -ENOSYS;
+       return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned int irq)
 {
-       return -EINVAL;
+       return -ENOSYS;
 }
 
 #endif /* CONFIG_GPIOLIB */
index 147775a..e4f9004 100644 (file)
@@ -464,5 +464,7 @@ extern struct clk sh7372_dv_clki_div2_clk;
 extern struct clk sh7372_pllc2_clk;
 extern struct clk sh7372_fsiack_clk;
 extern struct clk sh7372_fsibck_clk;
+extern struct clk sh7372_fsidiva_clk;
+extern struct clk sh7372_fsidivb_clk;
 
 #endif /* __ASM_SH7372_H__ */
index 4a5b284..7ef4115 100644 (file)
@@ -2,7 +2,9 @@
 #define _M68K_IRQFLAGS_H
 
 #include <linux/types.h>
+#ifdef CONFIG_MMU
 #include <linux/hardirq.h>
+#endif
 #include <linux/preempt.h>
 #include <asm/thread_info.h>
 #include <asm/entry.h>
index 789f3b2..415d548 100644 (file)
@@ -40,5 +40,6 @@ extern unsigned long hw_timer_offset(void);
 extern irqreturn_t arch_timer_interrupt(int irq, void *dummy);
 
 extern void config_BSP(char *command, int len);
+extern void do_IRQ(int irq, struct pt_regs *fp);
 
 #endif /* _M68K_MACHDEP_H */
index 428d0e5..b06bdae 100644 (file)
@@ -127,7 +127,7 @@ static void kvm_patch_ins_nop(u32 *inst)
 
 static void kvm_patch_ins_b(u32 *inst, int addr)
 {
-#ifdef CONFIG_RELOCATABLE
+#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_PPC_BOOK3S)
        /* On relocatable kernels interrupts handlers and our code
           can be in different regions, so we don't patch them */
 
index 0498469..1cc471f 100644 (file)
@@ -416,7 +416,7 @@ lightweight_exit:
        lwz     r3, VCPU_PC(r4)
        mtsrr0  r3
        lwz     r3, VCPU_SHARED(r4)
-       lwz     r3, VCPU_SHARED_MSR(r3)
+       lwz     r3, (VCPU_SHARED_MSR + 4)(r3)
        oris    r3, r3, KVMPPC_MSR_MASK@h
        ori     r3, r3, KVMPPC_MSR_MASK@l
        mtsrr1  r3
index 71750f2..e3768ee 100644 (file)
@@ -138,8 +138,8 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
 
        free_page((unsigned long)vcpu->arch.shared);
-       kvmppc_e500_tlb_uninit(vcpu_e500);
        kvm_vcpu_uninit(vcpu);
+       kvmppc_e500_tlb_uninit(vcpu_e500);
        kmem_cache_free(kvm_vcpu_cache, vcpu_e500);
 }
 
index 2f87a16..38f756f 100644 (file)
@@ -617,6 +617,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
        switch (ioctl) {
        case KVM_PPC_GET_PVINFO: {
                struct kvm_ppc_pvinfo pvinfo;
+               memset(&pvinfo, 0, sizeof(pvinfo));
                r = kvm_vm_ioctl_get_pvinfo(&pvinfo);
                if (copy_to_user(argp, &pvinfo, sizeof(pvinfo))) {
                        r = -EFAULT;
index 46fa04f..a021f58 100644 (file)
@@ -35,7 +35,6 @@ void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
        int i;
 
        /* pause guest execution to avoid concurrent updates */
-       local_irq_disable();
        mutex_lock(&vcpu->mutex);
 
        vcpu->arch.last_exit_type = 0xDEAD;
@@ -51,7 +50,6 @@ void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
        vcpu->arch.timing_last_enter.tv64 = 0;
 
        mutex_unlock(&vcpu->mutex);
-       local_irq_enable();
 }
 
 static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type)
index 5c075f5..7f217b3 100644 (file)
@@ -193,6 +193,7 @@ config CPU_SH2
 config CPU_SH2A
        bool
        select CPU_SH2
+       select UNCACHED_MAPPING
 
 config CPU_SH3
        bool
index 307b3a4..9c8c6e1 100644 (file)
@@ -133,10 +133,7 @@ machdir-$(CONFIG_SOLUTION_ENGINE)          += mach-se
 machdir-$(CONFIG_SH_HP6XX)                     += mach-hp6xx
 machdir-$(CONFIG_SH_DREAMCAST)                 += mach-dreamcast
 machdir-$(CONFIG_SH_SH03)                      += mach-sh03
-machdir-$(CONFIG_SH_SECUREEDGE5410)            += mach-snapgear
 machdir-$(CONFIG_SH_RTS7751R2D)                        += mach-r2d
-machdir-$(CONFIG_SH_7751_SYSTEMH)              += mach-systemh
-machdir-$(CONFIG_SH_EDOSK7705)                 += mach-edosk7705
 machdir-$(CONFIG_SH_HIGHLANDER)                        += mach-highlander
 machdir-$(CONFIG_SH_MIGOR)                     += mach-migor
 machdir-$(CONFIG_SH_AP325RXA)                  += mach-ap325rxa
index 9c94711..2018c7e 100644 (file)
@@ -81,13 +81,6 @@ config SH_7343_SOLUTION_ENGINE
          Select 7343 SolutionEngine if configuring for a Hitachi
          SH7343 (SH-Mobile 3AS) evaluation board.
 
-config SH_7751_SYSTEMH
-       bool "SystemH7751R"
-       depends on CPU_SUBTYPE_SH7751R
-       help
-         Select SystemH if you are configuring for a Renesas SystemH
-         7751R evaluation board.
-
 config SH_HP6XX
        bool "HP6XX"
        select SYS_SUPPORTS_APM_EMULATION
index 38ef655..be7d11d 100644 (file)
@@ -2,10 +2,12 @@
 # Specific board support, not covered by a mach group.
 #
 obj-$(CONFIG_SH_MAGIC_PANEL_R2)        += board-magicpanelr2.o
+obj-$(CONFIG_SH_SECUREEDGE5410)        += board-secureedge5410.o
 obj-$(CONFIG_SH_SH2007)                += board-sh2007.o
 obj-$(CONFIG_SH_SH7785LCR)     += board-sh7785lcr.o
 obj-$(CONFIG_SH_URQUELL)       += board-urquell.o
 obj-$(CONFIG_SH_SHMIN)         += board-shmin.o
+obj-$(CONFIG_SH_EDOSK7705)     += board-edosk7705.o
 obj-$(CONFIG_SH_EDOSK7760)     += board-edosk7760.o
 obj-$(CONFIG_SH_ESPT)          += board-espt.o
 obj-$(CONFIG_SH_POLARIS)       += board-polaris.o
diff --git a/arch/sh/boards/board-edosk7705.c b/arch/sh/boards/board-edosk7705.c
new file mode 100644 (file)
index 0000000..4cb3bb7
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * arch/sh/boards/renesas/edosk7705/setup.c
+ *
+ * Copyright (C) 2000  Kazumoto Kojima
+ *
+ * Hitachi SolutionEngine Support.
+ *
+ * Modified for edosk7705 development
+ * board by S. Dunn, 2003.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/smc91x.h>
+#include <asm/machvec.h>
+#include <asm/sizes.h>
+
+#define SMC_IOBASE     0xA2000000
+#define SMC_IO_OFFSET  0x300
+#define SMC_IOADDR     (SMC_IOBASE + SMC_IO_OFFSET)
+
+#define ETHERNET_IRQ   0x09
+
+static void __init sh_edosk7705_init_irq(void)
+{
+       make_imask_irq(ETHERNET_IRQ);
+}
+
+/* eth initialization functions */
+static struct smc91x_platdata smc91x_info = {
+       .flags = SMC91X_USE_16BIT | SMC91X_IO_SHIFT_1 | IORESOURCE_IRQ_LOWLEVEL,
+};
+
+static struct resource smc91x_res[] = {
+       [0] = {
+               .start  = SMC_IOADDR,
+               .end    = SMC_IOADDR + SZ_32 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = ETHERNET_IRQ,
+               .end    = ETHERNET_IRQ,
+               .flags  = IORESOURCE_IRQ ,
+       }
+};
+
+static struct platform_device smc91x_dev = {
+       .name           = "smc91x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smc91x_res),
+       .resource       = smc91x_res,
+
+       .dev    = {
+               .platform_data  = &smc91x_info,
+       },
+};
+
+/* platform init code */
+static struct platform_device *edosk7705_devices[] __initdata = {
+       &smc91x_dev,
+};
+
+static int __init init_edosk7705_devices(void)
+{
+       return platform_add_devices(edosk7705_devices,
+                                   ARRAY_SIZE(edosk7705_devices));
+}
+__initcall(init_edosk7705_devices);
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_edosk7705 __initmv = {
+       .mv_name                = "EDOSK7705",
+       .mv_nr_irqs             = 80,
+       .mv_init_irq            = sh_edosk7705_init_irq,
+};
similarity index 70%
rename from arch/sh/boards/mach-snapgear/setup.c
rename to arch/sh/boards/board-secureedge5410.c
index 331745d..32f875e 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/arch/sh/boards/snapgear/setup.c
- *
  * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
  * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
  *
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <asm/machvec.h>
-#include <mach/snapgear.h>
+#include <mach/secureedge5410.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <cpu/timer.h>
 
+unsigned short secureedge5410_ioport;
+
 /*
  * EraseConfig handling functions
  */
-
 static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
 {
-       (void)__raw_readb(0xb8000000);  /* dummy read */
+       ctrl_delay();   /* dummy read */
 
        printk("SnapGear: erase switch interrupt!\n");
 
@@ -39,21 +38,22 @@ static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
 
 static int __init eraseconfig_init(void)
 {
+       unsigned int irq = evt2irq(0x240);
+
        printk("SnapGear: EraseConfig init\n");
+
        /* Setup "EraseConfig" switch on external IRQ 0 */
-       if (request_irq(IRL0_IRQ, eraseconfig_interrupt, IRQF_DISABLED,
+       if (request_irq(irq, eraseconfig_interrupt, IRQF_DISABLED,
                                "Erase Config", NULL))
                printk("SnapGear: failed to register IRQ%d for Reset witch\n",
-                               IRL0_IRQ);
+                               irq);
        else
                printk("SnapGear: registered EraseConfig switch on IRQ%d\n",
-                               IRL0_IRQ);
-       return(0);
+                               irq);
+       return 0;
 }
-
 module_init(eraseconfig_init);
 
-/****************************************************************************/
 /*
  * Initialize IRQ setting
  *
@@ -62,7 +62,6 @@ module_init(eraseconfig_init);
  * IRL2 = eth1
  * IRL3 = crypto
  */
-
 static void __init init_snapgear_IRQ(void)
 {
        printk("Setup SnapGear IRQ/IPR ...\n");
@@ -76,20 +75,5 @@ static void __init init_snapgear_IRQ(void)
 static struct sh_machine_vector mv_snapgear __initmv = {
        .mv_name                = "SnapGear SecureEdge5410",
        .mv_nr_irqs             = 72,
-
-       .mv_inb                 = snapgear_inb,
-       .mv_inw                 = snapgear_inw,
-       .mv_inl                 = snapgear_inl,
-       .mv_outb                = snapgear_outb,
-       .mv_outw                = snapgear_outw,
-       .mv_outl                = snapgear_outl,
-
-       .mv_inb_p               = snapgear_inb_p,
-       .mv_inw_p               = snapgear_inw,
-       .mv_inl_p               = snapgear_inl,
-       .mv_outb_p              = snapgear_outb_p,
-       .mv_outw_p              = snapgear_outw,
-       .mv_outl_p              = snapgear_outl,
-
        .mv_init_irq            = init_snapgear_IRQ,
 };
diff --git a/arch/sh/boards/mach-edosk7705/Makefile b/arch/sh/boards/mach-edosk7705/Makefile
deleted file mode 100644 (file)
index cd54acb..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the EDOSK7705 specific parts of the kernel
-#
-
-obj-y   := setup.o io.o
diff --git a/arch/sh/boards/mach-edosk7705/io.c b/arch/sh/boards/mach-edosk7705/io.c
deleted file mode 100644 (file)
index 5b9c57c..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * arch/sh/boards/renesas/edosk7705/io.c
- *
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routines for Hitachi EDOSK7705 board.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <mach/edosk7705.h>
-#include <asm/addrspace.h>
-
-#define SMC_IOADDR     0xA2000000
-
-/* Map the Ethernet addresses as if it is at 0x300 - 0x320 */
-static unsigned long sh_edosk7705_isa_port2addr(unsigned long port)
-{
-       /*
-        * SMC91C96 registers are 4 byte aligned rather than the
-        * usual 2 byte!
-        */
-       if (port >= 0x300 && port < 0x320)
-               return SMC_IOADDR + ((port - 0x300) * 2);
-
-       maybebadio(port);
-       return port;
-}
-
-/* Trying to read / write bytes on odd-byte boundaries to the Ethernet
- * registers causes problems. So we bit-shift the value and read / write
- * in 2 byte chunks. Setting the low byte to 0 does not cause problems
- * now as odd byte writes are only made on the bit mask / interrupt
- * register. This may not be the case in future Mar-2003 SJD
- */
-unsigned char sh_edosk7705_inb(unsigned long port)
-{
-       if (port >= 0x300 && port < 0x320 && port & 0x01)
-               return __raw_readw(port - 1) >> 8;
-
-       return __raw_readb(sh_edosk7705_isa_port2addr(port));
-}
-
-void sh_edosk7705_outb(unsigned char value, unsigned long port)
-{
-       if (port >= 0x300 && port < 0x320 && port & 0x01) {
-               __raw_writew(((unsigned short)value << 8), port - 1);
-               return;
-       }
-
-       __raw_writeb(value, sh_edosk7705_isa_port2addr(port));
-}
-
-void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned char *p = addr;
-
-       while (count--)
-               *p++ = sh_edosk7705_inb(port);
-}
-
-void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned char *p = (unsigned char *)addr;
-
-       while (count--)
-               sh_edosk7705_outb(*p++, port);
-}
diff --git a/arch/sh/boards/mach-edosk7705/setup.c b/arch/sh/boards/mach-edosk7705/setup.c
deleted file mode 100644 (file)
index d59225e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/sh/boards/renesas/edosk7705/setup.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SolutionEngine Support.
- *
- * Modified for edosk7705 development
- * board by S. Dunn, 2003.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <asm/machvec.h>
-#include <mach/edosk7705.h>
-
-static void __init sh_edosk7705_init_irq(void)
-{
-       /* This is the Ethernet interrupt */
-       make_imask_irq(0x09);
-}
-
-/*
- * The Machine Vector
- */
-static struct sh_machine_vector mv_edosk7705 __initmv = {
-       .mv_name                = "EDOSK7705",
-       .mv_nr_irqs             = 80,
-
-       .mv_inb                 = sh_edosk7705_inb,
-       .mv_outb                = sh_edosk7705_outb,
-
-       .mv_insb                = sh_edosk7705_insb,
-       .mv_outsb               = sh_edosk7705_outsb,
-
-       .mv_init_irq            = sh_edosk7705_init_irq,
-};
index 2960c65..acdafb0 100644 (file)
@@ -54,7 +54,7 @@
 /*
  * map I/O ports to memory-mapped addresses
  */
-static unsigned long microdev_isa_port2addr(unsigned long offset)
+void __iomem *microdev_ioport_map(unsigned long offset, unsigned int len)
 {
        unsigned long result;
 
@@ -72,16 +72,6 @@ static unsigned long microdev_isa_port2addr(unsigned long offset)
                         *      Configuration Registers
                         */
                result = IO_SUPERIO_PHYS + (offset << 1);
-#if 0
-       } else if (offset == KBD_DATA_REG || offset == KBD_CNTL_REG ||
-                  offset == KBD_STATUS_REG) {
-                       /*
-                        *      SMSC FDC37C93xAPM SuperIO chip
-                        *
-                        *      PS/2 Keyboard + Mouse (ports 0x60 and 0x64).
-                        */
-               result = IO_SUPERIO_PHYS + (offset << 1);
-#endif
        } else if (((offset >= IO_IDE1_BASE) &&
                    (offset <  IO_IDE1_BASE + IO_IDE_EXTENT)) ||
                    (offset == IO_IDE1_MISC)) {
@@ -131,237 +121,5 @@ static unsigned long microdev_isa_port2addr(unsigned long offset)
                result = PVR;
        }
 
-       return result;
-}
-
-#define PORT2ADDR(x) (microdev_isa_port2addr(x))
-
-static inline void delay(void)
-{
-#if defined(CONFIG_PCI)
-       /* System board present, just make a dummy SRAM access.  (CS0 will be
-          mapped to PCI memory, probably good to avoid it.) */
-       __raw_readw(0xa6800000);
-#else
-       /* CS0 will be mapped to flash, ROM etc so safe to access it. */
-       __raw_readw(0xa0000000);
-#endif
-}
-
-unsigned char microdev_inb(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inb(port);
-#endif
-       return *(volatile unsigned char*)PORT2ADDR(port);
-}
-
-unsigned short microdev_inw(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inw(port);
-#endif
-       return *(volatile unsigned short*)PORT2ADDR(port);
-}
-
-unsigned int microdev_inl(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inl(port);
-#endif
-       return *(volatile unsigned int*)PORT2ADDR(port);
-}
-
-void microdev_outw(unsigned short b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outw(b, port);
-               return;
-       }
-#endif
-       *(volatile unsigned short*)PORT2ADDR(port) = b;
-}
-
-void microdev_outb(unsigned char b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outb(b, port);
-               return;
-       }
-#endif
-
-       /*
-        *      There is a board feature with the current SH4-202 MicroDev in
-        *      that the 2 byte enables (nBE0 and nBE1) are tied together (and
-        *      to the Chip Select Line (Ethernet_CS)). Due to this connectivity,
-        *      it is not possible to safely perform 8-bit writes to the
-        *      Ethernet registers, as 16-bits will be consumed from the Data
-        *      lines (corrupting the other byte).  Hence, this function is
-        *      written to implement 16-bit read/modify/write for all byte-wide
-        *      accesses.
-        *
-        *      Note: there is no problem with byte READS (even or odd).
-        *
-        *                      Sean McGoogan - 16th June 2003.
-        */
-       if ((port >= IO_LAN91C111_BASE) &&
-           (port <  IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) {
-                       /*
-                        * Then are trying to perform a byte-write to the
-                        * LAN91C111.  This needs special care.
-                        */
-               if (port % 2 == 1) {    /* is the port odd ? */
-                       /* unset bit-0, i.e. make even */
-                       const unsigned long evenPort = port-1;
-                       unsigned short word;
-
-                       /*
-                        * do a 16-bit read/write to write to 'port',
-                        * preserving even byte.
-                        *
-                        *      Even addresses are bits 0-7
-                        *      Odd  addresses are bits 8-15
-                        */
-                       word = microdev_inw(evenPort);
-                       word = (word & 0xffu) | (b << 8);
-                       microdev_outw(word, evenPort);
-               } else {
-                       /* else, we are trying to do an even byte write */
-                       unsigned short word;
-
-                       /*
-                        * do a 16-bit read/write to write to 'port',
-                        * preserving odd byte.
-                        *
-                        *      Even addresses are bits 0-7
-                        *      Odd  addresses are bits 8-15
-                        */
-                       word = microdev_inw(port);
-                       word = (word & 0xff00u) | (b);
-                       microdev_outw(word, port);
-               }
-       } else {
-               *(volatile unsigned char*)PORT2ADDR(port) = b;
-       }
-}
-
-void microdev_outl(unsigned int b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outl(b, port);
-               return;
-       }
-#endif
-       *(volatile unsigned int*)PORT2ADDR(port) = b;
-}
-
-unsigned char microdev_inb_p(unsigned long port)
-{
-       unsigned char v = microdev_inb(port);
-       delay();
-       return v;
-}
-
-unsigned short microdev_inw_p(unsigned long port)
-{
-       unsigned short v = microdev_inw(port);
-       delay();
-       return v;
-}
-
-unsigned int microdev_inl_p(unsigned long port)
-{
-       unsigned int v = microdev_inl(port);
-       delay();
-       return v;
-}
-
-void microdev_outb_p(unsigned char b, unsigned long port)
-{
-       microdev_outb(b, port);
-       delay();
-}
-
-void microdev_outw_p(unsigned short b, unsigned long port)
-{
-       microdev_outw(b, port);
-       delay();
-}
-
-void microdev_outl_p(unsigned int b, unsigned long port)
-{
-       microdev_outl(b, port);
-       delay();
-}
-
-void microdev_insb(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned char *port_addr;
-       unsigned char *buf = buffer;
-
-       port_addr = (volatile unsigned char *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_insw(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned short *port_addr;
-       unsigned short *buf = buffer;
-
-       port_addr = (volatile unsigned short *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_insl(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned long *port_addr;
-       unsigned int *buf = buffer;
-
-       port_addr = (volatile unsigned long *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_outsb(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned char *port_addr;
-       const unsigned char *buf = buffer;
-
-       port_addr = (volatile unsigned char *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
-}
-
-void microdev_outsw(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned short *port_addr;
-       const unsigned short *buf = buffer;
-
-       port_addr = (volatile unsigned short *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
-}
-
-void microdev_outsl(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned long *port_addr;
-       const unsigned int *buf = buffer;
-
-       port_addr = (volatile unsigned long *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
+       return (void __iomem *)result;
 }
index d1df2a4..d8a7472 100644 (file)
@@ -195,27 +195,6 @@ device_initcall(microdev_devices_setup);
 static struct sh_machine_vector mv_sh4202_microdev __initmv = {
        .mv_name                = "SH4-202 MicroDev",
        .mv_nr_irqs             = 72,
-
-       .mv_inb                 = microdev_inb,
-       .mv_inw                 = microdev_inw,
-       .mv_inl                 = microdev_inl,
-       .mv_outb                = microdev_outb,
-       .mv_outw                = microdev_outw,
-       .mv_outl                = microdev_outl,
-
-       .mv_inb_p               = microdev_inb_p,
-       .mv_inw_p               = microdev_inw_p,
-       .mv_inl_p               = microdev_inl_p,
-       .mv_outb_p              = microdev_outb_p,
-       .mv_outw_p              = microdev_outw_p,
-       .mv_outl_p              = microdev_outl_p,
-
-       .mv_insb                = microdev_insb,
-       .mv_insw                = microdev_insw,
-       .mv_insl                = microdev_insl,
-       .mv_outsb               = microdev_outsb,
-       .mv_outsw               = microdev_outsw,
-       .mv_outsl               = microdev_outsl,
-
+       .mv_ioport_map          = microdev_ioport_map,
        .mv_init_irq            = init_microdev_irq,
 };
index 63e7ed6..5c9eaa0 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 7206 SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/7206/io.c b/arch/sh/boards/mach-se/7206/io.c
deleted file mode 100644 (file)
index adadc77..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $
- *
- * linux/arch/sh/boards/se/7206/io.c
- *
- * Copyright (C) 2006 Yoshinori Sato
- *
- * I/O routine for Hitachi 7206 SolutionEngine.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <mach-se/mach/se7206.h>
-
-
-static inline void delay(void)
-{
-       __raw_readw(0x20000000);  /* P2 ROM Area */
-}
-
-/* MS7750 requires special versions of in*, out* routines, since
-   PC-like io ports are located at upper half byte of 16-bit word which
-   can be accessed only with 16-bit wide.  */
-
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port >= 0x2000 && port < 0x2020)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       else if (port >= 0x300 && port < 0x310)
-               return (volatile __u16 *) (PA_SMSC + (port - 0x300));
-
-       return (volatile __u16 *)port;
-}
-
-unsigned char se7206_inb(unsigned long port)
-{
-       return (*port2adr(port)) & 0xff;
-}
-
-unsigned char se7206_inb_p(unsigned long port)
-{
-       unsigned long v;
-
-       v = (*port2adr(port)) & 0xff;
-       delay();
-       return v;
-}
-
-unsigned short se7206_inw(unsigned long port)
-{
-       return *port2adr(port);
-}
-
-void se7206_outb(unsigned char value, unsigned long port)
-{
-       *(port2adr(port)) = value;
-}
-
-void se7206_outb_p(unsigned char value, unsigned long port)
-{
-       *(port2adr(port)) = value;
-       delay();
-}
-
-void se7206_outw(unsigned short value, unsigned long port)
-{
-       *port2adr(port) = value;
-}
-
-void se7206_insb(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u8 *ap = addr;
-
-       while (count--)
-               *ap++ = *p;
-}
-
-void se7206_insw(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u16 *ap = addr;
-       while (count--)
-               *ap++ = *p;
-}
-
-void se7206_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u8 *ap = addr;
-
-       while (count--)
-               *p = *ap++;
-}
-
-void se7206_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u16 *ap = addr;
-       while (count--)
-               *p = *ap++;
-}
index 883b21e..d961949 100644 (file)
@@ -139,11 +139,13 @@ void __init init_se7206_IRQ(void)
        make_se7206_irq(IRQ0_IRQ); /* SMC91C111 */
        make_se7206_irq(IRQ1_IRQ); /* ATA */
        make_se7206_irq(IRQ3_IRQ); /* SLOT / PCM */
-       __raw_writew(inw(INTC_ICR1) | 0x000b ,INTC_ICR1 ) ; /* ICR1 */
+
+       __raw_writew(__raw_readw(INTC_ICR1) | 0x000b, INTC_ICR); /* ICR1 */
 
        /* FPGA System register setup*/
        __raw_writew(0x0000,INTSTS0); /* Clear INTSTS0 */
        __raw_writew(0x0000,INTSTS1); /* Clear INTSTS1 */
+
        /* IRQ0=LAN, IRQ1=ATA, IRQ3=SLT,PCM */
        __raw_writew(0x0001,INTSEL);
 }
index 8f5c65d..7f4871c 100644 (file)
@@ -86,20 +86,5 @@ __initcall(se7206_devices_setup);
 static struct sh_machine_vector mv_se __initmv = {
        .mv_name                = "SolutionEngine",
        .mv_nr_irqs             = 256,
-       .mv_inb                 = se7206_inb,
-       .mv_inw                 = se7206_inw,
-       .mv_outb                = se7206_outb,
-       .mv_outw                = se7206_outw,
-
-       .mv_inb_p               = se7206_inb_p,
-       .mv_inw_p               = se7206_inw,
-       .mv_outb_p              = se7206_outb_p,
-       .mv_outw_p              = se7206_outw,
-
-       .mv_insb                = se7206_insb,
-       .mv_insw                = se7206_insw,
-       .mv_outsb               = se7206_outsb,
-       .mv_outsw               = se7206_outsw,
-
        .mv_init_irq            = init_se7206_IRQ,
 };
index 8e624b0..43ea14f 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 770x SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/770x/io.c b/arch/sh/boards/mach-se/770x/io.c
deleted file mode 100644 (file)
index 28833c8..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * I/O routine for Hitachi SolutionEngine.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <mach-se/mach/se.h>
-
-/* MS7750 requires special versions of in*, out* routines, since
-   PC-like io ports are located at upper half byte of 16-bit word which
-   can be accessed only with 16-bit wide.  */
-
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port & 0xff000000)
-               return ( volatile __u16 *) port;
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       else if (port >= 0x1000)
-               return (volatile __u16 *) (PA_83902 + (port << 1));
-       else
-               return (volatile __u16 *) (PA_SUPERIO + (port << 1));
-}
-
-static inline int
-shifted_port(unsigned long port)
-{
-       /* For IDE registers, value is not shifted */
-       if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
-               return 0;
-       else
-               return 1;
-}
-
-unsigned char se_inb(unsigned long port)
-{
-       if (shifted_port(port))
-               return (*port2adr(port) >> 8);
-       else
-               return (*port2adr(port))&0xff;
-}
-
-unsigned char se_inb_p(unsigned long port)
-{
-       unsigned long v;
-
-       if (shifted_port(port))
-               v = (*port2adr(port) >> 8);
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short se_inw(unsigned long port)
-{
-       if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int se_inl(unsigned long port)
-{
-       maybebadio(port);
-       return 0;
-}
-
-void se_outb(unsigned char value, unsigned long port)
-{
-       if (shifted_port(port))
-               *(port2adr(port)) = value << 8;
-       else
-               *(port2adr(port)) = value;
-}
-
-void se_outb_p(unsigned char value, unsigned long port)
-{
-       if (shifted_port(port))
-               *(port2adr(port)) = value << 8;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void se_outw(unsigned short value, unsigned long port)
-{
-       if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void se_outl(unsigned int value, unsigned long port)
-{
-       maybebadio(port);
-}
-
-void se_insb(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u8 *ap = addr;
-
-       if (shifted_port(port)) {
-               while (count--)
-                       *ap++ = *p >> 8;
-       } else {
-               while (count--)
-                       *ap++ = *p;
-       }
-}
-
-void se_insw(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u16 *ap = addr;
-       while (count--)
-               *ap++ = *p;
-}
-
-void se_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void se_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u8 *ap = addr;
-
-       if (shifted_port(port)) {
-               while (count--)
-                       *p = *ap++ << 8;
-       } else {
-               while (count--)
-                       *p = *ap++;
-       }
-}
-
-void se_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u16 *ap = addr;
-
-       while (count--)
-               *p = *ap++;
-}
-
-void se_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
index 66d39d1..31330c6 100644 (file)
@@ -195,27 +195,5 @@ static struct sh_machine_vector mv_se __initmv = {
 #elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
        .mv_nr_irqs             = 104,
 #endif
-
-       .mv_inb                 = se_inb,
-       .mv_inw                 = se_inw,
-       .mv_inl                 = se_inl,
-       .mv_outb                = se_outb,
-       .mv_outw                = se_outw,
-       .mv_outl                = se_outl,
-
-       .mv_inb_p               = se_inb_p,
-       .mv_inw_p               = se_inw,
-       .mv_inl_p               = se_inl,
-       .mv_outb_p              = se_outb_p,
-       .mv_outw_p              = se_outw,
-       .mv_outl_p              = se_outl,
-
-       .mv_insb                = se_insb,
-       .mv_insw                = se_insw,
-       .mv_insl                = se_insl,
-       .mv_outsb               = se_outsb,
-       .mv_outsw               = se_outsw,
-       .mv_outsl               = se_outsl,
-
        .mv_init_irq            = init_se_IRQ,
 };
index e6f4341..a338fd9 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 7751 SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/7751/io.c b/arch/sh/boards/mach-se/7751/io.c
deleted file mode 100644 (file)
index 6e75bd4..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 SolutionEngine.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_se.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <mach-se/mach/se7751.h>
-#include <asm/addrspace.h>
-
-static inline volatile u16 *port2adr(unsigned int port)
-{
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char sh7751se_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else
-               return (*port2adr(port)) & 0xff;
-}
-
-unsigned char sh7751se_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-        if (PXSEG(port))
-                v = *(volatile unsigned char *)port;
-       else
-               v = (*port2adr(port)) & 0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short sh7751se_inw(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int sh7751se_inl(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void sh7751se_outb(unsigned char value, unsigned long port)
-{
-
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void sh7751se_outb_p(unsigned char value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void sh7751se_outw(unsigned short value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751se_outl(unsigned int value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751se_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
index 5057251..9fbc51b 100644 (file)
@@ -56,23 +56,5 @@ __initcall(se7751_devices_setup);
 static struct sh_machine_vector mv_7751se __initmv = {
        .mv_name                = "7751 SolutionEngine",
        .mv_nr_irqs             = 72,
-
-       .mv_inb                 = sh7751se_inb,
-       .mv_inw                 = sh7751se_inw,
-       .mv_inl                 = sh7751se_inl,
-       .mv_outb                = sh7751se_outb,
-       .mv_outw                = sh7751se_outw,
-       .mv_outl                = sh7751se_outl,
-
-       .mv_inb_p               = sh7751se_inb_p,
-       .mv_inw_p               = sh7751se_inw,
-       .mv_inl_p               = sh7751se_inl,
-       .mv_outb_p              = sh7751se_outb_p,
-       .mv_outw_p              = sh7751se_outw,
-       .mv_outl_p              = sh7751se_outl,
-
-       .mv_insl                = sh7751se_insl,
-       .mv_outsl               = sh7751se_outsl,
-
        .mv_init_irq            = init_7751se_IRQ,
 };
diff --git a/arch/sh/boards/mach-snapgear/Makefile b/arch/sh/boards/mach-snapgear/Makefile
deleted file mode 100644 (file)
index d2d2f4b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the SnapGear specific parts of the kernel
-#
-
-obj-y   := setup.o io.o
diff --git a/arch/sh/boards/mach-snapgear/io.c b/arch/sh/boards/mach-snapgear/io.c
deleted file mode 100644 (file)
index 476650e..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 SolutionEngine.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_se.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/addrspace.h>
-
-#ifdef CONFIG_SH_SECUREEDGE5410
-unsigned short secureedge5410_ioport;
-#endif
-
-static inline volatile __u16 *port2adr(unsigned int port)
-{
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char snapgear_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else
-               return (*port2adr(port)) & 0xff;
-}
-
-unsigned char snapgear_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-       if (PXSEG(port))
-               v = *(volatile unsigned char *)port;
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short snapgear_inw(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int snapgear_inl(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void snapgear_outb(unsigned char value, unsigned long port)
-{
-
-       if (PXSEG(port))
-               *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void snapgear_outb_p(unsigned char value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void snapgear_outw(unsigned short value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void snapgear_outl(unsigned int value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void snapgear_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void snapgear_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
diff --git a/arch/sh/boards/mach-systemh/Makefile b/arch/sh/boards/mach-systemh/Makefile
deleted file mode 100644 (file)
index 2cc6a23..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Makefile for the SystemH specific parts of the kernel
-#
-
-obj-y   := setup.o irq.o io.o
-
-# XXX: This wants to be consolidated in arch/sh/drivers/pci, and more
-# importantly, with the generic sh7751_pcic_init() code. For now, we'll
-# just abuse the hell out of kbuild, because we can..
-
-obj-$(CONFIG_PCI) += pci.o
-pci-y := ../../se/7751/pci.o
-
diff --git a/arch/sh/boards/mach-systemh/io.c b/arch/sh/boards/mach-systemh/io.c
deleted file mode 100644 (file)
index 15577ff..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/io.c
- *
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 Systemh.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <mach/systemh7751.h>
-#include <asm/addrspace.h>
-#include <asm/io.h>
-
-#define ETHER_IOMAP(adr) (0xB3000000 + (adr)) /*map to 16bits access area
-                                                of smc lan chip*/
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char sh7751systemh_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else if (port <= 0x3F1)
-               return *(volatile unsigned char *)ETHER_IOMAP(port);
-       else
-               return (*port2adr(port))&0xff;
-}
-
-unsigned char sh7751systemh_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-        if (PXSEG(port))
-                v = *(volatile unsigned char *)port;
-       else if (port <= 0x3F1)
-               v = *(volatile unsigned char *)ETHER_IOMAP(port);
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short sh7751systemh_inw(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else if (port <= 0x3F1)
-               return *(volatile unsigned int *)ETHER_IOMAP(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int sh7751systemh_inl(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else if (port <= 0x3F1)
-               return *(volatile unsigned int *)ETHER_IOMAP(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void sh7751systemh_outb(unsigned char value, unsigned long port)
-{
-
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned char *)ETHER_IOMAP(port) = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void sh7751systemh_outb_p(unsigned char value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned char *)ETHER_IOMAP(port) = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void sh7751systemh_outw(unsigned short value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned short *)ETHER_IOMAP(port) = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751systemh_outl(unsigned int value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned char *p = addr;
-       while (count--) *p++ = sh7751systemh_inb(port);
-}
-
-void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned short *p = addr;
-       while (count--) *p++ = sh7751systemh_inw(port);
-}
-
-void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned char *p = (unsigned char*)addr;
-       while (count--) sh7751systemh_outb(*p++, port);
-}
-
-void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned short *p = (unsigned short*)addr;
-       while (count--) sh7751systemh_outw(*p++, port);
-}
-
-void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
diff --git a/arch/sh/boards/mach-systemh/irq.c b/arch/sh/boards/mach-systemh/irq.c
deleted file mode 100644 (file)
index e5ee13a..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/irq.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SystemH Support.
- *
- * Modified for 7751 SystemH by
- * Jonathan Short.
- */
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#include <mach/systemh7751.h>
-#include <asm/smc37c93x.h>
-
-/* address of external interrupt mask register
- * address must be set prior to use these (maybe in init_XXX_irq())
- * XXX : is it better to use .config than specifying it in code? */
-static unsigned long *systemh_irq_mask_register = (unsigned long *)0xB3F10004;
-static unsigned long *systemh_irq_request_register = (unsigned long *)0xB3F10000;
-
-static void disable_systemh_irq(struct irq_data *data)
-{
-       unsigned long val, mask = 0x01 << 1;
-
-       /* Clear the "irq"th bit in the mask and set it in the request */
-       val = __raw_readl((unsigned long)systemh_irq_mask_register);
-       val &= ~mask;
-       __raw_writel(val, (unsigned long)systemh_irq_mask_register);
-
-       val = __raw_readl((unsigned long)systemh_irq_request_register);
-       val |= mask;
-       __raw_writel(val, (unsigned long)systemh_irq_request_register);
-}
-
-static void enable_systemh_irq(struct irq_data *data)
-{
-       unsigned long val, mask = 0x01 << 1;
-
-       /* Set "irq"th bit in the mask register */
-       val = __raw_readl((unsigned long)systemh_irq_mask_register);
-       val |= mask;
-       __raw_writel(val, (unsigned long)systemh_irq_mask_register);
-}
-
-static struct irq_chip systemh_irq_type = {
-       .name           = "SystemH Register",
-       .irq_unmask     = enable_systemh_irq,
-       .irq_mask       = disable_systemh_irq,
-};
-
-void make_systemh_irq(unsigned int irq)
-{
-       disable_irq_nosync(irq);
-       set_irq_chip_and_handler(irq, &systemh_irq_type, handle_level_irq);
-       disable_systemh_irq(irq_get_irq_data(irq));
-}
diff --git a/arch/sh/boards/mach-systemh/setup.c b/arch/sh/boards/mach-systemh/setup.c
deleted file mode 100644 (file)
index 219fd80..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/setup.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- * Copyright (C) 2003  Paul Mundt
- *
- * Hitachi SystemH Support.
- *
- * Modified for 7751 SystemH by Jonathan Short.
- *
- * Rewritten for 2.6 by Paul Mundt.
- *
- * 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.
- */
-#include <linux/init.h>
-#include <asm/machvec.h>
-#include <mach/systemh7751.h>
-
-extern void make_systemh_irq(unsigned int irq);
-
-/*
- * Initialize IRQ setting
- */
-static void __init sh7751systemh_init_irq(void)
-{
-       make_systemh_irq(0xb);  /* Ethernet interrupt */
-}
-
-static struct sh_machine_vector mv_7751systemh __initmv = {
-       .mv_name                = "7751 SystemH",
-       .mv_nr_irqs             = 72,
-
-       .mv_inb                 = sh7751systemh_inb,
-       .mv_inw                 = sh7751systemh_inw,
-       .mv_inl                 = sh7751systemh_inl,
-       .mv_outb                = sh7751systemh_outb,
-       .mv_outw                = sh7751systemh_outw,
-       .mv_outl                = sh7751systemh_outl,
-
-       .mv_inb_p               = sh7751systemh_inb_p,
-       .mv_inw_p               = sh7751systemh_inw,
-       .mv_inl_p               = sh7751systemh_inl,
-       .mv_outb_p              = sh7751systemh_outb_p,
-       .mv_outw_p              = sh7751systemh_outw,
-       .mv_outl_p              = sh7751systemh_outl,
-
-       .mv_insb                = sh7751systemh_insb,
-       .mv_insw                = sh7751systemh_insw,
-       .mv_insl                = sh7751systemh_insl,
-       .mv_outsb               = sh7751systemh_outsb,
-       .mv_outsw               = sh7751systemh_outsw,
-       .mv_outsl               = sh7751systemh_outsl,
-
-       .mv_init_irq            = sh7751systemh_init_irq,
-};
diff --git a/arch/sh/configs/systemh_defconfig b/arch/sh/configs/systemh_defconfig
deleted file mode 100644 (file)
index b58dfc5..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_CPU_SUBTYPE_SH7751R=y
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x00400000
-CONFIG_FLATMEM_MANUAL=y
-CONFIG_SH_7751_SYSTEMH=y
-CONFIG_PREEMPT=y
-# CONFIG_STANDALONE is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=1024
-# CONFIG_INPUT is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_VT is not set
-CONFIG_HW_RANDOM=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_ROMFS_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
index 446b383..3d1ae2b 100644 (file)
 /*
  * These will never work in 32-bit, don't even bother.
  */
-#define P1SEGADDR(a)   __futile_remapping_attempt
-#define P2SEGADDR(a)   __futile_remapping_attempt
-#define P3SEGADDR(a)   __futile_remapping_attempt
-#define P4SEGADDR(a)   __futile_remapping_attempt
+#define P1SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P2SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P3SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P4SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
 #endif
 #endif /* P1SEG */
 
index a15f105..083ea06 100644 (file)
@@ -66,7 +66,6 @@ static inline unsigned long long neff_sign_extend(unsigned long val)
 #define PHYS_ADDR_MASK29               0x1fffffff
 #define PHYS_ADDR_MASK32               0xffffffff
 
-#ifdef CONFIG_PMB
 static inline unsigned long phys_addr_mask(void)
 {
        /* Is the MMU in 29bit mode? */
@@ -75,17 +74,6 @@ static inline unsigned long phys_addr_mask(void)
 
        return PHYS_ADDR_MASK32;
 }
-#elif defined(CONFIG_32BIT)
-static inline unsigned long phys_addr_mask(void)
-{
-       return PHYS_ADDR_MASK32;
-}
-#else
-static inline unsigned long phys_addr_mask(void)
-{
-       return PHYS_ADDR_MASK29;
-}
-#endif
 
 #define PTE_PHYS_MASK          (phys_addr_mask() & PAGE_MASK)
 #define PTE_FLAGS_MASK         (~(PTE_PHYS_MASK) << PAGE_SHIFT)
index 1f1af5a..10c8b18 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/compiler.h>
 #include <linux/linkage.h>
 #include <asm/types.h>
+#include <asm/uncached.h>
 
 #define AT_VECTOR_SIZE_ARCH 5 /* entries in ARCH_DLINFO */
 
@@ -137,9 +138,6 @@ extern unsigned int instruction_size(unsigned int insn);
 #define instruction_size(insn) (4)
 #endif
 
-extern unsigned long cached_to_uncached;
-extern unsigned long uncached_size;
-
 void per_cpu_trap_init(void);
 void default_idle(void);
 void cpu_idle_wait(void);
index c941b27..a4ad1cd 100644 (file)
@@ -145,42 +145,6 @@ do {                                                               \
                __restore_dsp(prev);                            \
 } while (0)
 
-/*
- * Jump to uncached area.
- * When handling TLB or caches, we need to do it from an uncached area.
- */
-#define jump_to_uncached()                     \
-do {                                           \
-       unsigned long __dummy;                  \
-                                               \
-       __asm__ __volatile__(                   \
-               "mova   1f, %0\n\t"             \
-               "add    %1, %0\n\t"             \
-               "jmp    @%0\n\t"                \
-               " nop\n\t"                      \
-               ".balign 4\n"                   \
-               "1:"                            \
-               : "=&z" (__dummy)               \
-               : "r" (cached_to_uncached));    \
-} while (0)
-
-/*
- * Back to cached area.
- */
-#define back_to_cached()                               \
-do {                                                   \
-       unsigned long __dummy;                          \
-       ctrl_barrier();                                 \
-       __asm__ __volatile__(                           \
-               "mov.l  1f, %0\n\t"                     \
-               "jmp    @%0\n\t"                        \
-               " nop\n\t"                              \
-               ".balign 4\n"                           \
-               "1:     .long 2f\n"                     \
-               "2:"                                    \
-               : "=&r" (__dummy));                     \
-} while (0)
-
 #ifdef CONFIG_CPU_HAS_SR_RB
 #define lookup_exception_vector()      \
 ({                                     \
index 3633864..8593bc8 100644 (file)
@@ -34,9 +34,6 @@ do {                                                          \
                              &next->thread);                   \
 } while (0)
 
-#define jump_to_uncached()     do { } while (0)
-#define back_to_cached()       do { } while (0)
-
 #define __icbi(addr)   __asm__ __volatile__ ( "icbi %0, 0\n\t" : : "r" (addr))
 #define __ocbp(addr)   __asm__ __volatile__ ( "ocbp %0, 0\n\t" : : "r" (addr))
 #define __ocbi(addr)   __asm__ __volatile__ ( "ocbi %0, 0\n\t" : : "r" (addr))
index e3419f9..6f8816b 100644 (file)
@@ -4,15 +4,55 @@
 #include <linux/bug.h>
 
 #ifdef CONFIG_UNCACHED_MAPPING
+extern unsigned long cached_to_uncached;
+extern unsigned long uncached_size;
 extern unsigned long uncached_start, uncached_end;
 
 extern int virt_addr_uncached(unsigned long kaddr);
 extern void uncached_init(void);
 extern void uncached_resize(unsigned long size);
+
+/*
+ * Jump to uncached area.
+ * When handling TLB or caches, we need to do it from an uncached area.
+ */
+#define jump_to_uncached()                     \
+do {                                           \
+       unsigned long __dummy;                  \
+                                               \
+       __asm__ __volatile__(                   \
+               "mova   1f, %0\n\t"             \
+               "add    %1, %0\n\t"             \
+               "jmp    @%0\n\t"                \
+               " nop\n\t"                      \
+               ".balign 4\n"                   \
+               "1:"                            \
+               : "=&z" (__dummy)               \
+               : "r" (cached_to_uncached));    \
+} while (0)
+
+/*
+ * Back to cached area.
+ */
+#define back_to_cached()                               \
+do {                                                   \
+       unsigned long __dummy;                          \
+       ctrl_barrier();                                 \
+       __asm__ __volatile__(                           \
+               "mov.l  1f, %0\n\t"                     \
+               "jmp    @%0\n\t"                        \
+               " nop\n\t"                              \
+               ".balign 4\n"                           \
+               "1:     .long 2f\n"                     \
+               "2:"                                    \
+               : "=&r" (__dummy));                     \
+} while (0)
 #else
 #define virt_addr_uncached(kaddr)      (0)
 #define uncached_init()                        do { } while (0)
 #define uncached_resize(size)          BUG()
+#define jump_to_uncached()             do { } while (0)
+#define back_to_cached()               do { } while (0)
 #endif
 
 #endif /* __ASM_SH_UNCACHED_H */
diff --git a/arch/sh/include/mach-common/mach/edosk7705.h b/arch/sh/include/mach-common/mach/edosk7705.h
deleted file mode 100644 (file)
index efc43b3..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __ASM_SH_EDOSK7705_H
-#define __ASM_SH_EDOSK7705_H
-
-#define __IO_PREFIX sh_edosk7705
-#include <asm/io_generic.h>
-
-#endif /* __ASM_SH_EDOSK7705_H */
index 1aed158..dcb05fa 100644 (file)
@@ -68,13 +68,4 @@ extern void microdev_print_fpga_intc_status(void);
 #define __IO_PREFIX microdev
 #include <asm/io_generic.h>
 
-#if defined(CONFIG_PCI)
-unsigned char  microdev_pci_inb(unsigned long port);
-unsigned short microdev_pci_inw(unsigned long port);
-unsigned long  microdev_pci_inl(unsigned long port);
-void           microdev_pci_outb(unsigned char  data, unsigned long port);
-void           microdev_pci_outw(unsigned short data, unsigned long port);
-void           microdev_pci_outl(unsigned long  data, unsigned long port);
-#endif
-
 #endif /* __ASM_SH_MICRODEV_H */
 #ifndef _ASM_SH_IO_SNAPGEAR_H
 #define _ASM_SH_IO_SNAPGEAR_H
 
-#if defined(CONFIG_CPU_SH4)
-/*
- * The external interrupt lines, these take up ints 0 - 15 inclusive
- * depending on the priority for the interrupt.  In fact the priority
- * is the interrupt :-)
- */
-
-#define IRL0_IRQ       2
-#define IRL0_PRIORITY  13
-
-#define IRL1_IRQ       5
-#define IRL1_PRIORITY  10
-
-#define IRL2_IRQ       8
-#define IRL2_PRIORITY  7
-
-#define IRL3_IRQ       11
-#define IRL3_PRIORITY  4
-#endif
-
 #define __IO_PREFIX    snapgear
 #include <asm/io_generic.h>
 
-#ifdef CONFIG_SH_SECUREEDGE5410
 /*
  * We need to remember what was written to the ioport as some bits
  * are shared with other functions and you cannot read back what was
@@ -66,6 +45,5 @@ extern unsigned short secureedge5410_ioport;
                        ((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
 #define SECUREEDGE_READ_IOPORT() \
         ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
-#endif
 
 #endif /* _ASM_SH_IO_SNAPGEAR_H */
diff --git a/arch/sh/include/mach-common/mach/systemh7751.h b/arch/sh/include/mach-common/mach/systemh7751.h
deleted file mode 100644 (file)
index 4161122..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef __ASM_SH_SYSTEMH_7751SYSTEMH_H
-#define __ASM_SH_SYSTEMH_7751SYSTEMH_H
-
-/*
- * linux/include/asm-sh/systemh/7751systemh.h
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SystemH support
-
- * Modified for 7751 SystemH by
- * Jonathan Short, 2002.
- */
-
-/* Box specific addresses.  */
-
-#define PA_ROM         0x00000000      /* EPROM */
-#define PA_ROM_SIZE    0x00400000      /* EPROM size 4M byte */
-#define PA_FROM                0x01000000      /* EPROM */
-#define PA_FROM_SIZE   0x00400000      /* EPROM size 4M byte */
-#define PA_EXT1                0x04000000
-#define PA_EXT1_SIZE   0x04000000
-#define PA_EXT2                0x08000000
-#define PA_EXT2_SIZE   0x04000000
-#define PA_SDRAM       0x0c000000
-#define PA_SDRAM_SIZE  0x04000000
-
-#define PA_EXT4                0x12000000
-#define PA_EXT4_SIZE   0x02000000
-#define PA_EXT5                0x14000000
-#define PA_EXT5_SIZE   0x04000000
-#define PA_PCIC                0x18000000      /* MR-SHPC-01 PCMCIA */
-
-#define PA_DIPSW0      0xb9000000      /* Dip switch 5,6 */
-#define PA_DIPSW1      0xb9000002      /* Dip switch 7,8 */
-#define PA_LED         0xba000000      /* LED */
-#define        PA_BCR          0xbb000000      /* FPGA on the MS7751SE01 */
-
-#define PA_MRSHPC      0xb83fffe0      /* MR-SHPC-01 PCMCIA controller */
-#define PA_MRSHPC_MW1  0xb8400000      /* MR-SHPC-01 memory window base */
-#define PA_MRSHPC_MW2  0xb8500000      /* MR-SHPC-01 attribute window base */
-#define PA_MRSHPC_IO   0xb8600000      /* MR-SHPC-01 I/O window base */
-#define MRSHPC_MODE     (PA_MRSHPC + 4)
-#define MRSHPC_OPTION   (PA_MRSHPC + 6)
-#define MRSHPC_CSR      (PA_MRSHPC + 8)
-#define MRSHPC_ISR      (PA_MRSHPC + 10)
-#define MRSHPC_ICR      (PA_MRSHPC + 12)
-#define MRSHPC_CPWCR    (PA_MRSHPC + 14)
-#define MRSHPC_MW0CR1   (PA_MRSHPC + 16)
-#define MRSHPC_MW1CR1   (PA_MRSHPC + 18)
-#define MRSHPC_IOWCR1   (PA_MRSHPC + 20)
-#define MRSHPC_MW0CR2   (PA_MRSHPC + 22)
-#define MRSHPC_MW1CR2   (PA_MRSHPC + 24)
-#define MRSHPC_IOWCR2   (PA_MRSHPC + 26)
-#define MRSHPC_CDCR     (PA_MRSHPC + 28)
-#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
-
-#define BCR_ILCRA      (PA_BCR + 0)
-#define BCR_ILCRB      (PA_BCR + 2)
-#define BCR_ILCRC      (PA_BCR + 4)
-#define BCR_ILCRD      (PA_BCR + 6)
-#define BCR_ILCRE      (PA_BCR + 8)
-#define BCR_ILCRF      (PA_BCR + 10)
-#define BCR_ILCRG      (PA_BCR + 12)
-
-#define IRQ_79C973     13
-
-#define __IO_PREFIX    sh7751systemh
-#include <asm/io_generic.h>
-
-#endif  /* __ASM_SH_SYSTEMH_7751SYSTEMH_H */
index 2d9700c..0fe2e93 100644 (file)
@@ -48,7 +48,7 @@ static struct clk r_clk = {
  * Default rate for the root input clock, reset this with clk_set_rate()
  * from the platform code.
  */
-struct clk extal_clk = {
+static struct clk extal_clk = {
        .rate           = 33333333,
 };
 
@@ -111,7 +111,7 @@ static struct clk div3_clk = {
        .parent         = &pll_clk,
 };
 
-struct clk *main_clks[] = {
+static struct clk *main_clks[] = {
        &r_clk,
        &extal_clk,
        &fll_clk,
@@ -156,7 +156,7 @@ struct clk div4_clks[DIV4_NR] = {
 
 enum { DIV6_V, DIV6_FA, DIV6_FB, DIV6_I, DIV6_S, DIV6_NR };
 
-struct clk div6_clks[DIV6_NR] = {
+static struct clk div6_clks[DIV6_NR] = {
        [DIV6_V] = SH_CLK_DIV6(&div3_clk, VCLKCR, 0),
        [DIV6_FA] = SH_CLK_DIV6(&div3_clk, FCLKACR, 0),
        [DIV6_FB] = SH_CLK_DIV6(&div3_clk, FCLKBCR, 0),
index 0937039..c3e61b3 100644 (file)
@@ -79,7 +79,7 @@ config 29BIT
 
 config 32BIT
        bool
-       default y if CPU_SH5
+       default y if CPU_SH5 || !MMU
 
 config PMB
        bool "Support 32-bit physical addressing through PMB"
index 0387932..40733a9 100644 (file)
@@ -79,21 +79,20 @@ void dma_generic_free_coherent(struct device *dev, size_t size,
 void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
                    enum dma_data_direction direction)
 {
-#if defined(CONFIG_CPU_SH5) || defined(CONFIG_PMB)
-       void *p1addr = vaddr;
-#else
-       void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
-#endif
+       void *addr;
+
+       addr = __in_29bit_mode() ?
+              (void *)P1SEGADDR((unsigned long)vaddr) : vaddr;
 
        switch (direction) {
        case DMA_FROM_DEVICE:           /* invalidate only */
-               __flush_invalidate_region(p1addr, size);
+               __flush_invalidate_region(addr, size);
                break;
        case DMA_TO_DEVICE:             /* writeback only */
-               __flush_wback_region(p1addr, size);
+               __flush_wback_region(addr, size);
                break;
        case DMA_BIDIRECTIONAL:         /* writeback and invalidate */
-               __flush_purge_region(p1addr, size);
+               __flush_purge_region(addr, size);
                break;
        default:
                BUG();
index 8a4eca5..a7767da 100644 (file)
@@ -28,7 +28,7 @@ EXPORT_SYMBOL(virt_addr_uncached);
 
 void __init uncached_init(void)
 {
-#ifdef CONFIG_29BIT
+#if defined(CONFIG_29BIT) || !defined(CONFIG_MMU)
        uncached_start = P2SEG;
 #else
        uncached_start = memory_end;
index 9f56eb9..0e68465 100644 (file)
@@ -26,7 +26,6 @@ HD64461                       HD64461
 7724SE                 SH_7724_SOLUTION_ENGINE
 7751SE                 SH_7751_SOLUTION_ENGINE
 7780SE                 SH_7780_SOLUTION_ENGINE
-7751SYSTEMH            SH_7751_SYSTEMH
 HP6XX                  SH_HP6XX
 DREAMCAST              SH_DREAMCAST
 SNAPGEAR               SH_SECUREEDGE5410
index e0f7ee1..b2a6c5d 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <linux/interrupt.h>
 #include <linux/threads.h>
-#include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
 #include <asm/homecache.h>
 
index 1480106..3d0f202 100644 (file)
 #define _ASM_TILE_KMAP_TYPES_H
 
 /*
- * In TILE Linux each set of four of these uses another 16MB chunk of
- * address space, given 64 tiles and 64KB pages, so we only enable
- * ones that are required by the kernel configuration.
+ * In 32-bit TILE Linux we have to balance the desire to have a lot of
+ * nested atomic mappings with the fact that large page sizes and many
+ * processors chew up address space quickly.  In a typical
+ * 64-processor, 64KB-page layout build, making KM_TYPE_NR one larger
+ * adds 4MB of required address-space.  For now we leave KM_TYPE_NR
+ * set to depth 8.
  */
 enum km_type {
+       KM_TYPE_NR = 8
+};
+
+/*
+ * We provide dummy definitions of all the stray values that used to be
+ * required for kmap_atomic() and no longer are.
+ */
+enum {
        KM_BOUNCE_READ,
        KM_SKB_SUNRPC_DATA,
        KM_SKB_DATA_SOFTIRQ,
        KM_USER0,
        KM_USER1,
        KM_BIO_SRC_IRQ,
+       KM_BIO_DST_IRQ,
+       KM_PTE0,
+       KM_PTE1,
        KM_IRQ0,
        KM_IRQ1,
        KM_SOFTIRQ0,
        KM_SOFTIRQ1,
-       KM_MEMCPY0,
-       KM_MEMCPY1,
-#if defined(CONFIG_HIGHPTE)
-       KM_PTE0,
-       KM_PTE1,
-#endif
-       KM_TYPE_NR
+       KM_SYNC_ICACHE,
+       KM_SYNC_DCACHE,
+       KM_UML_USERCOPY,
+       KM_IRQ_PTE,
+       KM_NMI,
+       KM_NMI_PTE,
+       KM_KDB
 };
 
 #endif /* _ASM_TILE_KMAP_TYPES_H */
index dc4ccdd..a6604e9 100644 (file)
@@ -344,10 +344,8 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 #if defined(CONFIG_HIGHPTE)
-extern pte_t *_pte_offset_map(pmd_t *, unsigned long address, enum km_type);
-#define pte_offset_map(dir, address) \
-       _pte_offset_map(dir, address, KM_PTE0)
-#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
+extern pte_t *pte_offset_map(pmd_t *, unsigned long address);
+#define pte_unmap(pte) kunmap_atomic(pte)
 #else
 #define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
 #define pte_unmap(pte) do { } while (0)
index 3dc90fa..b16e5db 100644 (file)
@@ -1 +1,4 @@
+#ifdef CONFIG_COMPAT
+#define __ARCH_WANT_STAT64     /* Used for compat_sys_stat64() etc. */
+#endif
 #include <asm-generic/stat.h>
index f2e3ff4..b35c2db 100644 (file)
@@ -41,6 +41,7 @@ __SYSCALL(__NR_cmpxchg_badaddr, sys_cmpxchg_badaddr)
 #ifdef CONFIG_COMPAT
 #define __ARCH_WANT_SYS_LLSEEK
 #endif
+#define __ARCH_WANT_SYS_NEWFSTATAT
 #endif
 
 #endif /* _ASM_TILE_UNISTD_H */
index 77739cd..67617a0 100644 (file)
@@ -148,11 +148,11 @@ long tile_compat_sys_msgrcv(int msqid,
 #define compat_sys_readahead sys32_readahead
 #define compat_sys_sync_file_range compat_sys_sync_file_range2
 
-/* The native 64-bit "struct stat" matches the 32-bit "struct stat64". */
-#define compat_sys_stat64 sys_newstat
-#define compat_sys_lstat64 sys_newlstat
-#define compat_sys_fstat64 sys_newfstat
-#define compat_sys_fstatat64 sys_newfstatat
+/* We leverage the "struct stat64" type for 32-bit time_t/nsec. */
+#define compat_sys_stat64 sys_stat64
+#define compat_sys_lstat64 sys_lstat64
+#define compat_sys_fstat64 sys_fstat64
+#define compat_sys_fstatat64 sys_fstatat64
 
 /* The native sys_ptrace dynamically handles compat binaries. */
 #define compat_sys_ptrace sys_ptrace
index 2c54fd4..493a0e6 100644 (file)
@@ -54,7 +54,7 @@ void early_printk(const char *fmt, ...)
 void early_panic(const char *fmt, ...)
 {
        va_list ap;
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        va_start(ap, fmt);
        early_printk("Kernel panic - not syncing: ");
        early_vprintk(fmt, ap);
index 1e54a78..e910530 100644 (file)
@@ -151,12 +151,12 @@ enum direction_protect {
 
 static void enable_firewall_interrupts(void)
 {
-       raw_local_irq_unmask_now(INT_UDN_FIREWALL);
+       arch_local_irq_unmask_now(INT_UDN_FIREWALL);
 }
 
 static void disable_firewall_interrupts(void)
 {
-       raw_local_irq_mask_now(INT_UDN_FIREWALL);
+       arch_local_irq_mask_now(INT_UDN_FIREWALL);
 }
 
 /* Set up hardwall on this cpu based on the passed hardwall_info. */
@@ -768,13 +768,13 @@ static int hardwall_release(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations dev_hardwall_fops = {
+       .open           = nonseekable_open,
        .unlocked_ioctl = hardwall_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = hardwall_compat_ioctl,
 #endif
        .flush          = hardwall_flush,
        .release        = hardwall_release,
-       .llseek         = noop_llseek,
 };
 
 static struct cdev hardwall_dev;
index e639176..128805e 100644 (file)
@@ -26,7 +26,7 @@
 #define IS_HW_CLEARED 1
 
 /*
- * The set of interrupts we enable for raw_local_irq_enable().
+ * The set of interrupts we enable for arch_local_irq_enable().
  * This is initialized to have just a single interrupt that the kernel
  * doesn't actually use as a sentinel.  During kernel init,
  * interrupts are added as the kernel gets prepared to support them.
@@ -225,7 +225,7 @@ void __cpuinit setup_irq_regs(void)
        /* Enable interrupt delivery. */
        unmask_irqs(~0UL);
 #if CHIP_HAS_IPI()
-       raw_local_irq_unmask(INT_IPI_K);
+       arch_local_irq_unmask(INT_IPI_K);
 #endif
 }
 
index ba7a265..0d8b9e9 100644 (file)
@@ -182,13 +182,13 @@ static void kexec_find_and_set_command_line(struct kimage *image)
 
                if ((entry & IND_SOURCE)) {
                        void *va =
-                               kmap_atomic_pfn(entry >> PAGE_SHIFT, KM_USER0);
+                               kmap_atomic_pfn(entry >> PAGE_SHIFT);
                        r = kexec_bn2cl(va);
                        if (r) {
                                command_line = r;
                                break;
                        }
-                       kunmap_atomic(va, KM_USER0);
+                       kunmap_atomic(va);
                }
        }
 
@@ -198,7 +198,7 @@ static void kexec_find_and_set_command_line(struct kimage *image)
 
                hverr = hv_set_command_line(
                        (HV_VirtAddr) command_line, strlen(command_line));
-               kunmap_atomic(command_line, KM_USER0);
+               kunmap_atomic(command_line);
        } else {
                pr_info("%s: no command line found; making empty\n",
                       __func__);
index 997e393..0858ee6 100644 (file)
@@ -34,7 +34,7 @@ void __cpuinit init_messaging(void)
                panic("hv_register_message_state: error %d", rc);
 
        /* Make sure downcall interrupts will be enabled. */
-       raw_local_irq_unmask(INT_INTCTRL_K);
+       arch_local_irq_unmask(INT_INTCTRL_K);
 }
 
 void hv_message_intr(struct pt_regs *regs, int intnum)
index 9cd2988..e92e405 100644 (file)
@@ -50,10 +50,10 @@ long arch_ptrace(struct task_struct *child, long request,
 {
        unsigned long __user *datap = (long __user __force *)data;
        unsigned long tmp;
-       int i;
        long ret = -EIO;
-       unsigned long *childregs;
        char *childreg;
+       struct pt_regs copyregs;
+       int ex1_offset;
 
        switch (request) {
 
@@ -80,6 +80,16 @@ long arch_ptrace(struct task_struct *child, long request,
                if (addr >= PTREGS_SIZE)
                        break;
                childreg = (char *)task_pt_regs(child) + addr;
+
+               /* Guard against overwrites of the privilege level. */
+               ex1_offset = PTREGS_OFFSET_EX1;
+#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
+               if (is_compat_task())   /* point at low word */
+                       ex1_offset += sizeof(compat_long_t);
+#endif
+               if (addr == ex1_offset)
+                       data = PL_ICS_EX1(USER_PL, EX1_ICS(data));
+
 #ifdef CONFIG_COMPAT
                if (is_compat_task()) {
                        if (addr & (sizeof(compat_long_t)-1))
@@ -96,26 +106,19 @@ long arch_ptrace(struct task_struct *child, long request,
                break;
 
        case PTRACE_GETREGS:  /* Get all registers from the child. */
-               if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE))
-                       break;
-               childregs = (long *)task_pt_regs(child);
-               for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long);
-                               ++i) {
-                       ret = __put_user(childregs[i], &datap[i]);
-                       if (ret != 0)
-                               break;
+               if (copy_to_user(datap, task_pt_regs(child),
+                                sizeof(struct pt_regs)) == 0) {
+                       ret = 0;
                }
                break;
 
        case PTRACE_SETREGS:  /* Set all registers in the child. */
-               if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE))
-                       break;
-               childregs = (long *)task_pt_regs(child);
-               for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long);
-                               ++i) {
-                       ret = __get_user(childregs[i], &datap[i]);
-                       if (ret != 0)
-                               break;
+               if (copy_from_user(&copyregs, datap,
+                                  sizeof(struct pt_regs)) == 0) {
+                       copyregs.ex1 =
+                               PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1));
+                       *task_pt_regs(child) = copyregs;
+                       ret = 0;
                }
                break;
 
index acd86d2..baa3d90 100644 (file)
@@ -27,7 +27,7 @@
 void machine_halt(void)
 {
        warn_early_printk();
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_halt();
 }
@@ -35,14 +35,14 @@ void machine_halt(void)
 void machine_power_off(void)
 {
        warn_early_printk();
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_power_off();
 }
 
 void machine_restart(char *cmd)
 {
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_restart((HV_VirtAddr) "vmlinux", (HV_VirtAddr) cmd);
 }
index ae51cad..fb0b3cb 100644 (file)
@@ -868,14 +868,14 @@ void __cpuinit setup_cpu(int boot)
 
        /* Allow asynchronous TLB interrupts. */
 #if CHIP_HAS_TILE_DMA()
-       raw_local_irq_unmask(INT_DMATLB_MISS);
-       raw_local_irq_unmask(INT_DMATLB_ACCESS);
+       arch_local_irq_unmask(INT_DMATLB_MISS);
+       arch_local_irq_unmask(INT_DMATLB_ACCESS);
 #endif
 #if CHIP_HAS_SN_PROC()
-       raw_local_irq_unmask(INT_SNITLB_MISS);
+       arch_local_irq_unmask(INT_SNITLB_MISS);
 #endif
 #ifdef __tilegx__
-       raw_local_irq_unmask(INT_SINGLE_STEP_K);
+       arch_local_irq_unmask(INT_SINGLE_STEP_K);
 #endif
 
        /*
index fb28e85..687719d 100644 (file)
@@ -71,6 +71,9 @@ int restore_sigcontext(struct pt_regs *regs,
        for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
                err |= __get_user(regs->regs[i], &sc->gregs[i]);
 
+       /* Ensure that the PL is always set to USER_PL. */
+       regs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(regs->ex1));
+
        regs->faultnum = INT_SWINT_1_SIGRETURN;
 
        err |= __get_user(*pr0, &sc->gregs[0]);
@@ -330,7 +333,7 @@ void do_signal(struct pt_regs *regs)
                        current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
                }
 
-               return;
+               goto done;
        }
 
        /* Did we come from a system call? */
@@ -358,4 +361,8 @@ void do_signal(struct pt_regs *regs)
                current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
                sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
        }
+
+done:
+       /* Avoid double syscall restart if there are nested signals. */
+       regs->faultnum = INT_SWINT_1_SIGRETURN;
 }
index 75255d9..9575b37 100644 (file)
@@ -115,7 +115,7 @@ static void smp_start_cpu_interrupt(void)
 static void smp_stop_cpu_interrupt(void)
 {
        set_cpu_online(smp_processor_id(), 0);
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        for (;;)
                asm("nap");
 }
index 6bed820..f2e156e 100644 (file)
@@ -132,7 +132,7 @@ static int tile_timer_set_next_event(unsigned long ticks,
 {
        BUG_ON(ticks > MAX_TICK);
        __insn_mtspr(SPR_TILE_TIMER_CONTROL, ticks);
-       raw_local_irq_unmask_now(INT_TILE_TIMER);
+       arch_local_irq_unmask_now(INT_TILE_TIMER);
        return 0;
 }
 
@@ -143,7 +143,7 @@ static int tile_timer_set_next_event(unsigned long ticks,
 static void tile_timer_set_mode(enum clock_event_mode mode,
                                struct clock_event_device *evt)
 {
-       raw_local_irq_mask_now(INT_TILE_TIMER);
+       arch_local_irq_mask_now(INT_TILE_TIMER);
 }
 
 /*
@@ -172,7 +172,7 @@ void __cpuinit setup_tile_timer(void)
        evt->cpumask = cpumask_of(smp_processor_id());
 
        /* Start out with timer not firing. */
-       raw_local_irq_mask_now(INT_TILE_TIMER);
+       arch_local_irq_mask_now(INT_TILE_TIMER);
 
        /* Register tile timer. */
        clockevents_register_device(evt);
@@ -188,7 +188,7 @@ void do_timer_interrupt(struct pt_regs *regs, int fault_num)
         * Mask the timer interrupt here, since we are a oneshot timer
         * and there are now by definition no events pending.
         */
-       raw_local_irq_mask(INT_TILE_TIMER);
+       arch_local_irq_mask(INT_TILE_TIMER);
 
        /* Track time spent here in an interrupt context */
        irq_enter();
index dfedea7..f7d4a6a 100644 (file)
@@ -54,7 +54,7 @@ typedef unsigned long (*memcpy_t)(void *, const void *, unsigned long);
  * we must run with interrupts disabled to avoid the risk of some
  * other code seeing the incoherent data in our cache.  (Recall that
  * our cache is indexed by PA, so even if the other code doesn't use
- * our KM_MEMCPY virtual addresses, they'll still hit in cache using
+ * our kmap_atomic virtual addresses, they'll still hit in cache using
  * the normal VAs that aren't supposed to hit in cache.)
  */
 static void memcpy_multicache(void *dest, const void *source,
@@ -64,6 +64,7 @@ static void memcpy_multicache(void *dest, const void *source,
        unsigned long flags, newsrc, newdst;
        pmd_t *pmdp;
        pte_t *ptep;
+       int type0, type1;
        int cpu = get_cpu();
 
        /*
@@ -77,7 +78,8 @@ static void memcpy_multicache(void *dest, const void *source,
        sim_allow_multiple_caching(1);
 
        /* Set up the new dest mapping */
-       idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + KM_MEMCPY0;
+       type0 = kmap_atomic_idx_push();
+       idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + type0;
        newdst = __fix_to_virt(idx) + ((unsigned long)dest & (PAGE_SIZE-1));
        pmdp = pmd_offset(pud_offset(pgd_offset_k(newdst), newdst), newdst);
        ptep = pte_offset_kernel(pmdp, newdst);
@@ -87,7 +89,8 @@ static void memcpy_multicache(void *dest, const void *source,
        }
 
        /* Set up the new source mapping */
-       idx += (KM_MEMCPY0 - KM_MEMCPY1);
+       type1 = kmap_atomic_idx_push();
+       idx += (type0 - type1);
        src_pte = hv_pte_set_nc(src_pte);
        src_pte = hv_pte_clear_writable(src_pte);  /* be paranoid */
        newsrc = __fix_to_virt(idx) + ((unsigned long)source & (PAGE_SIZE-1));
@@ -119,6 +122,8 @@ static void memcpy_multicache(void *dest, const void *source,
         * We're done: notify the simulator that all is back to normal,
         * and re-enable interrupts and pre-emption.
         */
+       kmap_atomic_idx_pop();
+       kmap_atomic_idx_pop();
        sim_allow_multiple_caching(0);
        local_irq_restore(flags);
        put_cpu();
index abb5733..31dbbd9 100644 (file)
@@ -227,7 +227,7 @@ EXPORT_SYMBOL(kmap_atomic_prot);
 void *__kmap_atomic(struct page *page)
 {
        /* PAGE_NONE is a magic value that tells us to check immutability. */
-       return kmap_atomic_prot(page, type, PAGE_NONE);
+       return kmap_atomic_prot(page, PAGE_NONE);
 }
 EXPORT_SYMBOL(__kmap_atomic);
 
index 78e1982..0b9ce69 100644 (file)
@@ -988,8 +988,12 @@ static long __write_once initfree = 1;
 /* Select whether to free (1) or mark unusable (0) the __init pages. */
 static int __init set_initfree(char *str)
 {
-       strict_strtol(str, 0, &initfree);
-       pr_info("initfree: %s free init pages\n", initfree ? "will" : "won't");
+       long val;
+       if (strict_strtol(str, 0, &val)) {
+               initfree = val;
+               pr_info("initfree: %s free init pages\n",
+                       initfree ? "will" : "won't");
+       }
        return 1;
 }
 __setup("initfree=", set_initfree);
index 335c246..1f5430c 100644 (file)
@@ -134,9 +134,9 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
 }
 
 #if defined(CONFIG_HIGHPTE)
-pte_t *_pte_offset_map(pmd_t *dir, unsigned long address, enum km_type type)
+pte_t *_pte_offset_map(pmd_t *dir, unsigned long address)
 {
-       pte_t *pte = kmap_atomic(pmd_page(*dir), type) +
+       pte_t *pte = kmap_atomic(pmd_page(*dir)) +
                (pmd_ptfn(*dir) << HV_LOG2_PAGE_TABLE_ALIGN) & ~PAGE_MASK;
        return &pte[pte_index(address)];
 }
index 2cd899f..b7c5bab 100644 (file)
@@ -38,8 +38,8 @@ struct pt_regs {
 
 struct task_struct;
 
-extern long subarch_ptrace(struct task_struct *child, long request, long addr,
-                          long data);
+extern long subarch_ptrace(struct task_struct *child, long request,
+       unsigned long addr, unsigned long data);
 extern unsigned long getreg(struct task_struct *child, int regno);
 extern int putreg(struct task_struct *child, int regno, unsigned long value);
 extern int get_fpregs(struct user_i387_struct __user *buf,
index a5e33f2..701b672 100644 (file)
@@ -122,7 +122,7 @@ long arch_ptrace(struct task_struct *child, long request,
                break;
 
        case PTRACE_SET_THREAD_AREA:
-               ret = ptrace_set_thread_area(child, addr, datavp);
+               ret = ptrace_set_thread_area(child, addr, vp);
                break;
 
        case PTRACE_FAULTINFO: {
index 908ea54..fb8b376 100644 (file)
@@ -720,7 +720,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
        }
 }
 
-static void set_spte_track_bits(u64 *sptep, u64 new_spte)
+static int set_spte_track_bits(u64 *sptep, u64 new_spte)
 {
        pfn_t pfn;
        u64 old_spte = *sptep;
@@ -731,19 +731,20 @@ static void set_spte_track_bits(u64 *sptep, u64 new_spte)
                old_spte = __xchg_spte(sptep, new_spte);
 
        if (!is_rmap_spte(old_spte))
-               return;
+               return 0;
 
        pfn = spte_to_pfn(old_spte);
        if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
                kvm_set_pfn_accessed(pfn);
        if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask))
                kvm_set_pfn_dirty(pfn);
+       return 1;
 }
 
 static void drop_spte(struct kvm *kvm, u64 *sptep, u64 new_spte)
 {
-       set_spte_track_bits(sptep, new_spte);
-       rmap_remove(kvm, sptep);
+       if (set_spte_track_bits(sptep, new_spte))
+               rmap_remove(kvm, sptep);
 }
 
 static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
index 2288ad8..cdac9e5 100644 (file)
@@ -2560,6 +2560,7 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
                !kvm_exception_is_soft(vcpu->arch.exception.nr);
        events->exception.nr = vcpu->arch.exception.nr;
        events->exception.has_error_code = vcpu->arch.exception.has_error_code;
+       events->exception.pad = 0;
        events->exception.error_code = vcpu->arch.exception.error_code;
 
        events->interrupt.injected =
@@ -2573,12 +2574,14 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
        events->nmi.injected = vcpu->arch.nmi_injected;
        events->nmi.pending = vcpu->arch.nmi_pending;
        events->nmi.masked = kvm_x86_ops->get_nmi_mask(vcpu);
+       events->nmi.pad = 0;
 
        events->sipi_vector = vcpu->arch.sipi_vector;
 
        events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
                         | KVM_VCPUEVENT_VALID_SIPI_VECTOR
                         | KVM_VCPUEVENT_VALID_SHADOW);
+       memset(&events->reserved, 0, sizeof(events->reserved));
 }
 
 static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
@@ -2623,6 +2626,7 @@ static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
        dbgregs->dr6 = vcpu->arch.dr6;
        dbgregs->dr7 = vcpu->arch.dr7;
        dbgregs->flags = 0;
+       memset(&dbgregs->reserved, 0, sizeof(dbgregs->reserved));
 }
 
 static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
@@ -3106,6 +3110,7 @@ static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
                sizeof(ps->channels));
        ps->flags = kvm->arch.vpit->pit_state.flags;
        mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+       memset(&ps->reserved, 0, sizeof(ps->reserved));
        return r;
 }
 
@@ -3169,10 +3174,6 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
                struct kvm_memslots *slots, *old_slots;
                unsigned long *dirty_bitmap;
 
-               spin_lock(&kvm->mmu_lock);
-               kvm_mmu_slot_remove_write_access(kvm, log->slot);
-               spin_unlock(&kvm->mmu_lock);
-
                r = -ENOMEM;
                dirty_bitmap = vmalloc(n);
                if (!dirty_bitmap)
@@ -3194,6 +3195,10 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
                dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap;
                kfree(old_slots);
 
+               spin_lock(&kvm->mmu_lock);
+               kvm_mmu_slot_remove_write_access(kvm, log->slot);
+               spin_unlock(&kvm->mmu_lock);
+
                r = -EFAULT;
                if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n)) {
                        vfree(dirty_bitmap);
@@ -3486,6 +3491,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
                user_ns.clock = kvm->arch.kvmclock_offset + now_ns;
                local_irq_enable();
                user_ns.flags = 0;
+               memset(&user_ns.pad, 0, sizeof(user_ns.pad));
 
                r = -EFAULT;
                if (copy_to_user(argp, &user_ns, sizeof(user_ns)))
@@ -3972,8 +3978,10 @@ int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu)
                return X86EMUL_CONTINUE;
 
        if (kvm_x86_ops->has_wbinvd_exit()) {
+               preempt_disable();
                smp_call_function_many(vcpu->arch.wbinvd_dirty_mask,
                                wbinvd_ipi, NULL, 1);
+               preempt_enable();
                cpumask_clear(vcpu->arch.wbinvd_dirty_mask);
        }
        wbinvd();
index de30782..75586f1 100644 (file)
@@ -504,7 +504,6 @@ err:
 
 static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt)
 {
-       kobject_put(&pcrypt->pinst->kobj);
        free_cpumask_var(pcrypt->cb_cpumask->mask);
        kfree(pcrypt->cb_cpumask);
 
index 14cf907..f3ebb30 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_REGULATOR)               += regulator/
 
 # char/ comes before serial/ etc so that the VT console is the boot-time
 # default.
+obj-y                          += tty/
 obj-y                          += char/
 
 # gpu/ comes after char for AGP vs DRM startup
index 767107c..3951020 100644 (file)
@@ -4363,9 +4363,9 @@ out_unreg_blkdev:
 out_put_disk:
        while (dr--) {
                del_timer(&motor_off_timer[dr]);
-               put_disk(disks[dr]);
                if (disks[dr]->queue)
                        blk_cleanup_queue(disks[dr]->queue);
+               put_disk(disks[dr]);
        }
        return err;
 }
@@ -4573,8 +4573,8 @@ static void __exit floppy_module_exit(void)
                        device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
                        platform_device_unregister(&floppy_device[drive]);
                }
-               put_disk(disks[drive]);
                blk_cleanup_queue(disks[drive]->queue);
+               put_disk(disks[drive]);
        }
 
        del_timer_sync(&fd_timeout);
index 3a9c014..ba53ec9 100644 (file)
@@ -2,24 +2,10 @@
 # Makefile for the kernel character device drivers.
 #
 
-#
-# This file contains the font map for the default (hardware) font
-#
-FONTMAPFILE = cp437.uni
-
-obj-y   += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
-
-obj-y                          += tty_mutex.o
-obj-$(CONFIG_LEGACY_PTYS)      += pty.o
-obj-$(CONFIG_UNIX98_PTYS)      += pty.o
+obj-y                          += mem.o random.o
 obj-$(CONFIG_TTY_PRINTK)       += ttyprintk.o
 obj-y                          += misc.o
-obj-$(CONFIG_VT)               += vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)   += bfin_jtag_comm.o
-obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
-obj-$(CONFIG_HW_CONSOLE)       += vt.o defkeymap.o
-obj-$(CONFIG_AUDIT)            += tty_audit.o
-obj-$(CONFIG_MAGIC_SYSRQ)      += sysrq.o
 obj-$(CONFIG_MVME147_SCC)      += generic_serial.o vme_scc.o
 obj-$(CONFIG_MVME162_SCC)      += generic_serial.o vme_scc.o
 obj-$(CONFIG_BVME6000_SCC)     += generic_serial.o vme_scc.o
@@ -41,8 +27,6 @@ obj-$(CONFIG_ISI)             += isicom.o
 obj-$(CONFIG_SYNCLINK)         += synclink.o
 obj-$(CONFIG_SYNCLINKMP)       += synclinkmp.o
 obj-$(CONFIG_SYNCLINK_GT)      += synclink_gt.o
-obj-$(CONFIG_N_HDLC)           += n_hdlc.o
-obj-$(CONFIG_N_GSM)            += n_gsm.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)               += sx.o generic_serial.o
 obj-$(CONFIG_RIO)              += rio/ generic_serial.o
@@ -74,7 +58,6 @@ obj-$(CONFIG_PRINTER)         += lp.o
 obj-$(CONFIG_APM_EMULATION)    += apm-emulation.o
 
 obj-$(CONFIG_DTLK)             += dtlk.o
-obj-$(CONFIG_R3964)            += n_r3964.o
 obj-$(CONFIG_APPLICOM)         += applicom.o
 obj-$(CONFIG_SONYPI)           += sonypi.o
 obj-$(CONFIG_RTC)              += rtc.o
@@ -115,28 +98,3 @@ obj-$(CONFIG_RAMOOPS)               += ramoops.o
 
 obj-$(CONFIG_JS_RTC)           += js-rtc.o
 js-rtc-y = rtc.o
-
-# Files generated that shall be removed upon make clean
-clean-files := consolemap_deftbl.c defkeymap.c
-
-quiet_cmd_conmk = CONMK   $@
-      cmd_conmk = scripts/conmakehash $< > $@
-
-$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
-       $(call cmd,conmk)
-
-$(obj)/defkeymap.o:  $(obj)/defkeymap.c
-
-# Uncomment if you're changing the keymap and have an appropriate
-# loadkeys version for the map. By default, we'll use the shipped
-# versions.
-# GENERATE_KEYMAP := 1
-
-ifdef GENERATE_KEYMAP
-
-$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
-       loadkeys --mktable $< > $@.tmp
-       sed -e 's/^static *//' $@.tmp > $@
-       rm $@.tmp
-
-endif
index a446116..d68d3aa 100644 (file)
@@ -616,13 +616,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "cmt_fck");
        if (IS_ERR(p->clk)) {
-               dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-               p->clk = clk_get(&p->pdev->dev, cfg->clk);
-               if (IS_ERR(p->clk)) {
-                       dev_err(&p->pdev->dev, "cannot get clock\n");
-                       ret = PTR_ERR(p->clk);
-                       goto err1;
-               }
+               dev_err(&p->pdev->dev, "cannot get clock\n");
+               ret = PTR_ERR(p->clk);
+               goto err1;
        }
 
        if (resource_size(res) == 6) {
index ef7a5be..40630cb 100644 (file)
@@ -287,13 +287,9 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "mtu2_fck");
        if (IS_ERR(p->clk)) {
-               dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-               p->clk = clk_get(&p->pdev->dev, cfg->clk);
-               if (IS_ERR(p->clk)) {
-                       dev_err(&p->pdev->dev, "cannot get clock\n");
-                       ret = PTR_ERR(p->clk);
-                       goto err1;
-               }
+               dev_err(&p->pdev->dev, "cannot get clock\n");
+               ret = PTR_ERR(p->clk);
+               goto err1;
        }
 
        return sh_mtu2_register(p, (char *)dev_name(&p->pdev->dev),
index de71590..36aba99 100644 (file)
@@ -393,13 +393,9 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "tmu_fck");
        if (IS_ERR(p->clk)) {
-               dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-               p->clk = clk_get(&p->pdev->dev, cfg->clk);
-               if (IS_ERR(p->clk)) {
-                       dev_err(&p->pdev->dev, "cannot get clock\n");
-                       ret = PTR_ERR(p->clk);
-                       goto err1;
-               }
+               dev_err(&p->pdev->dev, "cannot get clock\n");
+               ret = PTR_ERR(p->clk);
+               goto err1;
        }
 
        return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev),
index 9dcb17d..84eb607 100644 (file)
@@ -577,17 +577,11 @@ static int ohci_update_phy_reg(struct fw_card *card, int addr,
        return ret;
 }
 
-static int ar_context_add_page(struct ar_context *ctx)
+static void ar_context_link_page(struct ar_context *ctx,
+                                struct ar_buffer *ab, dma_addr_t ab_bus)
 {
-       struct device *dev = ctx->ohci->card.device;
-       struct ar_buffer *ab;
-       dma_addr_t uninitialized_var(ab_bus);
        size_t offset;
 
-       ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
-       if (ab == NULL)
-               return -ENOMEM;
-
        ab->next = NULL;
        memset(&ab->descriptor, 0, sizeof(ab->descriptor));
        ab->descriptor.control        = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
@@ -606,6 +600,19 @@ static int ar_context_add_page(struct ar_context *ctx)
 
        reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
        flush_writes(ctx->ohci);
+}
+
+static int ar_context_add_page(struct ar_context *ctx)
+{
+       struct device *dev = ctx->ohci->card.device;
+       struct ar_buffer *ab;
+       dma_addr_t uninitialized_var(ab_bus);
+
+       ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
+       if (ab == NULL)
+               return -ENOMEM;
+
+       ar_context_link_page(ctx, ab, ab_bus);
 
        return 0;
 }
@@ -730,16 +737,17 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
 static void ar_context_tasklet(unsigned long data)
 {
        struct ar_context *ctx = (struct ar_context *)data;
-       struct fw_ohci *ohci = ctx->ohci;
        struct ar_buffer *ab;
        struct descriptor *d;
        void *buffer, *end;
+       __le16 res_count;
 
        ab = ctx->current_buffer;
        d = &ab->descriptor;
 
-       if (d->res_count == 0) {
-               size_t size, rest, offset;
+       res_count = ACCESS_ONCE(d->res_count);
+       if (res_count == 0) {
+               size_t size, size2, rest, pktsize, size3, offset;
                dma_addr_t start_bus;
                void *start;
 
@@ -750,29 +758,63 @@ static void ar_context_tasklet(unsigned long data)
                 */
 
                offset = offsetof(struct ar_buffer, data);
-               start = buffer = ab;
+               start = ab;
                start_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
+               buffer = ab->data;
 
                ab = ab->next;
                d = &ab->descriptor;
-               size = buffer + PAGE_SIZE - ctx->pointer;
+               size = start + PAGE_SIZE - ctx->pointer;
+               /* valid buffer data in the next page */
                rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count);
+               /* what actually fits in this page */
+               size2 = min(rest, (size_t)PAGE_SIZE - offset - size);
                memmove(buffer, ctx->pointer, size);
-               memcpy(buffer + size, ab->data, rest);
-               ctx->current_buffer = ab;
-               ctx->pointer = (void *) ab->data + rest;
-               end = buffer + size + rest;
+               memcpy(buffer + size, ab->data, size2);
+
+               while (size > 0) {
+                       void *next = handle_ar_packet(ctx, buffer);
+                       pktsize = next - buffer;
+                       if (pktsize >= size) {
+                               /*
+                                * We have handled all the data that was
+                                * originally in this page, so we can now
+                                * continue in the next page.
+                                */
+                               buffer = next;
+                               break;
+                       }
+                       /* move the next packet to the start of the buffer */
+                       memmove(buffer, next, size + size2 - pktsize);
+                       size -= pktsize;
+                       /* fill up this page again */
+                       size3 = min(rest - size2,
+                                   (size_t)PAGE_SIZE - offset - size - size2);
+                       memcpy(buffer + size + size2,
+                              (void *) ab->data + size2, size3);
+                       size2 += size3;
+               }
 
-               while (buffer < end)
-                       buffer = handle_ar_packet(ctx, buffer);
+               if (rest > 0) {
+                       /* handle the packets that are fully in the next page */
+                       buffer = (void *) ab->data +
+                                       (buffer - (start + offset + size));
+                       end = (void *) ab->data + rest;
+
+                       while (buffer < end)
+                               buffer = handle_ar_packet(ctx, buffer);
 
-               dma_free_coherent(ohci->card.device, PAGE_SIZE,
-                                 start, start_bus);
-               ar_context_add_page(ctx);
+                       ctx->current_buffer = ab;
+                       ctx->pointer = end;
+
+                       ar_context_link_page(ctx, start, start_bus);
+               } else {
+                       ctx->pointer = start + PAGE_SIZE;
+               }
        } else {
                buffer = ctx->pointer;
                ctx->pointer = end =
-                       (void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count);
+                       (void *) ab + PAGE_SIZE - le16_to_cpu(res_count);
 
                while (buffer < end)
                        buffer = handle_ar_packet(ctx, buffer);
index 2676261..4b50601 100644 (file)
@@ -82,7 +82,7 @@ static struct ltc4261_data *ltc4261_update_device(struct device *dev)
                        val = i2c_smbus_read_byte_data(client, i);
                        if (unlikely(val < 0)) {
                                dev_dbg(dev,
-                                       "Failed to read ADC value: error %d",
+                                       "Failed to read ADC value: error %d\n",
                                        val);
                                ret = ERR_PTR(val);
                                goto abort;
@@ -230,8 +230,7 @@ static int ltc4261_probe(struct i2c_client *client,
                return -ENODEV;
 
        if (i2c_smbus_read_byte_data(client, LTC4261_STATUS) < 0) {
-               dev_err(&client->dev, "Failed to read register %d:%02x:%02x\n",
-                       adapter->id, client->addr, LTC4261_STATUS);
+               dev_err(&client->dev, "Failed to read status register\n");
                return -ENODEV;
        }
 
index 40b914b..2e72227 100644 (file)
@@ -1427,8 +1427,8 @@ modeisar(struct BCState *bcs, int mode, int bc)
                                        &bcs->hw.isar.reg->Flags))
                                        bcs->hw.isar.dpath = 1;
                                else {
-                                       printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n");
-                                       debugl1(cs, "isar modeisar analog funktions only with DP1");
+                                       printk(KERN_WARNING"isar modeisar analog functions only with DP1\n");
+                                       debugl1(cs, "isar modeisar analog functions only with DP1");
                                        return(1);
                                }
                                break;
index cc2a88d..77b8fd2 100644 (file)
@@ -10,7 +10,7 @@ menuconfig NEW_LEDS
 if NEW_LEDS
 
 config LEDS_CLASS
-       tristate "LED Class Support"
+       bool "LED Class Support"
        help
          This option enables the led sysfs class in /sys/class/leds.  You'll
          need this to do anything useful with LEDs.  If unsure, say N.
@@ -176,6 +176,24 @@ config LEDS_LP3944
          To compile this driver as a module, choose M here: the
          module will be called leds-lp3944.
 
+config LEDS_LP5521
+       tristate "LED Support for N.S. LP5521 LED driver chip"
+       depends on LEDS_CLASS && I2C
+       help
+         If you say yes here you get support for the National Semiconductor
+         LP5521 LED driver. It is 3 channel chip with programmable engines.
+         Driver provides direct control via LED class and interface for
+         programming the engines.
+
+config LEDS_LP5523
+       tristate "LED Support for N.S. LP5523 LED driver chip"
+       depends on LEDS_CLASS && I2C
+       help
+         If you say yes here you get support for the National Semiconductor
+         LP5523 LED driver. It is 9 channel chip with programmable engines.
+         Driver provides direct control via LED class and interface for
+         programming the engines.
+
 config LEDS_CLEVO_MAIL
        tristate "Mail LED on Clevo notebook"
        depends on X86 && SERIO_I8042 && DMI
index 9c96db4..aae6989 100644 (file)
@@ -23,6 +23,8 @@ obj-$(CONFIG_LEDS_SUNFIRE)            += leds-sunfire.o
 obj-$(CONFIG_LEDS_PCA9532)             += leds-pca9532.o
 obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
 obj-$(CONFIG_LEDS_LP3944)              += leds-lp3944.o
+obj-$(CONFIG_LEDS_LP5521)              += leds-lp5521.o
+obj-$(CONFIG_LEDS_LP5523)              += leds-lp5523.o
 obj-$(CONFIG_LEDS_CLEVO_MAIL)          += leds-clevo-mail.o
 obj-$(CONFIG_LEDS_HP6XX)               += leds-hp6xx.o
 obj-$(CONFIG_LEDS_FSG)                 += leds-fsg.o
index 2606600..211e21f 100644 (file)
@@ -81,6 +81,79 @@ static struct device_attribute led_class_attrs[] = {
        __ATTR_NULL,
 };
 
+static void led_timer_function(unsigned long data)
+{
+       struct led_classdev *led_cdev = (void *)data;
+       unsigned long brightness;
+       unsigned long delay;
+
+       if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
+               led_set_brightness(led_cdev, LED_OFF);
+               return;
+       }
+
+       brightness = led_get_brightness(led_cdev);
+       if (!brightness) {
+               /* Time to switch the LED on. */
+               brightness = led_cdev->blink_brightness;
+               delay = led_cdev->blink_delay_on;
+       } else {
+               /* Store the current brightness value to be able
+                * to restore it when the delay_off period is over.
+                */
+               led_cdev->blink_brightness = brightness;
+               brightness = LED_OFF;
+               delay = led_cdev->blink_delay_off;
+       }
+
+       led_set_brightness(led_cdev, brightness);
+
+       mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
+}
+
+static void led_stop_software_blink(struct led_classdev *led_cdev)
+{
+       /* deactivate previous settings */
+       del_timer_sync(&led_cdev->blink_timer);
+       led_cdev->blink_delay_on = 0;
+       led_cdev->blink_delay_off = 0;
+}
+
+static void led_set_software_blink(struct led_classdev *led_cdev,
+                                  unsigned long delay_on,
+                                  unsigned long delay_off)
+{
+       int current_brightness;
+
+       current_brightness = led_get_brightness(led_cdev);
+       if (current_brightness)
+               led_cdev->blink_brightness = current_brightness;
+       if (!led_cdev->blink_brightness)
+               led_cdev->blink_brightness = led_cdev->max_brightness;
+
+       if (delay_on == led_cdev->blink_delay_on &&
+           delay_off == led_cdev->blink_delay_off)
+               return;
+
+       led_stop_software_blink(led_cdev);
+
+       led_cdev->blink_delay_on = delay_on;
+       led_cdev->blink_delay_off = delay_off;
+
+       /* never on - don't blink */
+       if (!delay_on)
+               return;
+
+       /* never off - just set to brightness */
+       if (!delay_off) {
+               led_set_brightness(led_cdev, led_cdev->blink_brightness);
+               return;
+       }
+
+       mod_timer(&led_cdev->blink_timer, jiffies + 1);
+}
+
+
 /**
  * led_classdev_suspend - suspend an led_classdev.
  * @led_cdev: the led_classdev to suspend.
@@ -148,6 +221,10 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 
        led_update_brightness(led_cdev);
 
+       init_timer(&led_cdev->blink_timer);
+       led_cdev->blink_timer.function = led_timer_function;
+       led_cdev->blink_timer.data = (unsigned long)led_cdev;
+
 #ifdef CONFIG_LEDS_TRIGGERS
        led_trigger_set_default(led_cdev);
 #endif
@@ -157,7 +234,6 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 
        return 0;
 }
-
 EXPORT_SYMBOL_GPL(led_classdev_register);
 
 /**
@@ -175,6 +251,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
        up_write(&led_cdev->trigger_lock);
 #endif
 
+       /* Stop blinking */
+       led_brightness_set(led_cdev, LED_OFF);
+
        device_unregister(led_cdev->dev);
 
        down_write(&leds_list_lock);
@@ -183,6 +262,30 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
 }
 EXPORT_SYMBOL_GPL(led_classdev_unregister);
 
+void led_blink_set(struct led_classdev *led_cdev,
+                  unsigned long *delay_on,
+                  unsigned long *delay_off)
+{
+       if (led_cdev->blink_set &&
+           led_cdev->blink_set(led_cdev, delay_on, delay_off))
+               return;
+
+       /* blink with 1 Hz as default if nothing specified */
+       if (!*delay_on && !*delay_off)
+               *delay_on = *delay_off = 500;
+
+       led_set_software_blink(led_cdev, *delay_on, *delay_off);
+}
+EXPORT_SYMBOL(led_blink_set);
+
+void led_brightness_set(struct led_classdev *led_cdev,
+                       enum led_brightness brightness)
+{
+       led_stop_software_blink(led_cdev);
+       led_cdev->brightness_set(led_cdev, brightness);
+}
+EXPORT_SYMBOL(led_brightness_set);
+
 static int __init leds_init(void)
 {
        leds_class = class_create(THIS_MODULE, "leds");
index f1c00db..c41eb61 100644 (file)
@@ -113,7 +113,7 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
                if (led_cdev->trigger->deactivate)
                        led_cdev->trigger->deactivate(led_cdev);
                led_cdev->trigger = NULL;
-               led_set_brightness(led_cdev, LED_OFF);
+               led_brightness_set(led_cdev, LED_OFF);
        }
        if (trigger) {
                write_lock_irqsave(&trigger->leddev_list_lock, flags);
index ea57e05..4d9fa38 100644 (file)
@@ -316,7 +316,7 @@ static struct of_platform_driver of_gpio_leds_driver = {
 
 static int __init gpio_led_init(void)
 {
-       int ret;
+       int ret = 0;
 
 #ifdef CONFIG_LEDS_GPIO_PLATFORM       
        ret = platform_driver_register(&gpio_led_driver);
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
new file mode 100644 (file)
index 0000000..3782f31
--- /dev/null
@@ -0,0 +1,821 @@
+/*
+ * LP5521 LED chip driver.
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.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/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/leds.h>
+#include <linux/leds-lp5521.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#define LP5521_PROGRAM_LENGTH          32      /* in bytes */
+
+#define LP5521_MAX_LEDS                        3       /* Maximum number of LEDs */
+#define LP5521_MAX_ENGINES             3       /* Maximum number of engines */
+
+#define LP5521_ENG_MASK_BASE           0x30    /* 00110000 */
+#define LP5521_ENG_STATUS_MASK         0x07    /* 00000111 */
+
+#define LP5521_CMD_LOAD                        0x15    /* 00010101 */
+#define LP5521_CMD_RUN                 0x2a    /* 00101010 */
+#define LP5521_CMD_DIRECT              0x3f    /* 00111111 */
+#define LP5521_CMD_DISABLED            0x00    /* 00000000 */
+
+/* Registers */
+#define LP5521_REG_ENABLE              0x00
+#define LP5521_REG_OP_MODE             0x01
+#define LP5521_REG_R_PWM               0x02
+#define LP5521_REG_G_PWM               0x03
+#define LP5521_REG_B_PWM               0x04
+#define LP5521_REG_R_CURRENT           0x05
+#define LP5521_REG_G_CURRENT           0x06
+#define LP5521_REG_B_CURRENT           0x07
+#define LP5521_REG_CONFIG              0x08
+#define LP5521_REG_R_CHANNEL_PC                0x09
+#define LP5521_REG_G_CHANNEL_PC                0x0A
+#define LP5521_REG_B_CHANNEL_PC                0x0B
+#define LP5521_REG_STATUS              0x0C
+#define LP5521_REG_RESET               0x0D
+#define LP5521_REG_GPO                 0x0E
+#define LP5521_REG_R_PROG_MEM          0x10
+#define LP5521_REG_G_PROG_MEM          0x30
+#define LP5521_REG_B_PROG_MEM          0x50
+
+#define LP5521_PROG_MEM_BASE           LP5521_REG_R_PROG_MEM
+#define LP5521_PROG_MEM_SIZE           0x20
+
+/* Base register to set LED current */
+#define LP5521_REG_LED_CURRENT_BASE    LP5521_REG_R_CURRENT
+
+/* Base register to set the brightness */
+#define LP5521_REG_LED_PWM_BASE                LP5521_REG_R_PWM
+
+/* Bits in ENABLE register */
+#define LP5521_MASTER_ENABLE           0x40    /* Chip master enable */
+#define LP5521_LOGARITHMIC_PWM         0x80    /* Logarithmic PWM adjustment */
+#define LP5521_EXEC_RUN                        0x2A
+
+/* Bits in CONFIG register */
+#define LP5521_PWM_HF                  0x40    /* PWM: 0 = 256Hz, 1 = 558Hz */
+#define LP5521_PWRSAVE_EN              0x20    /* 1 = Power save mode */
+#define LP5521_CP_MODE_OFF             0       /* Charge pump (CP) off */
+#define LP5521_CP_MODE_BYPASS          8       /* CP forced to bypass mode */
+#define LP5521_CP_MODE_1X5             0x10    /* CP forced to 1.5x mode */
+#define LP5521_CP_MODE_AUTO            0x18    /* Automatic mode selection */
+#define LP5521_R_TO_BATT               4       /* R out: 0 = CP, 1 = Vbat */
+#define LP5521_CLK_SRC_EXT             0       /* Ext-clk source (CLK_32K) */
+#define LP5521_CLK_INT                 1       /* Internal clock */
+#define LP5521_CLK_AUTO                        2       /* Automatic clock selection */
+
+/* Status */
+#define LP5521_EXT_CLK_USED            0x08
+
+struct lp5521_engine {
+       const struct attribute_group *attributes;
+       int             id;
+       u8              mode;
+       u8              prog_page;
+       u8              engine_mask;
+};
+
+struct lp5521_led {
+       int                     id;
+       u8                      chan_nr;
+       u8                      led_current;
+       u8                      max_current;
+       struct led_classdev     cdev;
+       struct work_struct      brightness_work;
+       u8                      brightness;
+};
+
+struct lp5521_chip {
+       struct lp5521_platform_data *pdata;
+       struct mutex            lock; /* Serialize control */
+       struct i2c_client       *client;
+       struct lp5521_engine    engines[LP5521_MAX_ENGINES];
+       struct lp5521_led       leds[LP5521_MAX_LEDS];
+       u8                      num_channels;
+       u8                      num_leds;
+};
+
+#define cdev_to_led(c)         container_of(c, struct lp5521_led, cdev)
+#define engine_to_lp5521(eng)  container_of((eng), struct lp5521_chip, \
+                                               engines[(eng)->id - 1])
+#define led_to_lp5521(led)     container_of((led), struct lp5521_chip, \
+                                               leds[(led)->id])
+
+static void lp5521_led_brightness_work(struct work_struct *work);
+
+static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf)
+{
+       s32 ret;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       if (ret < 0)
+               return -EIO;
+
+       *buf = ret;
+       return 0;
+}
+
+static int lp5521_set_engine_mode(struct lp5521_engine *engine, u8 mode)
+{
+       struct lp5521_chip *chip = engine_to_lp5521(engine);
+       struct i2c_client *client = chip->client;
+       int ret;
+       u8 engine_state;
+
+       /* Only transition between RUN and DIRECT mode are handled here */
+       if (mode == LP5521_CMD_LOAD)
+               return 0;
+
+       if (mode == LP5521_CMD_DISABLED)
+               mode = LP5521_CMD_DIRECT;
+
+       ret = lp5521_read(client, LP5521_REG_OP_MODE, &engine_state);
+
+       /* set mode only for this engine */
+       engine_state &= ~(engine->engine_mask);
+       mode &= engine->engine_mask;
+       engine_state |= mode;
+       ret |= lp5521_write(client, LP5521_REG_OP_MODE, engine_state);
+
+       return ret;
+}
+
+static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern)
+{
+       struct lp5521_chip *chip = engine_to_lp5521(eng);
+       struct i2c_client *client = chip->client;
+       int ret;
+       int addr;
+       u8 mode;
+
+       /* move current engine to direct mode and remember the state */
+       ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT);
+       usleep_range(1000, 10000);
+       ret |= lp5521_read(client, LP5521_REG_OP_MODE, &mode);
+
+       /* For loading, all the engines to load mode */
+       lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT);
+       usleep_range(1000, 10000);
+       lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_LOAD);
+       usleep_range(1000, 10000);
+
+       addr = LP5521_PROG_MEM_BASE + eng->prog_page * LP5521_PROG_MEM_SIZE;
+       i2c_smbus_write_i2c_block_data(client,
+                               addr,
+                               LP5521_PROG_MEM_SIZE,
+                               pattern);
+
+       ret |= lp5521_write(client, LP5521_REG_OP_MODE, mode);
+       return ret;
+}
+
+static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr)
+{
+       return lp5521_write(chip->client,
+                   LP5521_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr,
+                   curr);
+}
+
+static void lp5521_init_engine(struct lp5521_chip *chip,
+                       const struct attribute_group *attr_group)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(chip->engines); i++) {
+               chip->engines[i].id = i + 1;
+               chip->engines[i].engine_mask = LP5521_ENG_MASK_BASE >> (i * 2);
+               chip->engines[i].prog_page = i;
+               chip->engines[i].attributes = &attr_group[i];
+       }
+}
+
+static int lp5521_configure(struct i2c_client *client,
+                       const struct attribute_group *attr_group)
+{
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       int ret;
+
+       lp5521_init_engine(chip, attr_group);
+
+       lp5521_write(client, LP5521_REG_RESET, 0xff);
+
+       usleep_range(10000, 20000);
+
+       /* Set all PWMs to direct control mode */
+       ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F);
+
+       /* Enable auto-powersave, set charge pump to auto, red to battery */
+       ret |= lp5521_write(client, LP5521_REG_CONFIG,
+               LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT);
+
+       /* Initialize all channels PWM to zero -> leds off */
+       ret |= lp5521_write(client, LP5521_REG_R_PWM, 0);
+       ret |= lp5521_write(client, LP5521_REG_G_PWM, 0);
+       ret |= lp5521_write(client, LP5521_REG_B_PWM, 0);
+
+       /* Set engines are set to run state when OP_MODE enables engines */
+       ret |= lp5521_write(client, LP5521_REG_ENABLE,
+                       LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM |
+                       LP5521_EXEC_RUN);
+       /* enable takes 500us */
+       usleep_range(500, 20000);
+
+       return ret;
+}
+
+static int lp5521_run_selftest(struct lp5521_chip *chip, char *buf)
+{
+       int ret;
+       u8 status;
+
+       ret = lp5521_read(chip->client, LP5521_REG_STATUS, &status);
+       if (ret < 0)
+               return ret;
+
+       /* Check that ext clock is really in use if requested */
+       if (chip->pdata && chip->pdata->clock_mode == LP5521_CLOCK_EXT)
+               if  ((status & LP5521_EXT_CLK_USED) == 0)
+                       return -EIO;
+       return 0;
+}
+
+static void lp5521_set_brightness(struct led_classdev *cdev,
+                            enum led_brightness brightness)
+{
+       struct lp5521_led *led = cdev_to_led(cdev);
+       led->brightness = (u8)brightness;
+       schedule_work(&led->brightness_work);
+}
+
+static void lp5521_led_brightness_work(struct work_struct *work)
+{
+       struct lp5521_led *led = container_of(work,
+                                             struct lp5521_led,
+                                             brightness_work);
+       struct lp5521_chip *chip = led_to_lp5521(led);
+       struct i2c_client *client = chip->client;
+
+       mutex_lock(&chip->lock);
+       lp5521_write(client, LP5521_REG_LED_PWM_BASE + led->chan_nr,
+               led->brightness);
+       mutex_unlock(&chip->lock);
+}
+
+/* Detect the chip by setting its ENABLE register and reading it back. */
+static int lp5521_detect(struct i2c_client *client)
+{
+       int ret;
+       u8 buf;
+
+       ret = lp5521_write(client, LP5521_REG_ENABLE,
+                       LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM);
+       if (ret)
+               return ret;
+       usleep_range(1000, 10000);
+       ret = lp5521_read(client, LP5521_REG_ENABLE, &buf);
+       if (ret)
+               return ret;
+       if (buf != (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM))
+               return -ENODEV;
+
+       return 0;
+}
+
+/* Set engine mode and create appropriate sysfs attributes, if required. */
+static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode)
+{
+       struct lp5521_chip *chip = engine_to_lp5521(engine);
+       struct i2c_client *client = chip->client;
+       struct device *dev = &client->dev;
+       int ret = 0;
+
+       /* if in that mode already do nothing, except for run */
+       if (mode == engine->mode && mode != LP5521_CMD_RUN)
+               return 0;
+
+       if (mode == LP5521_CMD_RUN) {
+               ret = lp5521_set_engine_mode(engine, LP5521_CMD_RUN);
+       } else if (mode == LP5521_CMD_LOAD) {
+               lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED);
+               lp5521_set_engine_mode(engine, LP5521_CMD_LOAD);
+
+               ret = sysfs_create_group(&dev->kobj, engine->attributes);
+               if (ret)
+                       return ret;
+       } else if (mode == LP5521_CMD_DISABLED) {
+               lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED);
+       }
+
+       /* remove load attribute from sysfs if not in load mode */
+       if (engine->mode == LP5521_CMD_LOAD && mode != LP5521_CMD_LOAD)
+               sysfs_remove_group(&dev->kobj, engine->attributes);
+
+       engine->mode = mode;
+
+       return ret;
+}
+
+static int lp5521_do_store_load(struct lp5521_engine *engine,
+                               const char *buf, size_t len)
+{
+       struct lp5521_chip *chip = engine_to_lp5521(engine);
+       struct i2c_client *client = chip->client;
+       int  ret, nrchars, offset = 0, i = 0;
+       char c[3];
+       unsigned cmd;
+       u8 pattern[LP5521_PROGRAM_LENGTH] = {0};
+
+       while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) {
+               /* separate sscanfs because length is working only for %s */
+               ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
+               ret = sscanf(c, "%2x", &cmd);
+               if (ret != 1)
+                       goto fail;
+               pattern[i] = (u8)cmd;
+
+               offset += nrchars;
+               i++;
+       }
+
+       /* Each instruction is 16bit long. Check that length is even */
+       if (i % 2)
+               goto fail;
+
+       mutex_lock(&chip->lock);
+       ret = lp5521_load_program(engine, pattern);
+       mutex_unlock(&chip->lock);
+
+       if (ret) {
+               dev_err(&client->dev, "failed loading pattern\n");
+               return ret;
+       }
+
+       return len;
+fail:
+       dev_err(&client->dev, "wrong pattern format\n");
+       return -EINVAL;
+}
+
+static ssize_t store_engine_load(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t len, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       return lp5521_do_store_load(&chip->engines[nr - 1], buf, len);
+}
+
+#define store_load(nr)                                                 \
+static ssize_t store_engine##nr##_load(struct device *dev,             \
+                                    struct device_attribute *attr,     \
+                                    const char *buf, size_t len)       \
+{                                                                      \
+       return store_engine_load(dev, attr, buf, len, nr);              \
+}
+store_load(1)
+store_load(2)
+store_load(3)
+
+static ssize_t show_engine_mode(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       switch (chip->engines[nr - 1].mode) {
+       case LP5521_CMD_RUN:
+               return sprintf(buf, "run\n");
+       case LP5521_CMD_LOAD:
+               return sprintf(buf, "load\n");
+       case LP5521_CMD_DISABLED:
+               return sprintf(buf, "disabled\n");
+       default:
+               return sprintf(buf, "disabled\n");
+       }
+}
+
+#define show_mode(nr)                                                  \
+static ssize_t show_engine##nr##_mode(struct device *dev,              \
+                                   struct device_attribute *attr,      \
+                                   char *buf)                          \
+{                                                                      \
+       return show_engine_mode(dev, attr, buf, nr);                    \
+}
+show_mode(1)
+show_mode(2)
+show_mode(3)
+
+static ssize_t store_engine_mode(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t len, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       struct lp5521_engine *engine = &chip->engines[nr - 1];
+       mutex_lock(&chip->lock);
+
+       if (!strncmp(buf, "run", 3))
+               lp5521_set_mode(engine, LP5521_CMD_RUN);
+       else if (!strncmp(buf, "load", 4))
+               lp5521_set_mode(engine, LP5521_CMD_LOAD);
+       else if (!strncmp(buf, "disabled", 8))
+               lp5521_set_mode(engine, LP5521_CMD_DISABLED);
+
+       mutex_unlock(&chip->lock);
+       return len;
+}
+
+#define store_mode(nr)                                                 \
+static ssize_t store_engine##nr##_mode(struct device *dev,             \
+                                    struct device_attribute *attr,     \
+                                    const char *buf, size_t len)       \
+{                                                                      \
+       return store_engine_mode(dev, attr, buf, len, nr);              \
+}
+store_mode(1)
+store_mode(2)
+store_mode(3)
+
+static ssize_t show_max_current(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5521_led *led = cdev_to_led(led_cdev);
+
+       return sprintf(buf, "%d\n", led->max_current);
+}
+
+static ssize_t show_current(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5521_led *led = cdev_to_led(led_cdev);
+
+       return sprintf(buf, "%d\n", led->led_current);
+}
+
+static ssize_t store_current(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5521_led *led = cdev_to_led(led_cdev);
+       struct lp5521_chip *chip = led_to_lp5521(led);
+       ssize_t ret;
+       unsigned long curr;
+
+       if (strict_strtoul(buf, 0, &curr))
+               return -EINVAL;
+
+       if (curr > led->max_current)
+               return -EINVAL;
+
+       mutex_lock(&chip->lock);
+       ret = lp5521_set_led_current(chip, led->id, curr);
+       mutex_unlock(&chip->lock);
+
+       if (ret < 0)
+               return ret;
+
+       led->led_current = (u8)curr;
+
+       return len;
+}
+
+static ssize_t lp5521_selftest(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       int ret;
+
+       mutex_lock(&chip->lock);
+       ret = lp5521_run_selftest(chip, buf);
+       mutex_unlock(&chip->lock);
+       return sprintf(buf, "%s\n", ret ? "FAIL" : "OK");
+}
+
+/* led class device attributes */
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current);
+static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
+
+static struct attribute *lp5521_led_attributes[] = {
+       &dev_attr_led_current.attr,
+       &dev_attr_max_current.attr,
+       NULL,
+};
+
+static struct attribute_group lp5521_led_attribute_group = {
+       .attrs = lp5521_led_attributes
+};
+
+/* device attributes */
+static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO,
+                  show_engine1_mode, store_engine1_mode);
+static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO,
+                  show_engine2_mode, store_engine2_mode);
+static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO,
+                  show_engine3_mode, store_engine3_mode);
+static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load);
+static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load);
+static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load);
+static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
+
+static struct attribute *lp5521_attributes[] = {
+       &dev_attr_engine1_mode.attr,
+       &dev_attr_engine2_mode.attr,
+       &dev_attr_engine3_mode.attr,
+       &dev_attr_selftest.attr,
+       NULL
+};
+
+static struct attribute *lp5521_engine1_attributes[] = {
+       &dev_attr_engine1_load.attr,
+       NULL
+};
+
+static struct attribute *lp5521_engine2_attributes[] = {
+       &dev_attr_engine2_load.attr,
+       NULL
+};
+
+static struct attribute *lp5521_engine3_attributes[] = {
+       &dev_attr_engine3_load.attr,
+       NULL
+};
+
+static const struct attribute_group lp5521_group = {
+       .attrs = lp5521_attributes,
+};
+
+static const struct attribute_group lp5521_engine_group[] = {
+       {.attrs = lp5521_engine1_attributes },
+       {.attrs = lp5521_engine2_attributes },
+       {.attrs = lp5521_engine3_attributes },
+};
+
+static int lp5521_register_sysfs(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       return sysfs_create_group(&dev->kobj, &lp5521_group);
+}
+
+static void lp5521_unregister_sysfs(struct i2c_client *client)
+{
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       struct device *dev = &client->dev;
+       int i;
+
+       sysfs_remove_group(&dev->kobj, &lp5521_group);
+
+       for (i = 0; i <  ARRAY_SIZE(chip->engines); i++) {
+               if (chip->engines[i].mode == LP5521_CMD_LOAD)
+                       sysfs_remove_group(&dev->kobj,
+                                       chip->engines[i].attributes);
+       }
+
+       for (i = 0; i < chip->num_leds; i++)
+               sysfs_remove_group(&chip->leds[i].cdev.dev->kobj,
+                               &lp5521_led_attribute_group);
+}
+
+static int __init lp5521_init_led(struct lp5521_led *led,
+                               struct i2c_client *client,
+                               int chan, struct lp5521_platform_data *pdata)
+{
+       struct device *dev = &client->dev;
+       char name[32];
+       int res;
+
+       if (chan >= LP5521_MAX_LEDS)
+               return -EINVAL;
+
+       if (pdata->led_config[chan].led_current == 0)
+               return 0;
+
+       led->led_current = pdata->led_config[chan].led_current;
+       led->max_current = pdata->led_config[chan].max_current;
+       led->chan_nr = pdata->led_config[chan].chan_nr;
+
+       if (led->chan_nr >= LP5521_MAX_LEDS) {
+               dev_err(dev, "Use channel numbers between 0 and %d\n",
+                       LP5521_MAX_LEDS - 1);
+               return -EINVAL;
+       }
+
+       snprintf(name, sizeof(name), "%s:channel%d", client->name, chan);
+       led->cdev.brightness_set = lp5521_set_brightness;
+       led->cdev.name = name;
+       res = led_classdev_register(dev, &led->cdev);
+       if (res < 0) {
+               dev_err(dev, "couldn't register led on channel %d\n", chan);
+               return res;
+       }
+
+       res = sysfs_create_group(&led->cdev.dev->kobj,
+                       &lp5521_led_attribute_group);
+       if (res < 0) {
+               dev_err(dev, "couldn't register current attribute\n");
+               led_classdev_unregister(&led->cdev);
+               return res;
+       }
+       return 0;
+}
+
+static int lp5521_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct lp5521_chip              *chip;
+       struct lp5521_platform_data     *pdata;
+       int ret, i, led;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, chip);
+       chip->client = client;
+
+       pdata = client->dev.platform_data;
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data\n");
+               ret = -EINVAL;
+               goto fail1;
+       }
+
+       mutex_init(&chip->lock);
+
+       chip->pdata   = pdata;
+
+       if (pdata->setup_resources) {
+               ret = pdata->setup_resources();
+               if (ret < 0)
+                       goto fail1;
+       }
+
+       if (pdata->enable) {
+               pdata->enable(0);
+               usleep_range(1000, 10000);
+               pdata->enable(1);
+               usleep_range(1000, 10000); /* Spec says min 500us */
+       }
+
+       ret = lp5521_detect(client);
+
+       if (ret) {
+               dev_err(&client->dev, "Chip not found\n");
+               goto fail2;
+       }
+
+       dev_info(&client->dev, "%s programmable led chip found\n", id->name);
+
+       ret = lp5521_configure(client, lp5521_engine_group);
+       if (ret < 0) {
+               dev_err(&client->dev, "error configuring chip\n");
+               goto fail2;
+       }
+
+       /* Initialize leds */
+       chip->num_channels = pdata->num_channels;
+       chip->num_leds = 0;
+       led = 0;
+       for (i = 0; i < pdata->num_channels; i++) {
+               /* Do not initialize channels that are not connected */
+               if (pdata->led_config[i].led_current == 0)
+                       continue;
+
+               ret = lp5521_init_led(&chip->leds[led], client, i, pdata);
+               if (ret) {
+                       dev_err(&client->dev, "error initializing leds\n");
+                       goto fail3;
+               }
+               chip->num_leds++;
+
+               chip->leds[led].id = led;
+               /* Set initial LED current */
+               lp5521_set_led_current(chip, led,
+                               chip->leds[led].led_current);
+
+               INIT_WORK(&(chip->leds[led].brightness_work),
+                       lp5521_led_brightness_work);
+
+               led++;
+       }
+
+       ret = lp5521_register_sysfs(client);
+       if (ret) {
+               dev_err(&client->dev, "registering sysfs failed\n");
+               goto fail3;
+       }
+       return ret;
+fail3:
+       for (i = 0; i < chip->num_leds; i++) {
+               led_classdev_unregister(&chip->leds[i].cdev);
+               cancel_work_sync(&chip->leds[i].brightness_work);
+       }
+fail2:
+       if (pdata->enable)
+               pdata->enable(0);
+       if (pdata->release_resources)
+               pdata->release_resources();
+fail1:
+       kfree(chip);
+       return ret;
+}
+
+static int lp5521_remove(struct i2c_client *client)
+{
+       struct lp5521_chip *chip = i2c_get_clientdata(client);
+       int i;
+
+       lp5521_unregister_sysfs(client);
+
+       for (i = 0; i < chip->num_leds; i++) {
+               led_classdev_unregister(&chip->leds[i].cdev);
+               cancel_work_sync(&chip->leds[i].brightness_work);
+       }
+
+       if (chip->pdata->enable)
+               chip->pdata->enable(0);
+       if (chip->pdata->release_resources)
+               chip->pdata->release_resources();
+       kfree(chip);
+       return 0;
+}
+
+static const struct i2c_device_id lp5521_id[] = {
+       { "lp5521", 0 }, /* Three channel chip */
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lp5521_id);
+
+static struct i2c_driver lp5521_driver = {
+       .driver = {
+               .name   = "lp5521",
+       },
+       .probe          = lp5521_probe,
+       .remove         = lp5521_remove,
+       .id_table       = lp5521_id,
+};
+
+static int __init lp5521_init(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&lp5521_driver);
+
+       if (ret < 0)
+               printk(KERN_ALERT "Adding lp5521 driver failed\n");
+
+       return ret;
+}
+
+static void __exit lp5521_exit(void)
+{
+       i2c_del_driver(&lp5521_driver);
+}
+
+module_init(lp5521_init);
+module_exit(lp5521_exit);
+
+MODULE_AUTHOR("Mathias Nyman, Yuri Zaporozhets, Samu Onkalo");
+MODULE_DESCRIPTION("LP5521 LED engine");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
new file mode 100644 (file)
index 0000000..1e11fcc
--- /dev/null
@@ -0,0 +1,1065 @@
+/*
+ * lp5523.c - LP5523 LED Driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.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/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/leds.h>
+#include <linux/leds-lp5523.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+
+#define LP5523_REG_ENABLE              0x00
+#define LP5523_REG_OP_MODE             0x01
+#define LP5523_REG_RATIOMETRIC_MSB     0x02
+#define LP5523_REG_RATIOMETRIC_LSB     0x03
+#define LP5523_REG_ENABLE_LEDS_MSB     0x04
+#define LP5523_REG_ENABLE_LEDS_LSB     0x05
+#define LP5523_REG_LED_CNTRL_BASE      0x06
+#define LP5523_REG_LED_PWM_BASE                0x16
+#define LP5523_REG_LED_CURRENT_BASE    0x26
+#define LP5523_REG_CONFIG              0x36
+#define LP5523_REG_CHANNEL1_PC         0x37
+#define LP5523_REG_CHANNEL2_PC         0x38
+#define LP5523_REG_CHANNEL3_PC         0x39
+#define LP5523_REG_STATUS              0x3a
+#define LP5523_REG_GPO                 0x3b
+#define LP5523_REG_VARIABLE            0x3c
+#define LP5523_REG_RESET               0x3d
+#define LP5523_REG_TEMP_CTRL           0x3e
+#define LP5523_REG_TEMP_READ           0x3f
+#define LP5523_REG_TEMP_WRITE          0x40
+#define LP5523_REG_LED_TEST_CTRL       0x41
+#define LP5523_REG_LED_TEST_ADC                0x42
+#define LP5523_REG_ENG1_VARIABLE       0x45
+#define LP5523_REG_ENG2_VARIABLE       0x46
+#define LP5523_REG_ENG3_VARIABLE       0x47
+#define LP5523_REG_MASTER_FADER1       0x48
+#define LP5523_REG_MASTER_FADER2       0x49
+#define LP5523_REG_MASTER_FADER3       0x4a
+#define LP5523_REG_CH1_PROG_START      0x4c
+#define LP5523_REG_CH2_PROG_START      0x4d
+#define LP5523_REG_CH3_PROG_START      0x4e
+#define LP5523_REG_PROG_PAGE_SEL       0x4f
+#define LP5523_REG_PROG_MEM            0x50
+
+#define LP5523_CMD_LOAD                        0x15 /* 00010101 */
+#define LP5523_CMD_RUN                 0x2a /* 00101010 */
+#define LP5523_CMD_DISABLED            0x00 /* 00000000 */
+
+#define LP5523_ENABLE                  0x40
+#define LP5523_AUTO_INC                        0x40
+#define LP5523_PWR_SAVE                        0x20
+#define LP5523_PWM_PWR_SAVE            0x04
+#define LP5523_CP_1                    0x08
+#define LP5523_CP_1_5                  0x10
+#define LP5523_CP_AUTO                 0x18
+#define LP5523_INT_CLK                 0x01
+#define LP5523_AUTO_CLK                        0x02
+#define LP5523_EN_LEDTEST              0x80
+#define LP5523_LEDTEST_DONE            0x80
+
+#define LP5523_DEFAULT_CURRENT         50 /* microAmps */
+#define LP5523_PROGRAM_LENGTH          32 /* in bytes */
+#define LP5523_PROGRAM_PAGES           6
+#define LP5523_ADC_SHORTCIRC_LIM       80
+
+#define LP5523_LEDS                    9
+#define LP5523_ENGINES                 3
+
+#define LP5523_ENG_MASK_BASE           0x30 /* 00110000 */
+
+#define LP5523_ENG_STATUS_MASK          0x07 /* 00000111 */
+
+#define LP5523_IRQ_FLAGS                IRQF_TRIGGER_FALLING
+
+#define LP5523_EXT_CLK_USED            0x08
+
+#define LED_ACTIVE(mux, led)           (!!(mux & (0x0001 << led)))
+#define SHIFT_MASK(id)                 (((id) - 1) * 2)
+
+struct lp5523_engine {
+       const struct attribute_group *attributes;
+       int             id;
+       u8              mode;
+       u8              prog_page;
+       u8              mux_page;
+       u16             led_mux;
+       u8              engine_mask;
+};
+
+struct lp5523_led {
+       int                     id;
+       u8                      chan_nr;
+       u8                      led_current;
+       u8                      max_current;
+       struct led_classdev     cdev;
+       struct work_struct      brightness_work;
+       u8                      brightness;
+};
+
+struct lp5523_chip {
+       struct mutex            lock; /* Serialize control */
+       struct i2c_client       *client;
+       struct lp5523_engine    engines[LP5523_ENGINES];
+       struct lp5523_led       leds[LP5523_LEDS];
+       struct lp5523_platform_data *pdata;
+       u8                      num_channels;
+       u8                      num_leds;
+};
+
+#define cdev_to_led(c)          container_of(c, struct lp5523_led, cdev)
+
+static struct lp5523_chip *engine_to_lp5523(struct lp5523_engine *engine)
+{
+       return container_of(engine, struct lp5523_chip,
+                           engines[engine->id - 1]);
+}
+
+static struct lp5523_chip *led_to_lp5523(struct lp5523_led *led)
+{
+       return container_of(led, struct lp5523_chip,
+                           leds[led->id]);
+}
+
+static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode);
+static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode);
+static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern);
+
+static void lp5523_led_brightness_work(struct work_struct *work);
+
+static int lp5523_write(struct i2c_client *client, u8 reg, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int lp5523_read(struct i2c_client *client, u8 reg, u8 *buf)
+{
+       s32 ret = i2c_smbus_read_byte_data(client, reg);
+
+       if (ret < 0)
+               return -EIO;
+
+       *buf = ret;
+       return 0;
+}
+
+static int lp5523_detect(struct i2c_client *client)
+{
+       int ret;
+       u8 buf;
+
+       ret = lp5523_write(client, LP5523_REG_ENABLE, 0x40);
+       if (ret)
+               return ret;
+       ret = lp5523_read(client, LP5523_REG_ENABLE, &buf);
+       if (ret)
+               return ret;
+       if (buf == 0x40)
+               return 0;
+       else
+               return -ENODEV;
+}
+
+static int lp5523_configure(struct i2c_client *client)
+{
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       int ret = 0;
+       u8 status;
+
+       /* one pattern per engine setting led mux start and stop addresses */
+       u8 pattern[][LP5523_PROGRAM_LENGTH] =  {
+               { 0x9c, 0x30, 0x9c, 0xb0, 0x9d, 0x80, 0xd8, 0x00, 0},
+               { 0x9c, 0x40, 0x9c, 0xc0, 0x9d, 0x80, 0xd8, 0x00, 0},
+               { 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0},
+       };
+
+       lp5523_write(client, LP5523_REG_RESET, 0xff);
+
+       usleep_range(10000, 100000);
+
+       ret |= lp5523_write(client, LP5523_REG_ENABLE, LP5523_ENABLE);
+       /* Chip startup time after reset is 500 us */
+       usleep_range(1000, 10000);
+
+       ret |= lp5523_write(client, LP5523_REG_CONFIG,
+                           LP5523_AUTO_INC | LP5523_PWR_SAVE |
+                           LP5523_CP_AUTO | LP5523_AUTO_CLK |
+                           LP5523_PWM_PWR_SAVE);
+
+       /* turn on all leds */
+       ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_MSB, 0x01);
+       ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_LSB, 0xff);
+
+       /* hardcode 32 bytes of memory for each engine from program memory */
+       ret |= lp5523_write(client, LP5523_REG_CH1_PROG_START, 0x00);
+       ret |= lp5523_write(client, LP5523_REG_CH2_PROG_START, 0x10);
+       ret |= lp5523_write(client, LP5523_REG_CH3_PROG_START, 0x20);
+
+       /* write led mux address space for each channel */
+       ret |= lp5523_load_program(&chip->engines[0], pattern[0]);
+       ret |= lp5523_load_program(&chip->engines[1], pattern[1]);
+       ret |= lp5523_load_program(&chip->engines[2], pattern[2]);
+
+       if (ret) {
+               dev_err(&client->dev, "could not load mux programs\n");
+               return -1;
+       }
+
+       /* set all engines exec state and mode to run 00101010 */
+       ret |= lp5523_write(client, LP5523_REG_ENABLE,
+                           (LP5523_CMD_RUN | LP5523_ENABLE));
+
+       ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_RUN);
+
+       if (ret) {
+               dev_err(&client->dev, "could not start mux programs\n");
+               return -1;
+       }
+
+       /* Wait 3ms and check the engine status */
+       usleep_range(3000, 20000);
+       lp5523_read(client, LP5523_REG_STATUS, &status);
+       status &= LP5523_ENG_STATUS_MASK;
+
+       if (status == LP5523_ENG_STATUS_MASK) {
+               dev_dbg(&client->dev, "all engines configured\n");
+       } else {
+               dev_info(&client->dev, "status == %x\n", status);
+               dev_err(&client->dev, "cound not configure LED engine\n");
+               return -1;
+       }
+
+       dev_info(&client->dev, "disabling engines\n");
+
+       ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_DISABLED);
+
+       return ret;
+}
+
+static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode)
+{
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+       int ret;
+       u8 engine_state;
+
+       ret = lp5523_read(client, LP5523_REG_OP_MODE, &engine_state);
+       if (ret)
+               goto fail;
+
+       engine_state &= ~(engine->engine_mask);
+
+       /* set mode only for this engine */
+       mode &= engine->engine_mask;
+
+       engine_state |= mode;
+
+       ret |= lp5523_write(client, LP5523_REG_OP_MODE, engine_state);
+fail:
+       return ret;
+}
+
+static int lp5523_load_mux(struct lp5523_engine *engine, u16 mux)
+{
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
+
+       ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL, engine->mux_page);
+       ret |= lp5523_write(client, LP5523_REG_PROG_MEM,
+                           (u8)(mux >> 8));
+       ret |= lp5523_write(client, LP5523_REG_PROG_MEM + 1, (u8)(mux));
+       engine->led_mux = mux;
+
+       return ret;
+}
+
+static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern)
+{
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+
+       int ret = 0;
+
+       ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
+
+       ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL,
+                           engine->prog_page);
+       ret |= i2c_smbus_write_i2c_block_data(client, LP5523_REG_PROG_MEM,
+                                             LP5523_PROGRAM_LENGTH, pattern);
+
+       return ret;
+}
+
+static int lp5523_run_program(struct lp5523_engine *engine)
+{
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+       int ret;
+
+       ret = lp5523_write(client, LP5523_REG_ENABLE,
+                                       LP5523_CMD_RUN | LP5523_ENABLE);
+       if (ret)
+               goto fail;
+
+       ret = lp5523_set_engine_mode(engine, LP5523_CMD_RUN);
+fail:
+       return ret;
+}
+
+static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len)
+{
+       int i;
+       u16 tmp_mux = 0;
+       len = len < LP5523_LEDS ? len : LP5523_LEDS;
+       for (i = 0; i < len; i++) {
+               switch (buf[i]) {
+               case '1':
+                       tmp_mux |= (1 << i);
+                       break;
+               case '0':
+                       break;
+               case '\n':
+                       i = len;
+                       break;
+               default:
+                       return -1;
+               }
+       }
+       *mux = tmp_mux;
+
+       return 0;
+}
+
+static void lp5523_mux_to_array(u16 led_mux, char *array)
+{
+       int i, pos = 0;
+       for (i = 0; i < LP5523_LEDS; i++)
+               pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i));
+
+       array[pos] = '\0';
+}
+
+/*--------------------------------------------------------------*/
+/*                     Sysfs interface                         */
+/*--------------------------------------------------------------*/
+
+static ssize_t show_engine_leds(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       char mux[LP5523_LEDS + 1];
+
+       lp5523_mux_to_array(chip->engines[nr - 1].led_mux, mux);
+
+       return sprintf(buf, "%s\n", mux);
+}
+
+#define show_leds(nr)                                                  \
+static ssize_t show_engine##nr##_leds(struct device *dev,              \
+                           struct device_attribute *attr,              \
+                           char *buf)                                  \
+{                                                                      \
+       return show_engine_leds(dev, attr, buf, nr);                    \
+}
+show_leds(1)
+show_leds(2)
+show_leds(3)
+
+static ssize_t store_engine_leds(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       u16 mux = 0;
+
+       if (lp5523_mux_parse(buf, &mux, len))
+               return -EINVAL;
+
+       if (lp5523_load_mux(&chip->engines[nr - 1], mux))
+               return -EINVAL;
+
+       return len;
+}
+
+#define store_leds(nr)                                         \
+static ssize_t store_engine##nr##_leds(struct device *dev,     \
+                            struct device_attribute *attr,     \
+                            const char *buf, size_t len)       \
+{                                                              \
+       return store_engine_leds(dev, attr, buf, len, nr);      \
+}
+store_leds(1)
+store_leds(2)
+store_leds(3)
+
+static ssize_t lp5523_selftest(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       int i, ret, pos = 0;
+       int led = 0;
+       u8 status, adc, vdd;
+
+       mutex_lock(&chip->lock);
+
+       ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+       if (ret < 0)
+               goto fail;
+
+       /* Check that ext clock is really in use if requested */
+       if ((chip->pdata) && (chip->pdata->clock_mode == LP5523_CLOCK_EXT))
+               if  ((status & LP5523_EXT_CLK_USED) == 0)
+                       goto fail;
+
+       /* Measure VDD (i.e. VBAT) first (channel 16 corresponds to VDD) */
+       lp5523_write(chip->client, LP5523_REG_LED_TEST_CTRL,
+                                   LP5523_EN_LEDTEST | 16);
+       usleep_range(3000, 10000);
+       ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+       if (!(status & LP5523_LEDTEST_DONE))
+               usleep_range(3000, 10000);
+
+       ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &vdd);
+       vdd--;  /* There may be some fluctuation in measurement */
+
+       for (i = 0; i < LP5523_LEDS; i++) {
+               /* Skip non-existing channels */
+               if (chip->pdata->led_config[i].led_current == 0)
+                       continue;
+
+               /* Set default current */
+               lp5523_write(chip->client,
+                       LP5523_REG_LED_CURRENT_BASE + i,
+                       chip->pdata->led_config[i].led_current);
+
+               lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0xff);
+               /* let current stabilize 2ms before measurements start */
+               usleep_range(2000, 10000);
+               lp5523_write(chip->client,
+                            LP5523_REG_LED_TEST_CTRL,
+                            LP5523_EN_LEDTEST | i);
+               /* ledtest takes 2.7ms */
+               usleep_range(3000, 10000);
+               ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status);
+               if (!(status & LP5523_LEDTEST_DONE))
+                       usleep_range(3000, 10000);
+               ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &adc);
+
+               if (adc >= vdd || adc < LP5523_ADC_SHORTCIRC_LIM)
+                       pos += sprintf(buf + pos, "LED %d FAIL\n", i);
+
+               lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0x00);
+
+               /* Restore current */
+               lp5523_write(chip->client,
+                       LP5523_REG_LED_CURRENT_BASE + i,
+                       chip->leds[led].led_current);
+               led++;
+       }
+       if (pos == 0)
+               pos = sprintf(buf, "OK\n");
+       goto release_lock;
+fail:
+       pos = sprintf(buf, "FAIL\n");
+
+release_lock:
+       mutex_unlock(&chip->lock);
+
+       return pos;
+}
+
+static void lp5523_set_brightness(struct led_classdev *cdev,
+                            enum led_brightness brightness)
+{
+       struct lp5523_led *led = cdev_to_led(cdev);
+
+       led->brightness = (u8)brightness;
+
+       schedule_work(&led->brightness_work);
+}
+
+static void lp5523_led_brightness_work(struct work_struct *work)
+{
+       struct lp5523_led *led = container_of(work,
+                                             struct lp5523_led,
+                                             brightness_work);
+       struct lp5523_chip *chip = led_to_lp5523(led);
+       struct i2c_client *client = chip->client;
+
+       mutex_lock(&chip->lock);
+
+       lp5523_write(client, LP5523_REG_LED_PWM_BASE + led->chan_nr,
+                    led->brightness);
+
+       mutex_unlock(&chip->lock);
+}
+
+static int lp5523_do_store_load(struct lp5523_engine *engine,
+                               const char *buf, size_t len)
+{
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+       int  ret, nrchars, offset = 0, i = 0;
+       char c[3];
+       unsigned cmd;
+       u8 pattern[LP5523_PROGRAM_LENGTH] = {0};
+
+       while ((offset < len - 1) && (i < LP5523_PROGRAM_LENGTH)) {
+               /* separate sscanfs because length is working only for %s */
+               ret = sscanf(buf + offset, "%2s%n ", c, &nrchars);
+               ret = sscanf(c, "%2x", &cmd);
+               if (ret != 1)
+                       goto fail;
+               pattern[i] = (u8)cmd;
+
+               offset += nrchars;
+               i++;
+       }
+
+       /* Each instruction is 16bit long. Check that length is even */
+       if (i % 2)
+               goto fail;
+
+       mutex_lock(&chip->lock);
+
+       ret = lp5523_load_program(engine, pattern);
+       mutex_unlock(&chip->lock);
+
+       if (ret) {
+               dev_err(&client->dev, "failed loading pattern\n");
+               return ret;
+       }
+
+       return len;
+fail:
+       dev_err(&client->dev, "wrong pattern format\n");
+       return -EINVAL;
+}
+
+static ssize_t store_engine_load(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t len, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       return lp5523_do_store_load(&chip->engines[nr - 1], buf, len);
+}
+
+#define store_load(nr)                                                 \
+static ssize_t store_engine##nr##_load(struct device *dev,             \
+                                    struct device_attribute *attr,     \
+                                    const char *buf, size_t len)       \
+{                                                                      \
+       return store_engine_load(dev, attr, buf, len, nr);              \
+}
+store_load(1)
+store_load(2)
+store_load(3)
+
+static ssize_t show_engine_mode(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       switch (chip->engines[nr - 1].mode) {
+       case LP5523_CMD_RUN:
+               return sprintf(buf, "run\n");
+       case LP5523_CMD_LOAD:
+               return sprintf(buf, "load\n");
+       case LP5523_CMD_DISABLED:
+               return sprintf(buf, "disabled\n");
+       default:
+               return sprintf(buf, "disabled\n");
+       }
+}
+
+#define show_mode(nr)                                                  \
+static ssize_t show_engine##nr##_mode(struct device *dev,              \
+                                   struct device_attribute *attr,      \
+                                   char *buf)                          \
+{                                                                      \
+       return show_engine_mode(dev, attr, buf, nr);                    \
+}
+show_mode(1)
+show_mode(2)
+show_mode(3)
+
+static ssize_t store_engine_mode(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t len, int nr)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       struct lp5523_engine *engine = &chip->engines[nr - 1];
+       mutex_lock(&chip->lock);
+
+       if (!strncmp(buf, "run", 3))
+               lp5523_set_mode(engine, LP5523_CMD_RUN);
+       else if (!strncmp(buf, "load", 4))
+               lp5523_set_mode(engine, LP5523_CMD_LOAD);
+       else if (!strncmp(buf, "disabled", 8))
+               lp5523_set_mode(engine, LP5523_CMD_DISABLED);
+
+       mutex_unlock(&chip->lock);
+       return len;
+}
+
+#define store_mode(nr)                                                 \
+static ssize_t store_engine##nr##_mode(struct device *dev,             \
+                                    struct device_attribute *attr,     \
+                                    const char *buf, size_t len)       \
+{                                                                      \
+       return store_engine_mode(dev, attr, buf, len, nr);              \
+}
+store_mode(1)
+store_mode(2)
+store_mode(3)
+
+static ssize_t show_max_current(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5523_led *led = cdev_to_led(led_cdev);
+
+       return sprintf(buf, "%d\n", led->max_current);
+}
+
+static ssize_t show_current(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5523_led *led = cdev_to_led(led_cdev);
+
+       return sprintf(buf, "%d\n", led->led_current);
+}
+
+static ssize_t store_current(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct lp5523_led *led = cdev_to_led(led_cdev);
+       struct lp5523_chip *chip = led_to_lp5523(led);
+       ssize_t ret;
+       unsigned long curr;
+
+       if (strict_strtoul(buf, 0, &curr))
+               return -EINVAL;
+
+       if (curr > led->max_current)
+               return -EINVAL;
+
+       mutex_lock(&chip->lock);
+       ret = lp5523_write(chip->client,
+                       LP5523_REG_LED_CURRENT_BASE + led->chan_nr,
+                       (u8)curr);
+       mutex_unlock(&chip->lock);
+
+       if (ret < 0)
+               return ret;
+
+       led->led_current = (u8)curr;
+
+       return len;
+}
+
+/* led class device attributes */
+static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current);
+static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL);
+
+static struct attribute *lp5523_led_attributes[] = {
+       &dev_attr_led_current.attr,
+       &dev_attr_max_current.attr,
+       NULL,
+};
+
+static struct attribute_group lp5523_led_attribute_group = {
+       .attrs = lp5523_led_attributes
+};
+
+/* device attributes */
+static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO,
+                  show_engine1_mode, store_engine1_mode);
+static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO,
+                  show_engine2_mode, store_engine2_mode);
+static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO,
+                  show_engine3_mode, store_engine3_mode);
+static DEVICE_ATTR(engine1_leds, S_IRUGO | S_IWUGO,
+                  show_engine1_leds, store_engine1_leds);
+static DEVICE_ATTR(engine2_leds, S_IRUGO | S_IWUGO,
+                  show_engine2_leds, store_engine2_leds);
+static DEVICE_ATTR(engine3_leds, S_IRUGO | S_IWUGO,
+                  show_engine3_leds, store_engine3_leds);
+static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load);
+static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load);
+static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load);
+static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL);
+
+static struct attribute *lp5523_attributes[] = {
+       &dev_attr_engine1_mode.attr,
+       &dev_attr_engine2_mode.attr,
+       &dev_attr_engine3_mode.attr,
+       &dev_attr_selftest.attr,
+       NULL
+};
+
+static struct attribute *lp5523_engine1_attributes[] = {
+       &dev_attr_engine1_load.attr,
+       &dev_attr_engine1_leds.attr,
+       NULL
+};
+
+static struct attribute *lp5523_engine2_attributes[] = {
+       &dev_attr_engine2_load.attr,
+       &dev_attr_engine2_leds.attr,
+       NULL
+};
+
+static struct attribute *lp5523_engine3_attributes[] = {
+       &dev_attr_engine3_load.attr,
+       &dev_attr_engine3_leds.attr,
+       NULL
+};
+
+static const struct attribute_group lp5523_group = {
+       .attrs = lp5523_attributes,
+};
+
+static const struct attribute_group lp5523_engine_group[] = {
+       {.attrs = lp5523_engine1_attributes },
+       {.attrs = lp5523_engine2_attributes },
+       {.attrs = lp5523_engine3_attributes },
+};
+
+static int lp5523_register_sysfs(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       int ret;
+
+       ret = sysfs_create_group(&dev->kobj, &lp5523_group);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static void lp5523_unregister_sysfs(struct i2c_client *client)
+{
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       struct device *dev = &client->dev;
+       int i;
+
+       sysfs_remove_group(&dev->kobj, &lp5523_group);
+
+       for (i = 0; i < ARRAY_SIZE(chip->engines); i++)
+               if (chip->engines[i].mode == LP5523_CMD_LOAD)
+                       sysfs_remove_group(&dev->kobj, &lp5523_engine_group[i]);
+
+       for (i = 0; i < chip->num_leds; i++)
+               sysfs_remove_group(&chip->leds[i].cdev.dev->kobj,
+                               &lp5523_led_attribute_group);
+}
+
+/*--------------------------------------------------------------*/
+/*                     Set chip operating mode                 */
+/*--------------------------------------------------------------*/
+static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode)
+{
+       /*  engine to chip */
+       struct lp5523_chip *chip = engine_to_lp5523(engine);
+       struct i2c_client *client = chip->client;
+       struct device *dev = &client->dev;
+       int ret = 0;
+
+       /* if in that mode already do nothing, except for run */
+       if (mode == engine->mode && mode != LP5523_CMD_RUN)
+               return 0;
+
+       if (mode == LP5523_CMD_RUN) {
+               ret = lp5523_run_program(engine);
+       } else if (mode == LP5523_CMD_LOAD) {
+               lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
+               lp5523_set_engine_mode(engine, LP5523_CMD_LOAD);
+
+               ret = sysfs_create_group(&dev->kobj, engine->attributes);
+               if (ret)
+                       return ret;
+       } else if (mode == LP5523_CMD_DISABLED) {
+               lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED);
+       }
+
+       /* remove load attribute from sysfs if not in load mode */
+       if (engine->mode == LP5523_CMD_LOAD && mode != LP5523_CMD_LOAD)
+               sysfs_remove_group(&dev->kobj, engine->attributes);
+
+       engine->mode = mode;
+
+       return ret;
+}
+
+/*--------------------------------------------------------------*/
+/*                     Probe, Attach, Remove                   */
+/*--------------------------------------------------------------*/
+static int __init lp5523_init_engine(struct lp5523_engine *engine, int id)
+{
+       if (id < 1 || id > LP5523_ENGINES)
+               return -1;
+       engine->id = id;
+       engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id);
+       engine->prog_page = id - 1;
+       engine->mux_page = id + 2;
+       engine->attributes = &lp5523_engine_group[id - 1];
+
+       return 0;
+}
+
+static int __init lp5523_init_led(struct lp5523_led *led, struct device *dev,
+                          int chan, struct lp5523_platform_data *pdata)
+{
+       char name[32];
+       int res;
+
+       if (chan >= LP5523_LEDS)
+               return -EINVAL;
+
+       if (pdata->led_config[chan].led_current) {
+               led->led_current = pdata->led_config[chan].led_current;
+               led->max_current = pdata->led_config[chan].max_current;
+               led->chan_nr = pdata->led_config[chan].chan_nr;
+
+               if (led->chan_nr >= LP5523_LEDS) {
+                       dev_err(dev, "Use channel numbers between 0 and %d\n",
+                               LP5523_LEDS - 1);
+                       return -EINVAL;
+               }
+
+               snprintf(name, 32, "lp5523:channel%d", chan);
+
+               led->cdev.name = name;
+               led->cdev.brightness_set = lp5523_set_brightness;
+               res = led_classdev_register(dev, &led->cdev);
+               if (res < 0) {
+                       dev_err(dev, "couldn't register led on channel %d\n",
+                               chan);
+                       return res;
+               }
+               res = sysfs_create_group(&led->cdev.dev->kobj,
+                               &lp5523_led_attribute_group);
+               if (res < 0) {
+                       dev_err(dev, "couldn't register current attribute\n");
+                       led_classdev_unregister(&led->cdev);
+                       return res;
+               }
+       } else {
+               led->led_current = 0;
+       }
+       return 0;
+}
+
+static struct i2c_driver lp5523_driver;
+
+static int lp5523_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct lp5523_chip              *chip;
+       struct lp5523_platform_data     *pdata;
+       int ret, i, led;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, chip);
+       chip->client = client;
+
+       pdata = client->dev.platform_data;
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data\n");
+               ret = -EINVAL;
+               goto fail1;
+       }
+
+       mutex_init(&chip->lock);
+
+       chip->pdata   = pdata;
+
+       if (pdata->setup_resources) {
+               ret = pdata->setup_resources();
+               if (ret < 0)
+                       goto fail1;
+       }
+
+       if (pdata->enable) {
+               pdata->enable(0);
+               usleep_range(1000, 10000);
+               pdata->enable(1);
+               usleep_range(1000, 10000); /* Spec says min 500us */
+       }
+
+       ret = lp5523_detect(client);
+       if (ret)
+               goto fail2;
+
+       dev_info(&client->dev, "LP5523 Programmable led chip found\n");
+
+       /* Initialize engines */
+       for (i = 0; i < ARRAY_SIZE(chip->engines); i++) {
+               ret = lp5523_init_engine(&chip->engines[i], i + 1);
+               if (ret) {
+                       dev_err(&client->dev, "error initializing engine\n");
+                       goto fail2;
+               }
+       }
+       ret = lp5523_configure(client);
+       if (ret < 0) {
+               dev_err(&client->dev, "error configuring chip\n");
+               goto fail2;
+       }
+
+       /* Initialize leds */
+       chip->num_channels = pdata->num_channels;
+       chip->num_leds = 0;
+       led = 0;
+       for (i = 0; i < pdata->num_channels; i++) {
+               /* Do not initialize channels that are not connected */
+               if (pdata->led_config[i].led_current == 0)
+                       continue;
+
+               ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata);
+               if (ret) {
+                       dev_err(&client->dev, "error initializing leds\n");
+                       goto fail3;
+               }
+               chip->num_leds++;
+
+               chip->leds[led].id = led;
+               /* Set LED current */
+               lp5523_write(client,
+                         LP5523_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr,
+                         chip->leds[led].led_current);
+
+               INIT_WORK(&(chip->leds[led].brightness_work),
+                       lp5523_led_brightness_work);
+
+               led++;
+       }
+
+       ret = lp5523_register_sysfs(client);
+       if (ret) {
+               dev_err(&client->dev, "registering sysfs failed\n");
+               goto fail3;
+       }
+       return ret;
+fail3:
+       for (i = 0; i < chip->num_leds; i++) {
+               led_classdev_unregister(&chip->leds[i].cdev);
+               cancel_work_sync(&chip->leds[i].brightness_work);
+       }
+fail2:
+       if (pdata->enable)
+               pdata->enable(0);
+       if (pdata->release_resources)
+               pdata->release_resources();
+fail1:
+       kfree(chip);
+       return ret;
+}
+
+static int lp5523_remove(struct i2c_client *client)
+{
+       struct lp5523_chip *chip = i2c_get_clientdata(client);
+       int i;
+
+       lp5523_unregister_sysfs(client);
+
+       for (i = 0; i < chip->num_leds; i++) {
+               led_classdev_unregister(&chip->leds[i].cdev);
+               cancel_work_sync(&chip->leds[i].brightness_work);
+       }
+
+       if (chip->pdata->enable)
+               chip->pdata->enable(0);
+       if (chip->pdata->release_resources)
+               chip->pdata->release_resources();
+       kfree(chip);
+       return 0;
+}
+
+static const struct i2c_device_id lp5523_id[] = {
+       { "lp5523", 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, lp5523_id);
+
+static struct i2c_driver lp5523_driver = {
+       .driver = {
+               .name   = "lp5523",
+       },
+       .probe          = lp5523_probe,
+       .remove         = lp5523_remove,
+       .id_table       = lp5523_id,
+};
+
+static int __init lp5523_init(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&lp5523_driver);
+
+       if (ret < 0)
+               printk(KERN_ALERT "Adding lp5523 driver failed\n");
+
+       return ret;
+}
+
+static void __exit lp5523_exit(void)
+{
+       i2c_del_driver(&lp5523_driver);
+}
+
+module_init(lp5523_init);
+module_exit(lp5523_exit);
+
+MODULE_AUTHOR("Mathias Nyman <mathias.nyman@nokia.com>");
+MODULE_DESCRIPTION("LP5523 LED engine");
+MODULE_LICENSE("GPL");
index 3063f59..1739557 100644 (file)
@@ -92,3 +92,5 @@ unmap:
 }
 
 arch_initcall(soekris_init);
+
+MODULE_LICENSE("GPL");
index 82b77bd..b09bcbe 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
 #include <linux/device.h>
-#include <linux/sysdev.h>
-#include <linux/timer.h>
 #include <linux/ctype.h>
 #include <linux/leds.h>
-#include <linux/slab.h>
 #include "leds.h"
 
-struct timer_trig_data {
-       int brightness_on;              /* LED brightness during "on" period.
-                                        * (LED_OFF < brightness_on <= LED_FULL)
-                                        */
-       unsigned long delay_on;         /* milliseconds on */
-       unsigned long delay_off;        /* milliseconds off */
-       struct timer_list timer;
-};
-
-static void led_timer_function(unsigned long data)
-{
-       struct led_classdev *led_cdev = (struct led_classdev *) data;
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
-       unsigned long brightness;
-       unsigned long delay;
-
-       if (!timer_data->delay_on || !timer_data->delay_off) {
-               led_set_brightness(led_cdev, LED_OFF);
-               return;
-       }
-
-       brightness = led_get_brightness(led_cdev);
-       if (!brightness) {
-               /* Time to switch the LED on. */
-               brightness = timer_data->brightness_on;
-               delay = timer_data->delay_on;
-       } else {
-               /* Store the current brightness value to be able
-                * to restore it when the delay_off period is over.
-                */
-               timer_data->brightness_on = brightness;
-               brightness = LED_OFF;
-               delay = timer_data->delay_off;
-       }
-
-       led_set_brightness(led_cdev, brightness);
-
-       mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
-}
-
 static ssize_t led_delay_on_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
-       return sprintf(buf, "%lu\n", timer_data->delay_on);
+       return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
 }
 
 static ssize_t led_delay_on_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
        int ret = -EINVAL;
        char *after;
        unsigned long state = simple_strtoul(buf, &after, 10);
@@ -88,21 +40,7 @@ static ssize_t led_delay_on_store(struct device *dev,
                count++;
 
        if (count == size) {
-               if (timer_data->delay_on != state) {
-                       /* the new value differs from the previous */
-                       timer_data->delay_on = state;
-
-                       /* deactivate previous settings */
-                       del_timer_sync(&timer_data->timer);
-
-                       /* try to activate hardware acceleration, if any */
-                       if (!led_cdev->blink_set ||
-                           led_cdev->blink_set(led_cdev,
-                             &timer_data->delay_on, &timer_data->delay_off)) {
-                               /* no hardware acceleration, blink via timer */
-                               mod_timer(&timer_data->timer, jiffies + 1);
-                       }
-               }
+               led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off);
                ret = count;
        }
 
@@ -113,16 +51,14 @@ static ssize_t led_delay_off_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
-       return sprintf(buf, "%lu\n", timer_data->delay_off);
+       return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
 }
 
 static ssize_t led_delay_off_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
        int ret = -EINVAL;
        char *after;
        unsigned long state = simple_strtoul(buf, &after, 10);
@@ -132,21 +68,7 @@ static ssize_t led_delay_off_store(struct device *dev,
                count++;
 
        if (count == size) {
-               if (timer_data->delay_off != state) {
-                       /* the new value differs from the previous */
-                       timer_data->delay_off = state;
-
-                       /* deactivate previous settings */
-                       del_timer_sync(&timer_data->timer);
-
-                       /* try to activate hardware acceleration, if any */
-                       if (!led_cdev->blink_set ||
-                           led_cdev->blink_set(led_cdev,
-                             &timer_data->delay_on, &timer_data->delay_off)) {
-                               /* no hardware acceleration, blink via timer */
-                               mod_timer(&timer_data->timer, jiffies + 1);
-                       }
-               }
+               led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state);
                ret = count;
        }
 
@@ -158,60 +80,34 @@ static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
 
 static void timer_trig_activate(struct led_classdev *led_cdev)
 {
-       struct timer_trig_data *timer_data;
        int rc;
 
-       timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL);
-       if (!timer_data)
-               return;
-
-       timer_data->brightness_on = led_get_brightness(led_cdev);
-       if (timer_data->brightness_on == LED_OFF)
-               timer_data->brightness_on = led_cdev->max_brightness;
-       led_cdev->trigger_data = timer_data;
-
-       init_timer(&timer_data->timer);
-       timer_data->timer.function = led_timer_function;
-       timer_data->timer.data = (unsigned long) led_cdev;
+       led_cdev->trigger_data = NULL;
 
        rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
        if (rc)
-               goto err_out;
+               return;
        rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
        if (rc)
                goto err_out_delayon;
 
-       /* If there is hardware support for blinking, start one
-        * user friendly blink rate chosen by the driver.
-        */
-       if (led_cdev->blink_set)
-               led_cdev->blink_set(led_cdev,
-                       &timer_data->delay_on, &timer_data->delay_off);
+       led_cdev->trigger_data = (void *)1;
 
        return;
 
 err_out_delayon:
        device_remove_file(led_cdev->dev, &dev_attr_delay_on);
-err_out:
-       led_cdev->trigger_data = NULL;
-       kfree(timer_data);
 }
 
 static void timer_trig_deactivate(struct led_classdev *led_cdev)
 {
-       struct timer_trig_data *timer_data = led_cdev->trigger_data;
-       unsigned long on = 0, off = 0;
-
-       if (timer_data) {
+       if (led_cdev->trigger_data) {
                device_remove_file(led_cdev->dev, &dev_attr_delay_on);
                device_remove_file(led_cdev->dev, &dev_attr_delay_off);
-               del_timer_sync(&timer_data->timer);
-               kfree(timer_data);
        }
 
-       /* If there is hardware support for blinking, stop it */
-       if (led_cdev->blink_set)
-               led_cdev->blink_set(led_cdev, &on, &off);
+       /* Stop blinking */
+       led_brightness_set(led_cdev, LED_OFF);
 }
 
 static struct led_trigger timer_led_trigger = {
index 4446966..f5f4da3 100644 (file)
@@ -80,7 +80,7 @@ static void adb_iop_end_req(struct adb_request *req, int state)
 static void adb_iop_complete(struct iop_msg *msg)
 {
        struct adb_request *req;
-       uint flags;
+       unsigned long flags;
 
        local_irq_save(flags);
 
@@ -103,7 +103,7 @@ static void adb_iop_listen(struct iop_msg *msg)
 {
        struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message;
        struct adb_request *req;
-       uint flags;
+       unsigned long flags;
 #ifdef DEBUG_ADB_IOP
        int i;
 #endif
index f9b91ba..0ed0935 100644 (file)
@@ -123,7 +123,7 @@ static ssize_t als_sensing_range_store(struct device *dev,
 {
        struct i2c_client *client = to_i2c_client(dev);
        struct als_data *data = i2c_get_clientdata(client);
-       unsigned int ret_val;
+       int ret_val;
        unsigned long val;
 
        if (strict_strtoul(buf, 10, &val))
index cee632e..d79a972 100644 (file)
@@ -649,7 +649,7 @@ static ssize_t bh1770_power_state_store(struct device *dev,
 {
        struct bh1770_chip *chip =  dev_get_drvdata(dev);
        unsigned long value;
-       size_t ret;
+       ssize_t ret;
 
        if (strict_strtoul(buf, 0, &value))
                return -EINVAL;
@@ -659,8 +659,12 @@ static ssize_t bh1770_power_state_store(struct device *dev,
                pm_runtime_get_sync(dev);
 
                ret = bh1770_lux_rate(chip, chip->lux_rate_index);
-               ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
+               if (ret < 0) {
+                       pm_runtime_put(dev);
+                       goto leave;
+               }
 
+               ret = bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
                if (ret < 0) {
                        pm_runtime_put(dev);
                        goto leave;
index 34fe835..ca47e62 100644 (file)
@@ -87,7 +87,7 @@ static ssize_t als_sensing_range_store(struct device *dev,
                struct device_attribute *attr, const  char *buf, size_t count)
 {
        struct i2c_client *client = to_i2c_client(dev);
-       unsigned int ret_val;
+       int ret_val;
        unsigned long val;
 
        if (strict_strtoul(buf, 10, &val))
@@ -106,6 +106,8 @@ static ssize_t als_sensing_range_store(struct device *dev,
                val = 4;
 
        ret_val = i2c_smbus_read_byte_data(client, 0x00);
+       if (ret_val < 0)
+               return ret_val;
 
        ret_val &= 0xFC; /*reset the bit before setting them */
        ret_val |= val - 1;
index 43579b3..5336310 100644 (file)
@@ -3043,7 +3043,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
        atl1_pcie_patch(adapter);
        /* assume we have no link for now */
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
        setup_timer(&adapter->phy_config_timer, atl1_phy_config,
                    (unsigned long)adapter);
index 9eea225..863e73a 100644 (file)
@@ -20,8 +20,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.60.00-3"
-#define DRV_MODULE_RELDATE      "2010/10/19"
+#define DRV_MODULE_VERSION      "1.60.00-4"
+#define DRV_MODULE_RELDATE      "2010/11/01"
 #define BNX2X_BC_VER            0x040200
 
 #define BNX2X_MULTI_QUEUE
index 18c8e23..4cfd4e9 100644 (file)
@@ -244,7 +244,14 @@ struct port_hw_cfg {                           /* port 0: 0x12c  port 1: 0x2bc */
 
        u16 xgxs_config_tx[4];                              /* 0x1A0 */
 
-       u32 Reserved1[57];                                  /* 0x1A8 */
+       u32 Reserved1[56];                                  /* 0x1A8 */
+       u32 default_cfg;                                    /* 0x288 */
+       /*  Enable BAM on KR */
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_MASK                    0x00100000
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_SHIFT                   20
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_DISABLED                0x00000000
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED                 0x00100000
+
        u32 speed_capability_mask2;                         /* 0x28C */
 #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_MASK                0x0000FFFF
 #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_SHIFT               0
index 2326774..5809196 100644 (file)
@@ -610,7 +610,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params,
        /* reset and unreset the BigMac */
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
                     (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
-       udelay(10);
+       msleep(1);
 
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
                     (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
@@ -3525,13 +3525,19 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
        DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
 
        /* Enable CL37 BAM */
-       bnx2x_cl45_read(bp, phy,
-                       MDIO_AN_DEVAD,
-                       MDIO_AN_REG_8073_BAM, &val);
-       bnx2x_cl45_write(bp, phy,
-                        MDIO_AN_DEVAD,
-                        MDIO_AN_REG_8073_BAM, val | 1);
+       if (REG_RD(bp, params->shmem_base +
+                        offsetof(struct shmem_region, dev_info.
+                                 port_hw_config[params->port].default_cfg)) &
+           PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
 
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_AN_DEVAD,
+                               MDIO_AN_REG_8073_BAM, &val);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD,
+                                MDIO_AN_REG_8073_BAM, val | 1);
+               DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
+       }
        if (params->loopback_mode == LOOPBACK_EXT) {
                bnx2x_807x_force_10G(bp, phy);
                DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
@@ -5302,7 +5308,7 @@ static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
 {
        struct bnx2x *bp = params->bp;
        u16 autoneg_val, an_1000_val, an_10_100_val;
-       bnx2x_wait_reset_complete(bp, phy);
+
        bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
                      1 << NIG_LATCH_BC_ENABLE_MI_INT);
 
@@ -5431,6 +5437,7 @@ static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
 
        /* HW reset */
        bnx2x_ext_phy_hw_reset(bp, params->port);
+       bnx2x_wait_reset_complete(bp, phy);
 
        bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
        return bnx2x_848xx_cmn_config_init(phy, params, vars);
@@ -5441,7 +5448,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
                                  struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       u8 port = params->port, initialize = 1;
+       u8 port, initialize = 1;
        u16 val;
        u16 temp;
        u32 actual_phy_selection;
@@ -5450,11 +5457,16 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
        /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
 
        msleep(1);
+       if (CHIP_IS_E2(bp))
+               port = BP_PATH(bp);
+       else
+               port = params->port;
        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
                       MISC_REGISTERS_GPIO_OUTPUT_HIGH,
                       port);
-       msleep(200); /* 100 is not enough */
-
+       bnx2x_wait_reset_complete(bp, phy);
+       /* Wait for GPHY to come out of reset */
+       msleep(50);
        /* BCM84823 requires that XGXS links up first @ 10G for normal
        behavior */
        temp = vars->line_speed;
@@ -5625,7 +5637,11 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
                                   struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
-       u8 port = params->port;
+       u8 port;
+       if (CHIP_IS_E2(bp))
+               port = BP_PATH(bp);
+       else
+               port = params->port;
        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
                            MISC_REGISTERS_GPIO_OUTPUT_LOW,
                            port);
@@ -6928,7 +6944,7 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
                  u8 reset_ext_phy)
 {
        struct bnx2x *bp = params->bp;
-       u8 phy_index, port = params->port;
+       u8 phy_index, port = params->port, clear_latch_ind = 0;
        DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
        /* disable attentions */
        vars->link_status = 0;
@@ -6966,9 +6982,18 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
                                params->phy[phy_index].link_reset(
                                        &params->phy[phy_index],
                                        params);
+                       if (params->phy[phy_index].flags &
+                           FLAGS_REARM_LATCH_SIGNAL)
+                               clear_latch_ind = 1;
                }
        }
 
+       if (clear_latch_ind) {
+               /* Clear latching indication */
+               bnx2x_rearm_latch_signal(bp, port, 0);
+               bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
+                              1 << NIG_LATCH_BC_ENABLE_MI_INT);
+       }
        if (params->phy[INT_PHY].link_reset)
                params->phy[INT_PHY].link_reset(
                        &params->phy[INT_PHY], params);
@@ -6999,6 +7024,7 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
        s8 port;
        s8 port_of_path = 0;
 
+       bnx2x_ext_phy_hw_reset(bp, 0);
        /* PART1 - Reset both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                u32 shmem_base, shmem2_base;
@@ -7021,7 +7047,8 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
                        return -EINVAL;
                }
                /* disable attentions */
-               bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+               bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
+                              port_of_path*4,
                             (NIG_MASK_XGXS0_LINK_STATUS |
                              NIG_MASK_XGXS0_LINK10G |
                              NIG_MASK_SERDES0_LINK_STATUS |
@@ -7132,7 +7159,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp,
                (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
        REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
 
-       bnx2x_ext_phy_hw_reset(bp, 1);
+       bnx2x_ext_phy_hw_reset(bp, 0);
        msleep(5);
        for (port = 0; port < PORT_MAX; port++) {
                u32 shmem_base, shmem2_base;
index 8427533..8b4cea5 100644 (file)
@@ -33,6 +33,9 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
 MODULE_DESCRIPTION("CAIF SPI driver");
 
+/* Returns the number of padding bytes for alignment. */
+#define PAD_POW2(x, pow) ((((x)&((pow)-1))==0) ? 0 : (((pow)-((x)&((pow)-1)))))
+
 static int spi_loop;
 module_param(spi_loop, bool, S_IRUGO);
 MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
@@ -41,7 +44,10 @@ MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
 module_param(spi_frm_align, int, S_IRUGO);
 MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
 
-/* SPI padding options. */
+/*
+ * SPI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
 module_param(spi_up_head_align, int, S_IRUGO);
 MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
 
@@ -240,15 +246,13 @@ static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
 static const struct file_operations dbgfs_state_fops = {
        .open = dbgfs_open,
        .read = dbgfs_state,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
+       .owner = THIS_MODULE
 };
 
 static const struct file_operations dbgfs_frame_fops = {
        .open = dbgfs_open,
        .read = dbgfs_frame,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
+       .owner = THIS_MODULE
 };
 
 static inline void dev_debugfs_add(struct cfspi *cfspi)
@@ -337,6 +341,9 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
        u8 *dst = buf;
        caif_assert(buf);
 
+       if (cfspi->slave && !cfspi->slave_talked)
+               cfspi->slave_talked = true;
+
        do {
                struct sk_buff *skb;
                struct caif_payload_info *info;
@@ -357,8 +364,8 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute head offset i.e. number of bytes to add to
                 * get the start of the payload aligned.
                 */
-               if (spi_up_head_align) {
-                       spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+               if (spi_up_head_align > 1) {
+                       spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
                        *dst = (u8)(spad - 1);
                        dst += spad;
                }
@@ -373,7 +380,7 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute tail offset i.e. number of bytes to add to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (skb->len + spad) & spi_up_tail_align;
+               epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
                dst += epad;
 
                dev_kfree_skb(skb);
@@ -417,14 +424,14 @@ int cfspi_xmitlen(struct cfspi *cfspi)
                 * Compute head offset i.e. number of bytes to add to
                 * get the start of the payload aligned.
                 */
-               if (spi_up_head_align)
-                       spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+               if (spi_up_head_align > 1)
+                       spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
 
                /*
                 * Compute tail offset i.e. number of bytes to add to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (skb->len + spad) & spi_up_tail_align;
+               epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
 
                if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
                        skb_queue_tail(&cfspi->chead, skb);
@@ -433,6 +440,7 @@ int cfspi_xmitlen(struct cfspi *cfspi)
                } else {
                        /* Put back packet. */
                        skb_queue_head(&cfspi->qhead, skb);
+                       break;
                }
        } while (pkts <= CAIF_MAX_SPI_PKTS);
 
@@ -453,6 +461,15 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
 {
        struct cfspi *cfspi = (struct cfspi *)ifc->priv;
 
+       /*
+        * The slave device is the master on the link. Interrupts before the
+        * slave has transmitted are considered spurious.
+        */
+       if (cfspi->slave && !cfspi->slave_talked) {
+               printk(KERN_WARNING "CFSPI: Spurious SS interrupt.\n");
+               return;
+       }
+
        if (!in_interrupt())
                spin_lock(&cfspi->lock);
        if (assert) {
@@ -465,7 +482,8 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
                spin_unlock(&cfspi->lock);
 
        /* Wake up the xfer thread. */
-       wake_up_interruptible(&cfspi->wait);
+       if (assert)
+               wake_up_interruptible(&cfspi->wait);
 }
 
 static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
@@ -523,7 +541,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute head offset i.e. number of bytes added to
                 * get the start of the payload aligned.
                 */
-               if (spi_down_head_align) {
+               if (spi_down_head_align > 1) {
                        spad = 1 + *src;
                        src += spad;
                }
@@ -564,7 +582,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute tail offset i.e. number of bytes added to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (pkt_len + spad) & spi_down_tail_align;
+               epad = PAD_POW2((pkt_len + spad), spi_down_tail_align);
                src += epad;
        } while ((src - buf) < len);
 
@@ -625,11 +643,20 @@ int cfspi_spi_probe(struct platform_device *pdev)
        cfspi->ndev = ndev;
        cfspi->pdev = pdev;
 
-       /* Set flow info */
+       /* Set flow info. */
        cfspi->flow_off_sent = 0;
        cfspi->qd_low_mark = LOW_WATER_MARK;
        cfspi->qd_high_mark = HIGH_WATER_MARK;
 
+       /* Set slave info. */
+       if (!strncmp(cfspi_spi_driver.driver.name, "cfspi_sspi", 10)) {
+               cfspi->slave = true;
+               cfspi->slave_talked = false;
+       } else {
+               cfspi->slave = false;
+               cfspi->slave_talked = false;
+       }
+
        /* Assign the SPI device. */
        cfspi->dev = dev;
        /* Assign the device ifc to this SPI interface. */
index 2111dbf..1b9943a 100644 (file)
@@ -36,10 +36,15 @@ static inline int forward_to_spi_cmd(struct cfspi *cfspi)
 #endif
 
 int spi_frm_align = 2;
-int spi_up_head_align = 1;
-int spi_up_tail_align;
-int spi_down_head_align = 3;
-int spi_down_tail_align = 1;
+
+/*
+ * SPI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
+int spi_up_head_align   = 1 << 1;
+int spi_up_tail_align   = 1 << 0;
+int spi_down_head_align = 1 << 2;
+int spi_down_tail_align = 1 << 1;
 
 #ifdef CONFIG_DEBUG_FS
 static inline void debugfs_store_prev(struct cfspi *cfspi)
index 407d4e2..046d846 100644 (file)
@@ -3341,7 +3341,6 @@ static int __devinit init_one(struct pci_dev *pdev,
                                adapter->name = adapter->port[i]->name;
 
                        __set_bit(i, &adapter->registered_device_map);
-                       netif_tx_stop_all_queues(adapter->port[i]);
                }
        }
        if (!adapter->registered_device_map) {
index f17703f..f50bc98 100644 (file)
@@ -3736,7 +3736,6 @@ static int __devinit init_one(struct pci_dev *pdev,
 
                        __set_bit(i, &adapter->registered_device_map);
                        adapter->chan_map[adap2pinfo(adapter, i)->tx_chan] = i;
-                       netif_tx_stop_all_queues(adapter->port[i]);
                }
        }
        if (!adapter->registered_device_map) {
index 555ecc5..6de5e2e 100644 (file)
@@ -2600,7 +2600,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
                pi->xact_addr_filt = -1;
                pi->rx_offload = RX_CSO;
                netif_carrier_off(netdev);
-               netif_tx_stop_all_queues(netdev);
                netdev->irq = pdev->irq;
 
                netdev->features = (NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
index 385dc32..06bb9b7 100644 (file)
@@ -2871,7 +2871,6 @@ static int __devinit emac_probe(struct platform_device *ofdev,
        SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);
 
        netif_carrier_off(ndev);
-       netif_stop_queue(ndev);
 
        err = register_netdev(ndev);
        if (err) {
index d85edf3..c57d9a4 100644 (file)
@@ -2955,11 +2955,7 @@ jme_init_one(struct pci_dev *pdev,
         * Tell stack that we are not ready to work until open()
         */
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
-       /*
-        * Register netdev
-        */
        rc = register_netdev(netdev);
        if (rc) {
                pr_err("Cannot register net device\n");
index a75ba95..e1d30d7 100644 (file)
@@ -41,9 +41,6 @@
 MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID);
-MODULE_FIRMWARE(NX_P2_MN_ROMIMAGE_NAME);
-MODULE_FIRMWARE(NX_P3_CT_ROMIMAGE_NAME);
-MODULE_FIRMWARE(NX_P3_MN_ROMIMAGE_NAME);
 MODULE_FIRMWARE(NX_UNIFIED_ROMIMAGE_NAME);
 
 char netxen_nic_driver_name[] = "netxen_nic";
index 7a298cd..a3dcd04 100644 (file)
@@ -1450,7 +1450,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
        netdev->irq = adapter->msix_entries[0].vector;
 
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
        err = register_netdev(netdev);
        if (err) {
index 52f38e1..50f712e 100644 (file)
@@ -22,7 +22,7 @@
 #define __SMSC911X_H__
 
 #define TX_FIFO_LOW_THRESHOLD  ((u32)1600)
-#define SMSC911X_EEPROM_SIZE   ((u32)7)
+#define SMSC911X_EEPROM_SIZE   ((u32)128)
 #define USE_DEBUG              0
 
 /* This is the maximum number of packets to be received every
index 28e1ffb..c78a505 100644 (file)
@@ -2021,7 +2021,6 @@ static int __devinit de_init_one (struct pci_dev *pdev,
        de->media_timer.data = (unsigned long) de;
 
        netif_carrier_off(dev);
-       netif_stop_queue(dev);
 
        /* wake up device, assign resources */
        rc = pci_enable_device(pdev);
index ca7fc9d..c04d49e 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/pm_runtime.h>
 
 #define DRIVER_VERSION         "22-Aug-2005"
 
@@ -1273,6 +1274,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        struct usb_device               *xdev;
        int                             status;
        const char                      *name;
+       struct usb_driver       *driver = to_usb_driver(udev->dev.driver);
+
+       /* usbnet already took usb runtime pm, so have to enable the feature
+        * for usb interface, otherwise usb_autopm_get_interface may return
+        * failure if USB_SUSPEND(RUNTIME_PM) is enabled.
+        */
+       if (!driver->supports_autosuspend) {
+               driver->supports_autosuspend = 1;
+               pm_runtime_enable(&udev->dev);
+       }
 
        name = udev->dev.driver->name;
        info = (struct driver_info *) prod->driver_info;
index 32dee2c..d5ef696 100644 (file)
@@ -54,6 +54,7 @@
 
 #define DRV_DESCRIPTION "802.11 data/management/control stack"
 #define DRV_NAME        "libipw"
+#define DRV_PROCNAME   "ieee80211"
 #define DRV_VERSION    LIBIPW_VERSION
 #define DRV_COPYRIGHT   "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
 
@@ -293,16 +294,16 @@ static int __init libipw_init(void)
        struct proc_dir_entry *e;
 
        libipw_debug_level = debug;
-       libipw_proc = proc_mkdir("ieee80211", init_net.proc_net);
+       libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net);
        if (libipw_proc == NULL) {
-               LIBIPW_ERROR("Unable to create " DRV_NAME
+               LIBIPW_ERROR("Unable to create " DRV_PROCNAME
                                " proc directory\n");
                return -EIO;
        }
        e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc,
                        &debug_level_proc_fops);
        if (!e) {
-               remove_proc_entry(DRV_NAME, init_net.proc_net);
+               remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
                libipw_proc = NULL;
                return -EIO;
        }
@@ -319,7 +320,7 @@ static void __exit libipw_exit(void)
 #ifdef CONFIG_LIBIPW_DEBUG
        if (libipw_proc) {
                remove_proc_entry("debug_level", libipw_proc);
-               remove_proc_entry(DRV_NAME, init_net.proc_net);
+               remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
                libipw_proc = NULL;
        }
 #endif                         /* CONFIG_LIBIPW_DEBUG */
index eea1ef2..4396d4b 100644 (file)
@@ -221,9 +221,6 @@ config RT2X00_LIB_LEDS
        boolean
        default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
 
-comment "rt2x00 leds support disabled due to modularized LEDS_CLASS and built-in rt2x00"
-       depends on RT2X00_LIB=y && LEDS_CLASS=m
-
 config RT2X00_LIB_DEBUGFS
        bool "Ralink debugfs support"
        depends on RT2X00_LIB && MAC80211_DEBUGFS
index 68cf0c9..7b5080c 100644 (file)
@@ -1159,11 +1159,11 @@ int __devinit rio_init_mports(void)
 
        list_for_each_entry(port, &rio_mports, node) {
                if (!request_mem_region(port->iores.start,
-                                       port->iores.end - port->iores.start,
+                                       resource_size(&port->iores),
                                        port->name)) {
                        printk(KERN_ERR
                               "RIO: Error requesting master port region 0x%016llx-0x%016llx\n",
-                              (u64)port->iores.start, (u64)port->iores.end - 1);
+                              (u64)port->iores.start, (u64)port->iores.end);
                        rc = -ENOMEM;
                        goto out;
                }
index 359d1e0..f0d6389 100644 (file)
@@ -35,7 +35,7 @@
 
 #ifdef CONFIG_SH_SECUREEDGE5410
 #include <asm/rtc.h>
-#include <mach/snapgear.h>
+#include <mach/secureedge5410.h>
 
 #define        RTC_RESET       0x1000
 #define        RTC_IODATA      0x0800
index fd0d1b9..09615b5 100644 (file)
@@ -90,8 +90,8 @@ struct clk_rate_round_data {
 static long clk_rate_round_helper(struct clk_rate_round_data *rounder)
 {
        unsigned long rate_error, rate_error_prev = ~0UL;
-       unsigned long rate_best_fit = rounder->rate;
        unsigned long highest, lowest, freq;
+       long rate_best_fit = -ENOENT;
        int i;
 
        highest = 0;
@@ -146,7 +146,7 @@ long clk_rate_table_round(struct clk *clk,
        };
 
        if (clk->nr_freqs < 1)
-               return 0;
+               return -ENOSYS;
 
        return clk_rate_round_helper(&table_round);
 }
@@ -541,6 +541,98 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL_GPL(clk_round_rate);
 
+long clk_round_parent(struct clk *clk, unsigned long target,
+                     unsigned long *best_freq, unsigned long *parent_freq,
+                     unsigned int div_min, unsigned int div_max)
+{
+       struct cpufreq_frequency_table *freq, *best = NULL;
+       unsigned long error = ULONG_MAX, freq_high, freq_low, div;
+       struct clk *parent = clk_get_parent(clk);
+
+       if (!parent) {
+               *parent_freq = 0;
+               *best_freq = clk_round_rate(clk, target);
+               return abs(target - *best_freq);
+       }
+
+       for (freq = parent->freq_table; freq->frequency != CPUFREQ_TABLE_END;
+            freq++) {
+               if (freq->frequency == CPUFREQ_ENTRY_INVALID)
+                       continue;
+
+               if (unlikely(freq->frequency / target <= div_min - 1)) {
+                       unsigned long freq_max;
+
+                       freq_max = (freq->frequency + div_min / 2) / div_min;
+                       if (error > target - freq_max) {
+                               error = target - freq_max;
+                               best = freq;
+                               if (best_freq)
+                                       *best_freq = freq_max;
+                       }
+
+                       pr_debug("too low freq %lu, error %lu\n", freq->frequency,
+                                target - freq_max);
+
+                       if (!error)
+                               break;
+
+                       continue;
+               }
+
+               if (unlikely(freq->frequency / target >= div_max)) {
+                       unsigned long freq_min;
+
+                       freq_min = (freq->frequency + div_max / 2) / div_max;
+                       if (error > freq_min - target) {
+                               error = freq_min - target;
+                               best = freq;
+                               if (best_freq)
+                                       *best_freq = freq_min;
+                       }
+
+                       pr_debug("too high freq %lu, error %lu\n", freq->frequency,
+                                freq_min - target);
+
+                       if (!error)
+                               break;
+
+                       continue;
+               }
+
+               div = freq->frequency / target;
+               freq_high = freq->frequency / div;
+               freq_low = freq->frequency / (div + 1);
+
+               if (freq_high - target < error) {
+                       error = freq_high - target;
+                       best = freq;
+                       if (best_freq)
+                               *best_freq = freq_high;
+               }
+
+               if (target - freq_low < error) {
+                       error = target - freq_low;
+                       best = freq;
+                       if (best_freq)
+                               *best_freq = freq_low;
+               }
+
+               pr_debug("%u / %lu = %lu, / %lu = %lu, best %lu, parent %u\n",
+                        freq->frequency, div, freq_high, div + 1, freq_low,
+                        *best_freq, best->frequency);
+
+               if (!error)
+                       break;
+       }
+
+       if (parent_freq)
+               *parent_freq = best->frequency;
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(clk_round_parent);
+
 #ifdef CONFIG_PM
 static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
 {
index 873a99f..e5e9e67 100644 (file)
@@ -79,7 +79,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
         * Register the IRQ position with the global IRQ map, then insert
         * it in to the radix tree.
         */
-       irq_reserve_irqs(irq, 1);
+       irq_reserve_irq(irq);
 
        raw_spin_lock_irqsave(&intc_big_lock, flags);
        radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq));
index 4187cce..a3677c9 100644 (file)
@@ -60,5 +60,5 @@ void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
        int i;
 
        for (i = 0; i < nr_vecs; i++)
-               irq_reserve_irqs(evt2irq(vectors[i].vect), 1);
+               irq_reserve_irq(evt2irq(vectors[i].vect));
 }
index 22c6c66..ee8b477 100644 (file)
@@ -285,9 +285,9 @@ A_STATUS SetupHIFScatterSupport(HIF_DEVICE *device, HIF_DEVICE_SCATTER_SUPPORT_I
     do {
         
             /* check if host supports scatter requests and it meets our requirements */
-        if (device->func->card->host->max_hw_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
+        if (device->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : host only supports scatter of : %d entries, need: %d \n",
-                    device->func->card->host->max_hw_segs, MAX_SCATTER_ENTRIES_PER_REQ));
+                    device->func->card->host->max_segs, MAX_SCATTER_ENTRIES_PER_REQ));
             status = A_ENOTSUP;
             break;    
         }
diff --git a/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h
deleted file mode 100644 (file)
index e69de29..0000000
index bbf3d9c..097e82b 100644 (file)
@@ -766,7 +766,7 @@ static int solo_enc_open(struct file *file)
                                    &solo_enc->lock,
                                    V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    V4L2_FIELD_INTERLACED,
-                                   sizeof(struct videobuf_buffer), fh);
+                                   sizeof(struct videobuf_buffer), fh, NULL);
 
        spin_unlock(&solo_enc->lock);
 
index 9731fa0..6ffd21d 100644 (file)
@@ -437,7 +437,7 @@ static int solo_v4l2_open(struct file *file)
                                    &solo_dev->pdev->dev, &fh->slock,
                                    V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    SOLO_DISP_PIX_FIELD,
-                                   sizeof(struct videobuf_buffer), fh);
+                                   sizeof(struct videobuf_buffer), fh, NULL);
 
        return 0;
 }
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
new file mode 100644 (file)
index 0000000..c43ef48
--- /dev/null
@@ -0,0 +1,11 @@
+obj-y                          += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
+                                  tty_buffer.o tty_port.o tty_mutex.o
+obj-$(CONFIG_LEGACY_PTYS)      += pty.o
+obj-$(CONFIG_UNIX98_PTYS)      += pty.o
+obj-$(CONFIG_AUDIT)            += tty_audit.o
+obj-$(CONFIG_MAGIC_SYSRQ)      += sysrq.o
+obj-$(CONFIG_N_HDLC)           += n_hdlc.o
+obj-$(CONFIG_N_GSM)            += n_gsm.o
+obj-$(CONFIG_R3964)            += n_r3964.o
+
+obj-y                          += vt/
similarity index 100%
rename from drivers/char/n_gsm.c
rename to drivers/tty/n_gsm.c
similarity index 100%
rename from drivers/char/n_hdlc.c
rename to drivers/tty/n_hdlc.c
similarity index 100%
rename from drivers/char/n_r3964.c
rename to drivers/tty/n_r3964.c
similarity index 100%
rename from drivers/char/n_tty.c
rename to drivers/tty/n_tty.c
similarity index 100%
rename from drivers/char/pty.c
rename to drivers/tty/pty.c
similarity index 100%
rename from drivers/char/sysrq.c
rename to drivers/tty/sysrq.c
similarity index 100%
rename from drivers/char/tty_io.c
rename to drivers/tty/tty_io.c
diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile
new file mode 100644 (file)
index 0000000..14a51c9
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# This file contains the font map for the default (hardware) font
+#
+FONTMAPFILE = cp437.uni
+
+obj-$(CONFIG_VT)                       += vt_ioctl.o vc_screen.o \
+                                          selection.o keyboard.o
+obj-$(CONFIG_CONSOLE_TRANSLATIONS)     += consolemap.o consolemap_deftbl.o
+obj-$(CONFIG_HW_CONSOLE)               += vt.o defkeymap.o
+
+# Files generated that shall be removed upon make clean
+clean-files := consolemap_deftbl.c defkeymap.c
+
+quiet_cmd_conmk = CONMK   $@
+      cmd_conmk = scripts/conmakehash $< > $@
+
+$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
+       $(call cmd,conmk)
+
+$(obj)/defkeymap.o:  $(obj)/defkeymap.c
+
+# Uncomment if you're changing the keymap and have an appropriate
+# loadkeys version for the map. By default, we'll use the shipped
+# versions.
+# GENERATE_KEYMAP := 1
+
+ifdef GENERATE_KEYMAP
+
+$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
+       loadkeys --mktable $< > $@.tmp
+       sed -e 's/^static *//' $@.tmp > $@
+       rm $@.tmp
+
+endif
similarity index 100%
rename from drivers/char/vt.c
rename to drivers/tty/vt/vt.c
index cb23355..fbe86ca 100644 (file)
@@ -811,7 +811,6 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
                INFO(dev, "MAC %pM\n", net->dev_addr);
                INFO(dev, "HOST MAC %pM\n", dev->host_mac);
 
-               netif_stop_queue(net);
                the_dev = dev;
        }
 
index 3ec2460..734c650 100644 (file)
@@ -502,8 +502,10 @@ static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
        struct adp8860_bl *data = dev_get_drvdata(dev);
+       int ret = strict_strtoul(buf, 10, &data->cached_daylight_max);
+       if (ret)
+               return ret;
 
-       strict_strtoul(buf, 10, &data->cached_daylight_max);
        return adp8860_store(dev, buf, count, ADP8860_BLMX1);
 }
 static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show,
@@ -614,7 +616,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev,
        if (val == 0) {
                /* Enable automatic ambient light sensing */
                adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
-       } else if ((val > 0) && (val < 6)) {
+       } else if ((val > 0) && (val <= 3)) {
                /* Disable automatic ambient light sensing */
                adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
 
@@ -622,7 +624,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev,
                mutex_lock(&data->lock);
                adp8860_read(data->client, ADP8860_CFGR, &reg_val);
                reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
-               reg_val |= val << CFGR_BLV_SHIFT;
+               reg_val |= (val - 1) << CFGR_BLV_SHIFT;
                adp8860_write(data->client, ADP8860_CFGR, reg_val);
                mutex_unlock(&data->lock);
        }
index 9093ef0..c67801e 100644 (file)
@@ -78,7 +78,7 @@ static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power)
        const u16 slpin = 0x10;
        const u16 disoff = 0x28;
 
-       if (power) {
+       if (power <= FB_BLANK_NORMAL) {
                if (priv->lcd_on)
                        return 0;
 
index abc43a0..5d3cf33 100644 (file)
@@ -129,7 +129,7 @@ static int lms283gf05_power_set(struct lcd_device *ld, int power)
        struct spi_device *spi = st->spi;
        struct lms283gf05_pdata *pdata = spi->dev.platform_data;
 
-       if (power) {
+       if (power <= FB_BLANK_NORMAL) {
                if (pdata)
                        lms283gf05_reset(pdata->reset_gpio,
                                        pdata->reset_inverted);
index 9fb533f..1485f73 100644 (file)
@@ -335,6 +335,24 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
                },
                .driver_data    = (void *)&nvidia_chipset_data,
        },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBookAir 3,1",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"),
+               },
+               .driver_data    = (void *)&nvidia_chipset_data,
+       },
+       {
+               .callback       = mbp_dmi_match,
+               .ident          = "MacBookAir 3,2",
+               .matches        = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"),
+               },
+               .driver_data    = (void *)&nvidia_chipset_data,
+       },
        { }
 };
 
index 5504435..21866ec 100644 (file)
@@ -25,6 +25,7 @@ struct pwm_bl_data {
        struct pwm_device       *pwm;
        struct device           *dev;
        unsigned int            period;
+       unsigned int            lth_brightness;
        int                     (*notify)(struct device *,
                                          int brightness);
 };
@@ -48,7 +49,9 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
                pwm_config(pb->pwm, 0, pb->period);
                pwm_disable(pb->pwm);
        } else {
-               pwm_config(pb->pwm, brightness * pb->period / max, pb->period);
+               brightness = pb->lth_brightness +
+                       (brightness * (pb->period - pb->lth_brightness) / max);
+               pwm_config(pb->pwm, brightness, pb->period);
                pwm_enable(pb->pwm);
        }
        return 0;
@@ -92,6 +95,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 
        pb->period = data->pwm_period_ns;
        pb->notify = data->notify;
+       pb->lth_brightness = data->lth_brightness *
+               (data->pwm_period_ns / data->max_brightness);
        pb->dev = &pdev->dev;
 
        pb->pwm = pwm_request(data->pwm_id, "backlight");
index a3128c9..5927db0 100644 (file)
@@ -729,10 +729,10 @@ static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev,
 
        return strlen(buf);
 }
-static DEVICE_ATTR(gamma_table, 0644,
+static DEVICE_ATTR(gamma_table, 0444,
                s6e63m0_sysfs_show_gamma_table, NULL);
 
-static int __init s6e63m0_probe(struct spi_device *spi)
+static int __devinit s6e63m0_probe(struct spi_device *spi)
 {
        int ret = 0;
        struct s6e63m0 *lcd = NULL;
@@ -829,6 +829,9 @@ static int __devexit s6e63m0_remove(struct spi_device *spi)
        struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
 
        s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
+       device_remove_file(&spi->dev, &dev_attr_gamma_table);
+       device_remove_file(&spi->dev, &dev_attr_gamma_mode);
+       backlight_device_unregister(lcd->bd);
        lcd_device_unregister(lcd->ld);
        kfree(lcd);
 
index 5aff46c..355abcd 100644 (file)
@@ -81,7 +81,7 @@ u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for
 
 v) mount check for unmatched uids
 
-w) Add support for new vfs entry points for setlease and fallocate 
+w) Add support for new vfs entry point for fallocate
 
 x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of 
 processes can proceed better in parallel (on the server)
index 525ba59..e9a393c 100644 (file)
@@ -15,7 +15,7 @@
  *   the GNU Lesser General Public License for more details.
  *
  */
-#include <linux/radix-tree.h>
+#include <linux/rbtree.h>
 
 #ifndef _CIFS_FS_SB_H
 #define _CIFS_FS_SB_H
@@ -42,9 +42,9 @@
 #define CIFS_MOUNT_MULTIUSER   0x20000 /* multiuser mount */
 
 struct cifs_sb_info {
-       struct radix_tree_root tlink_tree;
-#define CIFS_TLINK_MASTER_TAG          0       /* is "master" (mount) tcon */
+       struct rb_root tlink_tree;
        spinlock_t tlink_tree_lock;
+       struct tcon_link *master_tlink;
        struct nls_table *local_nls;
        unsigned int rsize;
        unsigned int wsize;
index 75c4eaa..9c37897 100644 (file)
@@ -116,7 +116,7 @@ cifs_read_super(struct super_block *sb, void *data,
                return -ENOMEM;
 
        spin_lock_init(&cifs_sb->tlink_tree_lock);
-       INIT_RADIX_TREE(&cifs_sb->tlink_tree, GFP_KERNEL);
+       cifs_sb->tlink_tree = RB_ROOT;
 
        rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
        if (rc) {
@@ -321,8 +321,7 @@ cifs_alloc_inode(struct super_block *sb)
        /* Until the file is open and we have gotten oplock
        info back from the server, can not assume caching of
        file data or metadata */
-       cifs_inode->clientCanCacheRead = false;
-       cifs_inode->clientCanCacheAll = false;
+       cifs_set_oplock_level(cifs_inode, 0);
        cifs_inode->delete_pending = false;
        cifs_inode->invalid_mapping = false;
        cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
index f259e4d..b577bf0 100644 (file)
@@ -336,7 +336,8 @@ struct cifsTconInfo {
  * "get" on the container.
  */
 struct tcon_link {
-       unsigned long           tl_index;
+       struct rb_node          tl_rbnode;
+       uid_t                   tl_uid;
        unsigned long           tl_flags;
 #define TCON_LINK_MASTER       0
 #define TCON_LINK_PENDING      1
index edb6d90..7ed69b6 100644 (file)
@@ -104,6 +104,7 @@ extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
 extern u64 cifs_UnixTimeToNT(struct timespec);
 extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
                                      int offset);
+extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 
 extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
                                struct file *file, struct tcon_link *tlink,
index 9eb327d..251a17c 100644 (file)
@@ -116,6 +116,7 @@ struct smb_vol {
 
 static int ipv4_connect(struct TCP_Server_Info *server);
 static int ipv6_connect(struct TCP_Server_Info *server);
+static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
 static void cifs_prune_tlinks(struct work_struct *work);
 
 /*
@@ -2900,24 +2901,16 @@ remote_path_check:
                goto mount_fail_check;
        }
 
-       tlink->tl_index = pSesInfo->linux_uid;
+       tlink->tl_uid = pSesInfo->linux_uid;
        tlink->tl_tcon = tcon;
        tlink->tl_time = jiffies;
        set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
        set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
 
-       rc = radix_tree_preload(GFP_KERNEL);
-       if (rc == -ENOMEM) {
-               kfree(tlink);
-               goto mount_fail_check;
-       }
-
+       cifs_sb->master_tlink = tlink;
        spin_lock(&cifs_sb->tlink_tree_lock);
-       radix_tree_insert(&cifs_sb->tlink_tree, pSesInfo->linux_uid, tlink);
-       radix_tree_tag_set(&cifs_sb->tlink_tree, pSesInfo->linux_uid,
-                          CIFS_TLINK_MASTER_TAG);
+       tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
        spin_unlock(&cifs_sb->tlink_tree_lock);
-       radix_tree_preload_end();
 
        queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
                                TLINK_IDLE_EXPIRE);
@@ -3107,32 +3100,25 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 int
 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
 {
-       int i, ret;
+       struct rb_root *root = &cifs_sb->tlink_tree;
+       struct rb_node *node;
+       struct tcon_link *tlink;
        char *tmp;
-       struct tcon_link *tlink[8];
-       unsigned long index = 0;
 
        cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
 
-       do {
-               spin_lock(&cifs_sb->tlink_tree_lock);
-               ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
-                                            (void **)tlink, index,
-                                            ARRAY_SIZE(tlink));
-               /* increment index for next pass */
-               if (ret > 0)
-                       index = tlink[ret - 1]->tl_index + 1;
-               for (i = 0; i < ret; i++) {
-                       cifs_get_tlink(tlink[i]);
-                       clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
-                       radix_tree_delete(&cifs_sb->tlink_tree,
-                                                       tlink[i]->tl_index);
-               }
-               spin_unlock(&cifs_sb->tlink_tree_lock);
+       spin_lock(&cifs_sb->tlink_tree_lock);
+       while ((node = rb_first(root))) {
+               tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+               cifs_get_tlink(tlink);
+               clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
+               rb_erase(node, root);
 
-               for (i = 0; i < ret; i++)
-                       cifs_put_tlink(tlink[i]);
-       } while (ret != 0);
+               spin_unlock(&cifs_sb->tlink_tree_lock);
+               cifs_put_tlink(tlink);
+               spin_lock(&cifs_sb->tlink_tree_lock);
+       }
+       spin_unlock(&cifs_sb->tlink_tree_lock);
 
        tmp = cifs_sb->prepath;
        cifs_sb->prepathlen = 0;
@@ -3271,22 +3257,10 @@ out:
        return tcon;
 }
 
-static struct tcon_link *
+static inline struct tcon_link *
 cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
 {
-       struct tcon_link *tlink;
-       unsigned int ret;
-
-       spin_lock(&cifs_sb->tlink_tree_lock);
-       ret = radix_tree_gang_lookup_tag(&cifs_sb->tlink_tree, (void **)&tlink,
-                                       0, 1, CIFS_TLINK_MASTER_TAG);
-       spin_unlock(&cifs_sb->tlink_tree_lock);
-
-       /* the master tcon should always be present */
-       if (ret == 0)
-               BUG();
-
-       return tlink;
+       return cifs_sb->master_tlink;
 }
 
 struct cifsTconInfo *
@@ -3302,6 +3276,47 @@ cifs_sb_tcon_pending_wait(void *unused)
        return signal_pending(current) ? -ERESTARTSYS : 0;
 }
 
+/* find and return a tlink with given uid */
+static struct tcon_link *
+tlink_rb_search(struct rb_root *root, uid_t uid)
+{
+       struct rb_node *node = root->rb_node;
+       struct tcon_link *tlink;
+
+       while (node) {
+               tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+
+               if (tlink->tl_uid > uid)
+                       node = node->rb_left;
+               else if (tlink->tl_uid < uid)
+                       node = node->rb_right;
+               else
+                       return tlink;
+       }
+       return NULL;
+}
+
+/* insert a tcon_link into the tree */
+static void
+tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)
+{
+       struct rb_node **new = &(root->rb_node), *parent = NULL;
+       struct tcon_link *tlink;
+
+       while (*new) {
+               tlink = rb_entry(*new, struct tcon_link, tl_rbnode);
+               parent = *new;
+
+               if (tlink->tl_uid > new_tlink->tl_uid)
+                       new = &((*new)->rb_left);
+               else
+                       new = &((*new)->rb_right);
+       }
+
+       rb_link_node(&new_tlink->tl_rbnode, parent, new);
+       rb_insert_color(&new_tlink->tl_rbnode, root);
+}
+
 /*
  * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
  * current task.
@@ -3309,7 +3324,7 @@ cifs_sb_tcon_pending_wait(void *unused)
  * If the superblock doesn't refer to a multiuser mount, then just return
  * the master tcon for the mount.
  *
- * First, search the radix tree for an existing tcon for this fsuid. If one
+ * First, search the rbtree for an existing tcon for this fsuid. If one
  * exists, then check to see if it's pending construction. If it is then wait
  * for construction to complete. Once it's no longer pending, check to see if
  * it failed and either return an error or retry construction, depending on
@@ -3322,14 +3337,14 @@ struct tcon_link *
 cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
 {
        int ret;
-       unsigned long fsuid = (unsigned long) current_fsuid();
+       uid_t fsuid = current_fsuid();
        struct tcon_link *tlink, *newtlink;
 
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
 
        spin_lock(&cifs_sb->tlink_tree_lock);
-       tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
+       tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
        if (tlink)
                cifs_get_tlink(tlink);
        spin_unlock(&cifs_sb->tlink_tree_lock);
@@ -3338,36 +3353,24 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
                newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
                if (newtlink == NULL)
                        return ERR_PTR(-ENOMEM);
-               newtlink->tl_index = fsuid;
+               newtlink->tl_uid = fsuid;
                newtlink->tl_tcon = ERR_PTR(-EACCES);
                set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
                set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
                cifs_get_tlink(newtlink);
 
-               ret = radix_tree_preload(GFP_KERNEL);
-               if (ret != 0) {
-                       kfree(newtlink);
-                       return ERR_PTR(ret);
-               }
-
                spin_lock(&cifs_sb->tlink_tree_lock);
                /* was one inserted after previous search? */
-               tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
+               tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
                if (tlink) {
                        cifs_get_tlink(tlink);
                        spin_unlock(&cifs_sb->tlink_tree_lock);
-                       radix_tree_preload_end();
                        kfree(newtlink);
                        goto wait_for_construction;
                }
-               ret = radix_tree_insert(&cifs_sb->tlink_tree, fsuid, newtlink);
-               spin_unlock(&cifs_sb->tlink_tree_lock);
-               radix_tree_preload_end();
-               if (ret) {
-                       kfree(newtlink);
-                       return ERR_PTR(ret);
-               }
                tlink = newtlink;
+               tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
+               spin_unlock(&cifs_sb->tlink_tree_lock);
        } else {
 wait_for_construction:
                ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
@@ -3413,39 +3416,39 @@ cifs_prune_tlinks(struct work_struct *work)
 {
        struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
                                                    prune_tlinks.work);
-       struct tcon_link *tlink[8];
-       unsigned long now = jiffies;
-       unsigned long index = 0;
-       int i, ret;
+       struct rb_root *root = &cifs_sb->tlink_tree;
+       struct rb_node *node = rb_first(root);
+       struct rb_node *tmp;
+       struct tcon_link *tlink;
 
-       do {
-               spin_lock(&cifs_sb->tlink_tree_lock);
-               ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
-                                            (void **)tlink, index,
-                                            ARRAY_SIZE(tlink));
-               /* increment index for next pass */
-               if (ret > 0)
-                       index = tlink[ret - 1]->tl_index + 1;
-               for (i = 0; i < ret; i++) {
-                       if (test_bit(TCON_LINK_MASTER, &tlink[i]->tl_flags) ||
-                           atomic_read(&tlink[i]->tl_count) != 0 ||
-                           time_after(tlink[i]->tl_time + TLINK_IDLE_EXPIRE,
-                                      now)) {
-                               tlink[i] = NULL;
-                               continue;
-                       }
-                       cifs_get_tlink(tlink[i]);
-                       clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
-                       radix_tree_delete(&cifs_sb->tlink_tree,
-                                         tlink[i]->tl_index);
-               }
-               spin_unlock(&cifs_sb->tlink_tree_lock);
+       /*
+        * Because we drop the spinlock in the loop in order to put the tlink
+        * it's not guarded against removal of links from the tree. The only
+        * places that remove entries from the tree are this function and
+        * umounts. Because this function is non-reentrant and is canceled
+        * before umount can proceed, this is safe.
+        */
+       spin_lock(&cifs_sb->tlink_tree_lock);
+       node = rb_first(root);
+       while (node != NULL) {
+               tmp = node;
+               node = rb_next(tmp);
+               tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
+
+               if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
+                   atomic_read(&tlink->tl_count) != 0 ||
+                   time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
+                       continue;
 
-               for (i = 0; i < ret; i++) {
-                       if (tlink[i] != NULL)
-                               cifs_put_tlink(tlink[i]);
-               }
-       } while (ret != 0);
+               cifs_get_tlink(tlink);
+               clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
+               rb_erase(tmp, root);
+
+               spin_unlock(&cifs_sb->tlink_tree_lock);
+               cifs_put_tlink(tlink);
+               spin_lock(&cifs_sb->tlink_tree_lock);
+       }
+       spin_unlock(&cifs_sb->tlink_tree_lock);
 
        queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
                                TLINK_IDLE_EXPIRE);
index ae82159..06c3e83 100644 (file)
@@ -146,12 +146,7 @@ client_can_cache:
                rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
                                         xid, NULL);
 
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock granted on inode %p", inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ)
-               pCifsInode->clientCanCacheRead = true;
+       cifs_set_oplock_level(pCifsInode, oplock);
 
        return rc;
 }
@@ -253,12 +248,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
                list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
        spin_unlock(&cifs_file_list_lock);
 
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock inode %p", inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ)
-               pCifsInode->clientCanCacheRead = true;
+       cifs_set_oplock_level(pCifsInode, oplock);
 
        file->private_data = pCifsFile;
        return pCifsFile;
@@ -271,8 +261,9 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
  */
 void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 {
+       struct inode *inode = cifs_file->dentry->d_inode;
        struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
-       struct cifsInodeInfo *cifsi = CIFS_I(cifs_file->dentry->d_inode);
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
        struct cifsLockInfo *li, *tmp;
 
        spin_lock(&cifs_file_list_lock);
@@ -288,8 +279,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
        if (list_empty(&cifsi->openFileList)) {
                cFYI(1, "closing last open instance for inode %p",
                        cifs_file->dentry->d_inode);
-               cifsi->clientCanCacheRead = false;
-               cifsi->clientCanCacheAll  = false;
+               cifs_set_oplock_level(cifsi, 0);
        }
        spin_unlock(&cifs_file_list_lock);
 
@@ -607,8 +597,6 @@ reopen_success:
                rc = filemap_write_and_wait(inode->i_mapping);
                mapping_set_error(inode->i_mapping, rc);
 
-               pCifsInode->clientCanCacheAll = false;
-               pCifsInode->clientCanCacheRead = false;
                if (tcon->unix_ext)
                        rc = cifs_get_inode_info_unix(&inode,
                                full_path, inode->i_sb, xid);
@@ -622,18 +610,9 @@ reopen_success:
             invalidate the current end of file on the server
             we can not go to the server to get the new inod
             info */
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock granted on inode %p",
-                        pCifsFile->dentry->d_inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ) {
-               pCifsInode->clientCanCacheRead = true;
-               pCifsInode->clientCanCacheAll = false;
-       } else {
-               pCifsInode->clientCanCacheRead = false;
-               pCifsInode->clientCanCacheAll = false;
-       }
+
+       cifs_set_oplock_level(pCifsInode, oplock);
+
        cifs_relock_file(pCifsFile);
 
 reopen_error_exit:
@@ -775,12 +754,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
-
-       if (file->private_data == NULL) {
-               rc = -EBADF;
-               FreeXid(xid);
-               return rc;
-       }
        netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
 
        if ((tcon->ses->capabilities & CAP_UNIX) &&
@@ -956,6 +929,7 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
 ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        size_t write_size, loff_t *poffset)
 {
+       struct inode *inode = file->f_path.dentry->d_inode;
        int rc = 0;
        unsigned int bytes_written = 0;
        unsigned int total_written;
@@ -963,7 +937,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        struct cifsTconInfo *pTcon;
        int xid, long_op;
        struct cifsFileInfo *open_file;
-       struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
@@ -1029,21 +1003,17 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
 
        cifs_stats_bytes_written(pTcon, total_written);
 
-       /* since the write may have blocked check these pointers again */
-       if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
-               struct inode *inode = file->f_path.dentry->d_inode;
 /* Do not update local mtime - server will set its actual value on write
- *             inode->i_ctime = inode->i_mtime =
- *                     current_fs_time(inode->i_sb);*/
-               if (total_written > 0) {
-                       spin_lock(&inode->i_lock);
-                       if (*poffset > file->f_path.dentry->d_inode->i_size)
-                               i_size_write(file->f_path.dentry->d_inode,
-                                       *poffset);
-                       spin_unlock(&inode->i_lock);
-               }
-               mark_inode_dirty_sync(file->f_path.dentry->d_inode);
+ *     inode->i_ctime = inode->i_mtime =
+ *             current_fs_time(inode->i_sb);*/
+       if (total_written > 0) {
+               spin_lock(&inode->i_lock);
+               if (*poffset > inode->i_size)
+                       i_size_write(inode, *poffset);
+               spin_unlock(&inode->i_lock);
        }
+       mark_inode_dirty_sync(inode);
+
        FreeXid(xid);
        return total_written;
 }
@@ -1178,7 +1148,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
                                        bool fsuid_only)
 {
        struct cifsFileInfo *open_file;
-       struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+       struct cifs_sb_info *cifs_sb;
        bool any_available = false;
        int rc;
 
@@ -1192,6 +1162,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
                return NULL;
        }
 
+       cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+
        /* only filter by fsuid on multiuser mounts */
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                fsuid_only = false;
index 39869c3..ef3a55b 100644 (file)
@@ -2177,7 +2177,6 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
 
        setattr_copy(inode, attrs);
        mark_inode_dirty(inode);
-       return 0;
 
 cifs_setattr_exit:
        kfree(full_path);
index 077bf75..0c98672 100644 (file)
@@ -38,10 +38,10 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
        struct cifs_sb_info *cifs_sb;
 #ifdef CONFIG_CIFS_POSIX
        struct cifsFileInfo *pSMBFile = filep->private_data;
-       struct cifsTconInfo *tcon = tlink_tcon(pSMBFile->tlink);
+       struct cifsTconInfo *tcon;
        __u64   ExtAttrBits = 0;
        __u64   ExtAttrMask = 0;
-       __u64   caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
+       __u64   caps;
 #endif /* CONFIG_CIFS_POSIX */
 
        xid = GetXid();
@@ -62,9 +62,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
                        break;
 #ifdef CONFIG_CIFS_POSIX
                case FS_IOC_GETFLAGS:
+                       if (pSMBFile == NULL)
+                               break;
+                       tcon = tlink_tcon(pSMBFile->tlink);
+                       caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
                        if (CIFS_UNIX_EXTATTR_CAP & caps) {
-                               if (pSMBFile == NULL)
-                                       break;
                                rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
                                        &ExtAttrBits, &ExtAttrMask);
                                if (rc == 0)
@@ -75,13 +77,15 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
                        break;
 
                case FS_IOC_SETFLAGS:
+                       if (pSMBFile == NULL)
+                               break;
+                       tcon = tlink_tcon(pSMBFile->tlink);
+                       caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
                        if (CIFS_UNIX_EXTATTR_CAP & caps) {
                                if (get_user(ExtAttrBits, (int __user *)arg)) {
                                        rc = -EFAULT;
                                        break;
                                }
-                               if (pSMBFile == NULL)
-                                       break;
                                /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
                                        extAttrBits, &ExtAttrMask);*/
                        }
index c4e296f..43f1028 100644 (file)
@@ -569,10 +569,9 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 
                                cFYI(1, "file id match, oplock break");
                                pCifsInode = CIFS_I(netfile->dentry->d_inode);
-                               pCifsInode->clientCanCacheAll = false;
-                               if (pSMB->OplockLevel == 0)
-                                       pCifsInode->clientCanCacheRead = false;
 
+                               cifs_set_oplock_level(pCifsInode,
+                                                     pSMB->OplockLevel);
                                /*
                                 * cifs_oplock_break_put() can't be called
                                 * from here.  Get reference after queueing
@@ -722,3 +721,23 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
                           cifs_sb_master_tcon(cifs_sb)->treeName);
        }
 }
+
+void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
+{
+       oplock &= 0xF;
+
+       if (oplock == OPLOCK_EXCLUSIVE) {
+               cinode->clientCanCacheAll = true;
+               cinode->clientCanCacheRead = true;
+               cFYI(1, "Exclusive Oplock granted on inode %p",
+                    &cinode->vfs_inode);
+       } else if (oplock == OPLOCK_READ) {
+               cinode->clientCanCacheAll = false;
+               cinode->clientCanCacheRead = true;
+               cFYI(1, "Level II Oplock granted on inode %p",
+                   &cinode->vfs_inode);
+       } else {
+               cinode->clientCanCacheAll = false;
+               cinode->clientCanCacheRead = false;
+       }
+}
index 8b5dd63..6a5edea 100644 (file)
@@ -177,7 +177,7 @@ struct mpage_da_data {
 
 struct ext4_io_page {
        struct page     *p_page;
-       int             p_count;
+       atomic_t        p_count;
 };
 
 #define MAX_IO_PAGES 128
@@ -858,6 +858,7 @@ struct ext4_inode_info {
        spinlock_t i_completed_io_lock;
        /* current io_end structure for async DIO write*/
        ext4_io_end_t *cur_aio_dio;
+       atomic_t i_ioend_count; /* Number of outstanding io_end structs */
 
        /*
         * Transactions that contain inode's metadata needed to complete
@@ -2060,6 +2061,7 @@ extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
 /* page-io.c */
 extern int __init ext4_init_pageio(void);
 extern void ext4_exit_pageio(void);
+extern void ext4_ioend_wait(struct inode *);
 extern void ext4_free_io_end(ext4_io_end_t *io);
 extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags);
 extern int ext4_end_io_nolock(ext4_io_end_t *io);
index 1916164..bdbe699 100644 (file)
@@ -53,6 +53,7 @@
 static inline int ext4_begin_ordered_truncate(struct inode *inode,
                                              loff_t new_size)
 {
+       trace_ext4_begin_ordered_truncate(inode, new_size);
        return jbd2_journal_begin_ordered_truncate(
                                        EXT4_SB(inode->i_sb)->s_journal,
                                        &EXT4_I(inode)->jinode,
@@ -178,6 +179,7 @@ void ext4_evict_inode(struct inode *inode)
        handle_t *handle;
        int err;
 
+       trace_ext4_evict_inode(inode);
        if (inode->i_nlink) {
                truncate_inode_pages(&inode->i_data, 0);
                goto no_delete;
@@ -5410,9 +5412,7 @@ int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
         * will return the blocks that include the delayed allocation
         * blocks for this file.
         */
-       spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
        delalloc_blocks = EXT4_I(inode)->i_reserved_data_blocks;
-       spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
 
        stat->blocks += (delalloc_blocks << inode->i_sb->s_blocksize_bits)>>9;
        return 0;
@@ -5649,6 +5649,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
        int err, ret;
 
        might_sleep();
+       trace_ext4_mark_inode_dirty(inode, _RET_IP_);
        err = ext4_reserve_inode_write(handle, inode, &iloc);
        if (ext4_handle_valid(handle) &&
            EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
index c58eba3..5b4d4e3 100644 (file)
@@ -4640,8 +4640,6 @@ do_more:
                 * with group lock held. generate_buddy look at
                 * them with group lock_held
                 */
-               if (test_opt(sb, DISCARD))
-                       ext4_issue_discard(sb, block_group, bit, count);
                ext4_lock_group(sb, block_group);
                mb_clear_bits(bitmap_bh->b_data, bit, count);
                mb_free_blocks(inode, &e4b, bit, count);
index 46a7d6a..7f5451c 100644 (file)
 
 static struct kmem_cache *io_page_cachep, *io_end_cachep;
 
+#define WQ_HASH_SZ             37
+#define to_ioend_wq(v) (&ioend_wq[((unsigned long)v) % WQ_HASH_SZ])
+static wait_queue_head_t ioend_wq[WQ_HASH_SZ];
+
 int __init ext4_init_pageio(void)
 {
+       int i;
+
        io_page_cachep = KMEM_CACHE(ext4_io_page, SLAB_RECLAIM_ACCOUNT);
        if (io_page_cachep == NULL)
                return -ENOMEM;
@@ -42,6 +48,8 @@ int __init ext4_init_pageio(void)
                kmem_cache_destroy(io_page_cachep);
                return -ENOMEM;
        }
+       for (i = 0; i < WQ_HASH_SZ; i++)
+               init_waitqueue_head(&ioend_wq[i]);
 
        return 0;
 }
@@ -52,24 +60,37 @@ void ext4_exit_pageio(void)
        kmem_cache_destroy(io_page_cachep);
 }
 
+void ext4_ioend_wait(struct inode *inode)
+{
+       wait_queue_head_t *wq = to_ioend_wq(inode);
+
+       wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_ioend_count) == 0));
+}
+
+static void put_io_page(struct ext4_io_page *io_page)
+{
+       if (atomic_dec_and_test(&io_page->p_count)) {
+               end_page_writeback(io_page->p_page);
+               put_page(io_page->p_page);
+               kmem_cache_free(io_page_cachep, io_page);
+       }
+}
+
 void ext4_free_io_end(ext4_io_end_t *io)
 {
        int i;
+       wait_queue_head_t *wq;
 
        BUG_ON(!io);
        if (io->page)
                put_page(io->page);
-       for (i = 0; i < io->num_io_pages; i++) {
-               if (--io->pages[i]->p_count == 0) {
-                       struct page *page = io->pages[i]->p_page;
-
-                       end_page_writeback(page);
-                       put_page(page);
-                       kmem_cache_free(io_page_cachep, io->pages[i]);
-               }
-       }
+       for (i = 0; i < io->num_io_pages; i++)
+               put_io_page(io->pages[i]);
        io->num_io_pages = 0;
-       iput(io->inode);
+       wq = to_ioend_wq(io->inode);
+       if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count) &&
+           waitqueue_active(wq))
+               wake_up_all(wq);
        kmem_cache_free(io_end_cachep, io);
 }
 
@@ -142,8 +163,8 @@ ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags)
        io = kmem_cache_alloc(io_end_cachep, flags);
        if (io) {
                memset(io, 0, sizeof(*io));
-               io->inode = igrab(inode);
-               BUG_ON(!io->inode);
+               atomic_inc(&EXT4_I(inode)->i_ioend_count);
+               io->inode = inode;
                INIT_WORK(&io->work, ext4_end_io_work);
                INIT_LIST_HEAD(&io->list);
        }
@@ -171,35 +192,15 @@ static void ext4_end_bio(struct bio *bio, int error)
        struct workqueue_struct *wq;
        struct inode *inode;
        unsigned long flags;
-       ext4_fsblk_t err_block;
        int i;
 
        BUG_ON(!io_end);
-       inode = io_end->inode;
        bio->bi_private = NULL;
        bio->bi_end_io = NULL;
        if (test_bit(BIO_UPTODATE, &bio->bi_flags))
                error = 0;
-       err_block = bio->bi_sector >> (inode->i_blkbits - 9);
        bio_put(bio);
 
-       if (!(inode->i_sb->s_flags & MS_ACTIVE)) {
-               pr_err("sb umounted, discard end_io request for inode %lu\n",
-                       io_end->inode->i_ino);
-               ext4_free_io_end(io_end);
-               return;
-       }
-
-       if (error) {
-               io_end->flag |= EXT4_IO_END_ERROR;
-               ext4_warning(inode->i_sb, "I/O error writing to inode %lu "
-                            "(offset %llu size %ld starting block %llu)",
-                            inode->i_ino,
-                            (unsigned long long) io_end->offset,
-                            (long) io_end->size,
-                            (unsigned long long) err_block);
-       }
-
        for (i = 0; i < io_end->num_io_pages; i++) {
                struct page *page = io_end->pages[i]->p_page;
                struct buffer_head *bh, *head;
@@ -236,13 +237,7 @@ static void ext4_end_bio(struct bio *bio, int error)
                        } while (bh != head);
                }
 
-               if (--io_end->pages[i]->p_count == 0) {
-                       struct page *page = io_end->pages[i]->p_page;
-
-                       end_page_writeback(page);
-                       put_page(page);
-                       kmem_cache_free(io_page_cachep, io_end->pages[i]);
-               }
+               put_io_page(io_end->pages[i]);
 
                /*
                 * If this is a partial write which happened to make
@@ -254,8 +249,19 @@ static void ext4_end_bio(struct bio *bio, int error)
                if (!partial_write)
                        SetPageUptodate(page);
        }
-
        io_end->num_io_pages = 0;
+       inode = io_end->inode;
+
+       if (error) {
+               io_end->flag |= EXT4_IO_END_ERROR;
+               ext4_warning(inode->i_sb, "I/O error writing to inode %lu "
+                            "(offset %llu size %ld starting block %llu)",
+                            inode->i_ino,
+                            (unsigned long long) io_end->offset,
+                            (long) io_end->size,
+                            (unsigned long long)
+                            bio->bi_sector >> (inode->i_blkbits - 9));
+       }
 
        /* Add the io_end to per-inode completed io list*/
        spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
@@ -305,7 +311,6 @@ static int io_submit_init(struct ext4_io_submit *io,
        bio->bi_private = io->io_end = io_end;
        bio->bi_end_io = ext4_end_bio;
 
-       io_end->inode = inode;
        io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
 
        io->io_bio = bio;
@@ -360,7 +365,7 @@ submit_and_retry:
        if ((io_end->num_io_pages == 0) ||
            (io_end->pages[io_end->num_io_pages-1] != io_page)) {
                io_end->pages[io_end->num_io_pages++] = io_page;
-               io_page->p_count++;
+               atomic_inc(&io_page->p_count);
        }
        return 0;
 }
@@ -389,7 +394,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
                return -ENOMEM;
        }
        io_page->p_page = page;
-       io_page->p_count = 0;
+       atomic_set(&io_page->p_count, 1);
        get_page(page);
 
        for (bh = head = page_buffers(page), block_start = 0;
@@ -421,10 +426,6 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
         * PageWriteback bit from the page to prevent the system from
         * wedging later on.
         */
-       if (io_page->p_count == 0) {
-               put_page(page);
-               end_page_writeback(page);
-               kmem_cache_free(io_page_cachep, io_page);
-       }
+       put_io_page(io_page);
        return ret;
 }
index 40131b7..61182fe 100644 (file)
@@ -828,12 +828,22 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei->cur_aio_dio = NULL;
        ei->i_sync_tid = 0;
        ei->i_datasync_tid = 0;
+       atomic_set(&ei->i_ioend_count, 0);
 
        return &ei->vfs_inode;
 }
 
+static int ext4_drop_inode(struct inode *inode)
+{
+       int drop = generic_drop_inode(inode);
+
+       trace_ext4_drop_inode(inode, drop);
+       return drop;
+}
+
 static void ext4_destroy_inode(struct inode *inode)
 {
+       ext4_ioend_wait(inode);
        if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
                ext4_msg(inode->i_sb, KERN_ERR,
                         "Inode %lu (%p): orphan list check failed!",
@@ -1173,6 +1183,7 @@ static const struct super_operations ext4_sops = {
        .destroy_inode  = ext4_destroy_inode,
        .write_inode    = ext4_write_inode,
        .dirty_inode    = ext4_dirty_inode,
+       .drop_inode     = ext4_drop_inode,
        .evict_inode    = ext4_evict_inode,
        .put_super      = ext4_put_super,
        .sync_fs        = ext4_sync_fs,
@@ -1194,6 +1205,7 @@ static const struct super_operations ext4_nojournal_sops = {
        .destroy_inode  = ext4_destroy_inode,
        .write_inode    = ext4_write_inode,
        .dirty_inode    = ext4_dirty_inode,
+       .drop_inode     = ext4_drop_inode,
        .evict_inode    = ext4_evict_inode,
        .write_super    = ext4_write_super,
        .put_super      = ext4_put_super,
@@ -2699,7 +2711,6 @@ static int ext4_lazyinit_thread(void *arg)
        struct ext4_li_request *elr;
        unsigned long next_wakeup;
        DEFINE_WAIT(wait);
-       int ret;
 
        BUG_ON(NULL == eli);
 
@@ -2723,13 +2734,12 @@ cont_thread:
                        elr = list_entry(pos, struct ext4_li_request,
                                         lr_request);
 
-                       if (time_after_eq(jiffies, elr->lr_next_sched))
-                               ret = ext4_run_li_request(elr);
-
-                       if (ret) {
-                               ret = 0;
-                               ext4_remove_li_request(elr);
-                               continue;
+                       if (time_after_eq(jiffies, elr->lr_next_sched)) {
+                               if (ext4_run_li_request(elr) != 0) {
+                                       /* error, remove the lazy_init job */
+                                       ext4_remove_li_request(elr);
+                                       continue;
+                               }
                        }
 
                        if (time_before(elr->lr_next_sched, next_wakeup))
@@ -2740,7 +2750,8 @@ cont_thread:
                if (freezing(current))
                        refrigerator();
 
-               if (time_after_eq(jiffies, next_wakeup)) {
+               if ((time_after_eq(jiffies, next_wakeup)) ||
+                   (MAX_JIFFY_OFFSET == next_wakeup)) {
                        cond_resched();
                        continue;
                }
@@ -3348,6 +3359,24 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        get_random_bytes(&sbi->s_next_generation, sizeof(u32));
        spin_lock_init(&sbi->s_next_gen_lock);
 
+       err = percpu_counter_init(&sbi->s_freeblocks_counter,
+                       ext4_count_free_blocks(sb));
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_freeinodes_counter,
+                               ext4_count_free_inodes(sb));
+       }
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_dirs_counter,
+                               ext4_count_dirs(sb));
+       }
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
+       }
+       if (err) {
+               ext4_msg(sb, KERN_ERR, "insufficient memory");
+               goto failed_mount3;
+       }
+
        sbi->s_stripe = ext4_get_stripe_size(sbi);
        sbi->s_max_writeback_mb_bump = 128;
 
@@ -3446,22 +3475,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
        set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
 
-no_journal:
-       err = percpu_counter_init(&sbi->s_freeblocks_counter,
-                                 ext4_count_free_blocks(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_freeinodes_counter,
-                                         ext4_count_free_inodes(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_dirs_counter,
-                                         ext4_count_dirs(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
-       if (err) {
-               ext4_msg(sb, KERN_ERR, "insufficient memory");
-               goto failed_mount_wq;
-       }
+       /*
+        * The journal may have updated the bg summary counts, so we
+        * need to update the global counters.
+        */
+       percpu_counter_set(&sbi->s_freeblocks_counter,
+                          ext4_count_free_blocks(sb));
+       percpu_counter_set(&sbi->s_freeinodes_counter,
+                          ext4_count_free_inodes(sb));
+       percpu_counter_set(&sbi->s_dirs_counter,
+                          ext4_count_dirs(sb));
+       percpu_counter_set(&sbi->s_dirtyblocks_counter, 0);
 
+no_journal:
        EXT4_SB(sb)->dio_unwritten_wq = create_workqueue("ext4-dio-unwritten");
        if (!EXT4_SB(sb)->dio_unwritten_wq) {
                printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n");
@@ -3611,10 +3637,6 @@ failed_mount_wq:
                jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
        }
-       percpu_counter_destroy(&sbi->s_freeblocks_counter);
-       percpu_counter_destroy(&sbi->s_freeinodes_counter);
-       percpu_counter_destroy(&sbi->s_dirs_counter);
-       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount3:
        if (sbi->s_flex_groups) {
                if (is_vmalloc_addr(sbi->s_flex_groups))
@@ -3622,6 +3644,10 @@ failed_mount3:
                else
                        kfree(sbi->s_flex_groups);
        }
+       percpu_counter_destroy(&sbi->s_freeblocks_counter);
+       percpu_counter_destroy(&sbi->s_freeinodes_counter);
+       percpu_counter_destroy(&sbi->s_dirs_counter);
+       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -3949,13 +3975,11 @@ static int ext4_commit_super(struct super_block *sb, int sync)
        else
                es->s_kbytes_written =
                        cpu_to_le64(EXT4_SB(sb)->s_kbytes_written);
-       if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeblocks_counter))
-               ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
-                                       &EXT4_SB(sb)->s_freeblocks_counter));
-       if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter))
-               es->s_free_inodes_count =
-                       cpu_to_le32(percpu_counter_sum_positive(
-                                       &EXT4_SB(sb)->s_freeinodes_counter));
+       ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
+                                          &EXT4_SB(sb)->s_freeblocks_counter));
+       es->s_free_inodes_count =
+               cpu_to_le32(percpu_counter_sum_positive(
+                               &EXT4_SB(sb)->s_freeinodes_counter));
        sb->s_dirt = 0;
        BUFFER_TRACE(sbh, "marking dirty");
        mark_buffer_dirty(sbh);
@@ -4556,12 +4580,10 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
 
 static int ext4_quota_off(struct super_block *sb, int type)
 {
-       /* Force all delayed allocation blocks to be allocated */
-       if (test_opt(sb, DELALLOC)) {
-               down_read(&sb->s_umount);
+       /* Force all delayed allocation blocks to be allocated.
+        * Caller already holds s_umount sem */
+       if (test_opt(sb, DELALLOC))
                sync_filesystem(sb);
-               up_read(&sb->s_umount);
-       }
 
        return dquot_quota_off(sb, type);
 }
index d6cfac1..a5fe681 100644 (file)
@@ -932,8 +932,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag,
        if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {
                *user = current_user();
                if (user_shm_lock(size, *user)) {
-                       WARN_ONCE(1,
-                         "Using mlock ulimits for SHM_HUGETLB deprecated\n");
+                       printk_once(KERN_WARNING "Using mlock ulimits for SHM_HUGETLB is deprecated\n");
                } else {
                        *user = NULL;
                        return ERR_PTR(-EPERM);
index cd51a36..57afd4a 100644 (file)
@@ -486,7 +486,7 @@ static inline int logfs_get_sb_bdev(struct logfs_super *s,
 
 /* dev_mtd.c */
 #ifdef CONFIG_MTD
-int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr)
+int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr);
 #else
 static inline int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr)
 {
index ddb1f41..911e61f 100644 (file)
@@ -418,7 +418,7 @@ out_no_root:
 static struct dentry *openprom_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
-       return mount_single(fs_type, flags, data, openprom_fill_super)
+       return mount_single(fs_type, flags, data, openprom_fill_super);
 }
 
 static struct file_system_type openprom_fs_type = {
index 47e6417..bd8cad2 100644 (file)
@@ -33,18 +33,18 @@ struct stat {
        int             st_blksize;     /* Optimal block size for I/O.  */
        int             __pad2;
        long            st_blocks;      /* Number 512-byte blocks allocated. */
-       int             st_atime;       /* Time of last access.  */
-       unsigned int    st_atime_nsec;
-       int             st_mtime;       /* Time of last modification.  */
-       unsigned int    st_mtime_nsec;
-       int             st_ctime;       /* Time of last status change.  */
-       unsigned int    st_ctime_nsec;
+       long            st_atime;       /* Time of last access.  */
+       unsigned long   st_atime_nsec;
+       long            st_mtime;       /* Time of last modification.  */
+       unsigned long   st_mtime_nsec;
+       long            st_ctime;       /* Time of last status change.  */
+       unsigned long   st_ctime_nsec;
        unsigned int    __unused4;
        unsigned int    __unused5;
 };
 
-#if __BITS_PER_LONG != 64
 /* This matches struct stat64 in glibc2.1. Only used for 32 bit. */
+#if __BITS_PER_LONG != 64 || defined(__ARCH_WANT_STAT64)
 struct stat64 {
        unsigned long long st_dev;      /* Device.  */
        unsigned long long st_ino;      /* File serial number.  */
diff --git a/include/linux/atomic.h b/include/linux/atomic.h
new file mode 100644 (file)
index 0000000..96c038e
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _LINUX_ATOMIC_H
+#define _LINUX_ATOMIC_H
+#include <asm/atomic.h>
+
+/**
+ * atomic_inc_not_zero_hint - increment if not null
+ * @v: pointer of type atomic_t
+ * @hint: probable value of the atomic before the increment
+ *
+ * This version of atomic_inc_not_zero() gives a hint of probable
+ * value of the atomic. This helps processor to not read the memory
+ * before doing the atomic read/modify/write cycle, lowering
+ * number of bus transactions on some arches.
+ *
+ * Returns: 0 if increment was not done, 1 otherwise.
+ */
+#ifndef atomic_inc_not_zero_hint
+static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint)
+{
+       int val, c = hint;
+
+       /* sanity test, should be removed by compiler if hint is a constant */
+       if (!hint)
+               return atomic_inc_not_zero(v);
+
+       do {
+               val = atomic_cmpxchg(v, c, c + 1);
+               if (val == c)
+                       return 1;
+               c = val;
+       } while (c);
+
+       return 0;
+}
+#endif
+
+#endif /* _LINUX_ATOMIC_H */
index 8a389b6..41cb31f 100644 (file)
  */
 #define in_nmi()       (preempt_count() & NMI_MASK)
 
-#if defined(CONFIG_PREEMPT)
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_BKL)
 # define PREEMPT_INATOMIC_BASE kernel_locked()
-# define PREEMPT_CHECK_OFFSET 1
 #else
 # define PREEMPT_INATOMIC_BASE 0
+#endif
+
+#if defined(CONFIG_PREEMPT)
+# define PREEMPT_CHECK_OFFSET 1
+#else
 # define PREEMPT_CHECK_OFFSET 0
 #endif
 
index e913819..b676c58 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/uaccess.h>
+#include <linux/hardirq.h>
 
 #include <asm/cacheflush.h>
 
index 450092c..fc3da9e 100644 (file)
@@ -60,7 +60,7 @@ extern const char linux_proc_banner[];
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 #define roundup(x, y) (                                        \
 {                                                      \
-       typeof(y) __y = y;                              \
+       const typeof(y) __y = y;                        \
        (((x) + (__y - 1)) / __y) * __y;                \
 }                                                      \
 )
@@ -293,6 +293,7 @@ extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
                                   unsigned int interval_msec);
 
 extern int printk_delay_msec;
+extern int dmesg_restrict;
 
 /*
  * Print a one-time message (analogous to WARN_ONCE() et al):
diff --git a/include/linux/leds-lp5521.h b/include/linux/leds-lp5521.h
new file mode 100644 (file)
index 0000000..38368d7
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * LP5521 LED chip driver.
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.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
+ */
+
+#ifndef __LINUX_LP5521_H
+#define __LINUX_LP5521_H
+
+/* See Documentation/leds/leds-lp5521.txt */
+
+struct lp5521_led_config {
+       u8              chan_nr;
+       u8              led_current; /* mA x10, 0 if led is not connected */
+       u8              max_current;
+};
+
+#define LP5521_CLOCK_AUTO      0
+#define LP5521_CLOCK_INT       1
+#define LP5521_CLOCK_EXT       2
+
+struct lp5521_platform_data {
+       struct lp5521_led_config *led_config;
+       u8      num_channels;
+       u8      clock_mode;
+       int     (*setup_resources)(void);
+       void    (*release_resources)(void);
+       void    (*enable)(bool state);
+};
+
+#endif /* __LINUX_LP5521_H */
diff --git a/include/linux/leds-lp5523.h b/include/linux/leds-lp5523.h
new file mode 100644 (file)
index 0000000..7967476
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * LP5523 LED Driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Samu Onkalo <samu.p.onkalo@nokia.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
+ */
+
+#ifndef __LINUX_LP5523_H
+#define __LINUX_LP5523_H
+
+/* See Documentation/leds/leds-lp5523.txt */
+
+struct lp5523_led_config {
+       u8              chan_nr;
+       u8              led_current; /* mA x10, 0 if led is not connected */
+       u8              max_current;
+};
+
+#define LP5523_CLOCK_AUTO      0
+#define LP5523_CLOCK_INT       1
+#define LP5523_CLOCK_EXT       2
+
+struct lp5523_platform_data {
+       struct lp5523_led_config *led_config;
+       u8      num_channels;
+       u8      clock_mode;
+       int     (*setup_resources)(void);
+       void    (*release_resources)(void);
+       void    (*enable)(bool state);
+};
+
+#endif /* __LINUX_LP5523_H */
index ba6986a..0f19df9 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/rwsem.h>
+#include <linux/timer.h>
 
 struct device;
 /*
@@ -45,10 +46,14 @@ struct led_classdev {
        /* Get LED brightness level */
        enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
 
-       /* Activate hardware accelerated blink, delays are in
-        * miliseconds and if none is provided then a sensible default
-        * should be chosen. The call can adjust the timings if it can't
-        * match the values specified exactly. */
+       /*
+        * Activate hardware accelerated blink, delays are in milliseconds
+        * and if both are zero then a sensible default should be chosen.
+        * The call should adjust the timings in that case and if it can't
+        * match the values specified exactly.
+        * Deactivate blinking again when the brightness is set to a fixed
+        * value via the brightness_set() callback.
+        */
        int             (*blink_set)(struct led_classdev *led_cdev,
                                     unsigned long *delay_on,
                                     unsigned long *delay_off);
@@ -57,6 +62,10 @@ struct led_classdev {
        struct list_head         node;                  /* LED Device list */
        const char              *default_trigger;       /* Trigger to use */
 
+       unsigned long            blink_delay_on, blink_delay_off;
+       struct timer_list        blink_timer;
+       int                      blink_brightness;
+
 #ifdef CONFIG_LEDS_TRIGGERS
        /* Protects the trigger data below */
        struct rw_semaphore      trigger_lock;
@@ -73,6 +82,36 @@ extern void led_classdev_unregister(struct led_classdev *led_cdev);
 extern void led_classdev_suspend(struct led_classdev *led_cdev);
 extern void led_classdev_resume(struct led_classdev *led_cdev);
 
+/**
+ * led_blink_set - set blinking with software fallback
+ * @led_cdev: the LED to start blinking
+ * @delay_on: the time it should be on (in ms)
+ * @delay_off: the time it should ble off (in ms)
+ *
+ * This function makes the LED blink, attempting to use the
+ * hardware acceleration if possible, but falling back to
+ * software blinking if there is no hardware blinking or if
+ * the LED refuses the passed values.
+ *
+ * Note that if software blinking is active, simply calling
+ * led_cdev->brightness_set() will not stop the blinking,
+ * use led_classdev_brightness_set() instead.
+ */
+extern void led_blink_set(struct led_classdev *led_cdev,
+                         unsigned long *delay_on,
+                         unsigned long *delay_off);
+/**
+ * led_brightness_set - set LED brightness
+ * @led_cdev: the LED to set
+ * @brightness: the brightness to set it to
+ *
+ * Set an LED's brightness, and, if necessary, cancel the
+ * software blink timer that implements blinking when the
+ * hardware doesn't.
+ */
+extern void led_brightness_set(struct led_classdev *led_cdev,
+                              enum led_brightness brightness);
+
 /*
  * LED Triggers
  */
index d19e211..5c99da1 100644 (file)
@@ -59,19 +59,19 @@ struct sh_mmcif_plat_data {
 #define MMCIF_CE_HOST_STS2     0x0000004C
 #define MMCIF_CE_VERSION       0x0000007C
 
-extern inline u32 sh_mmcif_readl(void __iomem *addr, int reg)
+static inline u32 sh_mmcif_readl(void __iomem *addr, int reg)
 {
        return readl(addr + reg);
 }
 
-extern inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val)
+static inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val)
 {
        writel(val, addr + reg);
 }
 
 #define SH_MMCIF_BBS 512 /* boot block size */
 
-extern inline void sh_mmcif_boot_cmd_send(void __iomem *base,
+static inline void sh_mmcif_boot_cmd_send(void __iomem *base,
                                          unsigned long cmd, unsigned long arg)
 {
        sh_mmcif_writel(base, MMCIF_CE_INT, 0);
@@ -79,7 +79,7 @@ extern inline void sh_mmcif_boot_cmd_send(void __iomem *base,
        sh_mmcif_writel(base, MMCIF_CE_CMD_SET, cmd);
 }
 
-extern inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask)
+static inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask)
 {
        unsigned long tmp;
        int cnt;
@@ -95,14 +95,14 @@ extern inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask)
        return -1;
 }
 
-extern inline int sh_mmcif_boot_cmd(void __iomem *base,
+static inline int sh_mmcif_boot_cmd(void __iomem *base,
                                    unsigned long cmd, unsigned long arg)
 {
        sh_mmcif_boot_cmd_send(base, cmd, arg);
        return sh_mmcif_boot_cmd_poll(base, 0x00010000);
 }
 
-extern inline int sh_mmcif_boot_do_read_single(void __iomem *base,
+static inline int sh_mmcif_boot_do_read_single(void __iomem *base,
                                               unsigned int block_nr,
                                               unsigned long *buf)
 {
@@ -125,7 +125,7 @@ extern inline int sh_mmcif_boot_do_read_single(void __iomem *base,
        return 0;
 }
 
-extern inline int sh_mmcif_boot_do_read(void __iomem *base,
+static inline int sh_mmcif_boot_do_read(void __iomem *base,
                                        unsigned long first_block,
                                        unsigned long nr_blocks,
                                        void *buf)
@@ -143,7 +143,7 @@ extern inline int sh_mmcif_boot_do_read(void __iomem *base,
        return ret;
 }
 
-extern inline void sh_mmcif_boot_init(void __iomem *base)
+static inline void sh_mmcif_boot_init(void __iomem *base)
 {
        unsigned long tmp;
 
@@ -177,7 +177,7 @@ extern inline void sh_mmcif_boot_init(void __iomem *base)
        sh_mmcif_boot_cmd(base, 0x03400040, 0x00010000);
 }
 
-extern inline void sh_mmcif_boot_slurp(void __iomem *base,
+static inline void sh_mmcif_boot_slurp(void __iomem *base,
                                       unsigned char *buf,
                                       unsigned long no_bytes)
 {
index 01b3d75..e031e1a 100644 (file)
@@ -8,6 +8,7 @@ struct platform_pwm_backlight_data {
        int pwm_id;
        unsigned int max_brightness;
        unsigned int dft_brightness;
+       unsigned int lth_brightness;
        unsigned int pwm_period_ns;
        int (*init)(struct device *dev);
        int (*notify)(struct device *dev, int brightness);
index a39cbed..ab2baa5 100644 (file)
  * needed for RCU lookups (because root->height is unreliable). The only
  * time callers need worry about this is when doing a lookup_slot under
  * RCU.
+ *
+ * Indirect pointer in fact is also used to tag the last pointer of a node
+ * when it is shrunk, before we rcu free the node. See shrink code for
+ * details.
  */
 #define RADIX_TREE_INDIRECT_PTR        1
-#define RADIX_TREE_RETRY ((void *)-1UL)
-
-static inline void *radix_tree_ptr_to_indirect(void *ptr)
-{
-       return (void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR);
-}
 
-static inline void *radix_tree_indirect_to_ptr(void *ptr)
-{
-       return (void *)((unsigned long)ptr & ~RADIX_TREE_INDIRECT_PTR);
-}
 #define radix_tree_indirect_to_ptr(ptr) \
        radix_tree_indirect_to_ptr((void __force *)(ptr))
 
@@ -140,16 +134,29 @@ do {                                                                      \
  *             removed.
  *
  * For use with radix_tree_lookup_slot().  Caller must hold tree at least read
- * locked across slot lookup and dereference.  More likely, will be used with
- * radix_tree_replace_slot(), as well, so caller will hold tree write locked.
+ * locked across slot lookup and dereference. Not required if write lock is
+ * held (ie. items cannot be concurrently inserted).
+ *
+ * radix_tree_deref_retry must be used to confirm validity of the pointer if
+ * only the read lock is held.
  */
 static inline void *radix_tree_deref_slot(void **pslot)
 {
-       void *ret = rcu_dereference(*pslot);
-       if (unlikely(radix_tree_is_indirect_ptr(ret)))
-               ret = RADIX_TREE_RETRY;
-       return ret;
+       return rcu_dereference(*pslot);
 }
+
+/**
+ * radix_tree_deref_retry      - check radix_tree_deref_slot
+ * @arg:       pointer returned by radix_tree_deref_slot
+ * Returns:    0 if retry is not required, otherwise retry is required
+ *
+ * radix_tree_deref_retry must be used with radix_tree_deref_slot.
+ */
+static inline int radix_tree_deref_retry(void *arg)
+{
+       return unlikely((unsigned long)arg & RADIX_TREE_INDIRECT_PTR);
+}
+
 /**
  * radix_tree_replace_slot     - replace item in a slot
  * @pslot:     pointer to slot, returned by radix_tree_lookup_slot
index 88d36f9..d01c96c 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_RESOURCE_H
 
 #include <linux/time.h>
+#include <linux/types.h>
 
 /*
  * Resource control/accounting header file for linux
index 4dca992..cea0c38 100644 (file)
@@ -122,6 +122,10 @@ int clk_rate_table_find(struct clk *clk,
 long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
                              unsigned int div_max, unsigned long rate);
 
+long clk_round_parent(struct clk *clk, unsigned long target,
+                     unsigned long *best_freq, unsigned long *parent_freq,
+                     unsigned int div_min, unsigned int div_max);
+
 #define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags)       \
 {                                                                      \
        .parent         = _parent,                                      \
index 864bd56..4d9dcd1 100644 (file)
@@ -5,7 +5,6 @@ struct sh_timer_config {
        char *name;
        long channel_offset;
        int timer_bit;
-       char *clk;
        unsigned long clockevent_rating;
        unsigned long clocksource_rating;
 };
index 6da573c..8eff83b 100644 (file)
@@ -28,7 +28,7 @@ struct caif_param {
  * @sockaddr:          Socket address to connect.
  * @priority:          Priority of the connection.
  * @link_selector:     Link selector (high bandwidth or low latency)
- * @link_name:         Name of the CAIF Link Layer to use.
+ * @ifindex:           kernel index of the interface.
  * @param:             Connect Request parameters (CAIF_SO_REQ_PARAM).
  *
  * This struct is used when connecting a CAIF channel.
@@ -39,7 +39,7 @@ struct caif_connect_request {
        struct sockaddr_caif sockaddr;
        enum caif_channel_priority priority;
        enum caif_link_selector link_selector;
-       char link_name[16];
+       int ifindex;
        struct caif_param param;
 };
 
index ce4570d..87c3d11 100644 (file)
@@ -121,6 +121,8 @@ struct cfspi {
        wait_queue_head_t wait;
        spinlock_t lock;
        bool flow_stop;
+       bool slave;
+       bool slave_talked;
 #ifdef CONFIG_DEBUG_FS
        enum cfspi_state dbg_state;
        u16 pcmd;
index bd646fa..f688478 100644 (file)
@@ -139,10 +139,10 @@ struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
                     enum cfcnfg_phy_preference phy_pref);
 
 /**
- * cfcnfg_get_named() - Get the Physical Identifier of CAIF Link Layer
+ * cfcnfg_get_id_from_ifi() - Get the Physical Identifier of ifindex,
+ *                     it matches caif physical id with the kernel interface id.
  * @cnfg:      Configuration object
- * @name:      Name of the Physical Layer (Caif Link Layer)
+ * @ifi:       ifindex obtained from socket.c bindtodevice.
  */
-int cfcnfg_get_named(struct cfcnfg *cnfg, char *name);
-
+int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi);
 #endif                         /* CFCNFG_H_ */
index f3b201d..9801c55 100644 (file)
@@ -384,7 +384,7 @@ static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen,
  *
  * Returns the first attribute which matches the specified type.
  */
-static inline struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh,
+static inline struct nlattr *nlmsg_find_attr(const struct nlmsghdr *nlh,
                                             int hdrlen, int attrtype)
 {
        return nla_find(nlmsg_attrdata(nlh, hdrlen),
index 289010d..e5e345f 100644 (file)
@@ -98,6 +98,103 @@ TRACE_EVENT(ext4_allocate_inode,
                  (unsigned long) __entry->dir, __entry->mode)
 );
 
+TRACE_EVENT(ext4_evict_inode,
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode),
+
+       TP_STRUCT__entry(
+               __field(        int,   dev_major                )
+               __field(        int,   dev_minor                )
+               __field(        ino_t,  ino                     )
+               __field(        int,    nlink                   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->nlink  = inode->i_nlink;
+       ),
+
+       TP_printk("dev %d,%d ino %lu nlink %d",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, __entry->nlink)
+);
+
+TRACE_EVENT(ext4_drop_inode,
+       TP_PROTO(struct inode *inode, int drop),
+
+       TP_ARGS(inode, drop),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(        int,    drop                    )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->drop   = drop;
+       ),
+
+       TP_printk("dev %d,%d ino %lu drop %d",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, __entry->drop)
+);
+
+TRACE_EVENT(ext4_mark_inode_dirty,
+       TP_PROTO(struct inode *inode, unsigned long IP),
+
+       TP_ARGS(inode, IP),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(unsigned long,  ip                      )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->ip     = IP;
+       ),
+
+       TP_printk("dev %d,%d ino %lu caller %pF",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, (void *)__entry->ip)
+);
+
+TRACE_EVENT(ext4_begin_ordered_truncate,
+       TP_PROTO(struct inode *inode, loff_t new_size),
+
+       TP_ARGS(inode, new_size),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(        loff_t, new_size                )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major      = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor      = MINOR(inode->i_sb->s_dev);
+               __entry->ino            = inode->i_ino;
+               __entry->new_size       = new_size;
+       ),
+
+       TP_printk("dev %d,%d ino %lu new_size %lld",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino,
+                 (long long) __entry->new_size)
+);
+
 DECLARE_EVENT_CLASS(ext4__write_begin,
 
        TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
index b194feb..21aa7b3 100644 (file)
@@ -95,6 +95,14 @@ static void __exit_signal(struct task_struct *tsk)
                tty = sig->tty;
                sig->tty = NULL;
        } else {
+               /*
+                * This can only happen if the caller is de_thread().
+                * FIXME: this is the temporary hack, we should teach
+                * posix-cpu-timers to handle this case correctly.
+                */
+               if (unlikely(has_group_leader_pid(tsk)))
+                       posix_cpu_timers_exit_group(tsk);
+
                /*
                 * If there is any task waiting for the group exit
                 * then notify it:
index 877fb30..17110a4 100644 (file)
@@ -194,14 +194,7 @@ __account_scheduler_latency(struct task_struct *tsk, int usecs, int inter)
 
        account_global_scheduler_latency(tsk, &lat);
 
-       /*
-        * short term hack; if we're > 32 we stop; future we recycle:
-        */
-       tsk->latency_record_count++;
-       if (tsk->latency_record_count >= LT_SAVECOUNT)
-               goto out_unlock;
-
-       for (i = 0; i < LT_SAVECOUNT; i++) {
+       for (i = 0; i < tsk->latency_record_count; i++) {
                struct latency_record *mylat;
                int same = 1;
 
@@ -227,8 +220,14 @@ __account_scheduler_latency(struct task_struct *tsk, int usecs, int inter)
                }
        }
 
+       /*
+        * short term hack; if we're > 32 we stop; future we recycle:
+        */
+       if (tsk->latency_record_count >= LT_SAVECOUNT)
+               goto out_unlock;
+
        /* Allocated a new one: */
-       i = tsk->latency_record_count;
+       i = tsk->latency_record_count++;
        memcpy(&tsk->latency_record[i], &lat, sizeof(struct latency_record));
 
 out_unlock:
index b2ebaee..38e7d58 100644 (file)
@@ -261,6 +261,12 @@ static inline void boot_delay_msec(void)
 }
 #endif
 
+#ifdef CONFIG_SECURITY_DMESG_RESTRICT
+int dmesg_restrict = 1;
+#else
+int dmesg_restrict;
+#endif
+
 int do_syslog(int type, char __user *buf, int len, bool from_file)
 {
        unsigned i, j, limit, count;
index 471b66a..37fa9b9 100644 (file)
@@ -119,7 +119,7 @@ static int cmp_range(const void *x1, const void *x2)
 
 int clean_sort_range(struct range *range, int az)
 {
-       int i, j, k = az - 1, nr_range = 0;
+       int i, j, k = az - 1, nr_range = az;
 
        for (i = 0; i < k; i++) {
                if (range[i].end)
index c7cf397..859ea5a 100644 (file)
@@ -70,17 +70,10 @@ static const struct vm_operations_struct relay_file_mmap_ops = {
  */
 static struct page **relay_alloc_page_array(unsigned int n_pages)
 {
-       struct page **array;
-       size_t pa_size = n_pages * sizeof(struct page *);
-
-       if (pa_size > PAGE_SIZE) {
-               array = vmalloc(pa_size);
-               if (array)
-                       memset(array, 0, pa_size);
-       } else {
-               array = kzalloc(pa_size, GFP_KERNEL);
-       }
-       return array;
+       const size_t pa_size = n_pages * sizeof(struct page *);
+       if (pa_size > PAGE_SIZE)
+               return vzalloc(pa_size);
+       return kzalloc(pa_size, GFP_KERNEL);
 }
 
 /*
index c33a1ed..b65bf63 100644 (file)
@@ -703,6 +703,15 @@ static struct ctl_table kern_table[] = {
                .extra2         = &ten_thousand,
        },
 #endif
+       {
+               .procname       = "dmesg_restrict",
+               .data           = &dmesg_restrict,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &one,
+       },
        {
                .procname       = "ngroups_max",
                .data           = &ngroups_max,
index bafba68..6e3c41a 100644 (file)
@@ -43,7 +43,7 @@ static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
 static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
 #endif
 
-static int __initdata no_watchdog;
+static int no_watchdog;
 
 
 /* boot commands */
index 6f412ab..5086bb9 100644 (file)
@@ -82,6 +82,16 @@ struct radix_tree_preload {
 };
 static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
 
+static inline void *ptr_to_indirect(void *ptr)
+{
+       return (void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR);
+}
+
+static inline void *indirect_to_ptr(void *ptr)
+{
+       return (void *)((unsigned long)ptr & ~RADIX_TREE_INDIRECT_PTR);
+}
+
 static inline gfp_t root_gfp_mask(struct radix_tree_root *root)
 {
        return root->gfp_mask & __GFP_BITS_MASK;
@@ -265,7 +275,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
                        return -ENOMEM;
 
                /* Increase the height.  */
-               node->slots[0] = radix_tree_indirect_to_ptr(root->rnode);
+               node->slots[0] = indirect_to_ptr(root->rnode);
 
                /* Propagate the aggregated tag info into the new root */
                for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) {
@@ -276,7 +286,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
                newheight = root->height+1;
                node->height = newheight;
                node->count = 1;
-               node = radix_tree_ptr_to_indirect(node);
+               node = ptr_to_indirect(node);
                rcu_assign_pointer(root->rnode, node);
                root->height = newheight;
        } while (height > root->height);
@@ -309,7 +319,7 @@ int radix_tree_insert(struct radix_tree_root *root,
                        return error;
        }
 
-       slot = radix_tree_indirect_to_ptr(root->rnode);
+       slot = indirect_to_ptr(root->rnode);
 
        height = root->height;
        shift = (height-1) * RADIX_TREE_MAP_SHIFT;
@@ -325,8 +335,7 @@ int radix_tree_insert(struct radix_tree_root *root,
                                rcu_assign_pointer(node->slots[offset], slot);
                                node->count++;
                        } else
-                               rcu_assign_pointer(root->rnode,
-                                       radix_tree_ptr_to_indirect(slot));
+                               rcu_assign_pointer(root->rnode, ptr_to_indirect(slot));
                }
 
                /* Go a level down */
@@ -374,7 +383,7 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root,
                        return NULL;
                return is_slot ? (void *)&root->rnode : node;
        }
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        height = node->height;
        if (index > radix_tree_maxindex(height))
@@ -393,7 +402,7 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root,
                height--;
        } while (height > 0);
 
-       return is_slot ? (void *)slot:node;
+       return is_slot ? (void *)slot : indirect_to_ptr(node);
 }
 
 /**
@@ -455,7 +464,7 @@ void *radix_tree_tag_set(struct radix_tree_root *root,
        height = root->height;
        BUG_ON(index > radix_tree_maxindex(height));
 
-       slot = radix_tree_indirect_to_ptr(root->rnode);
+       slot = indirect_to_ptr(root->rnode);
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
 
        while (height > 0) {
@@ -509,7 +518,7 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
 
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
        pathp->node = NULL;
-       slot = radix_tree_indirect_to_ptr(root->rnode);
+       slot = indirect_to_ptr(root->rnode);
 
        while (height > 0) {
                int offset;
@@ -579,7 +588,7 @@ int radix_tree_tag_get(struct radix_tree_root *root,
 
        if (!radix_tree_is_indirect_ptr(node))
                return (index == 0);
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        height = node->height;
        if (index > radix_tree_maxindex(height))
@@ -666,7 +675,7 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
        }
 
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
-       slot = radix_tree_indirect_to_ptr(root->rnode);
+       slot = indirect_to_ptr(root->rnode);
 
        /*
         * we fill the path from (root->height - 2) to 0, leaving the index at
@@ -897,7 +906,7 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
                results[0] = node;
                return 1;
        }
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        max_index = radix_tree_maxindex(node->height);
 
@@ -916,7 +925,8 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
                        slot = *(((void ***)results)[ret + i]);
                        if (!slot)
                                continue;
-                       results[ret + nr_found] = rcu_dereference_raw(slot);
+                       results[ret + nr_found] =
+                               indirect_to_ptr(rcu_dereference_raw(slot));
                        nr_found++;
                }
                ret += nr_found;
@@ -965,7 +975,7 @@ radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results,
                results[0] = (void **)&root->rnode;
                return 1;
        }
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        max_index = radix_tree_maxindex(node->height);
 
@@ -1090,7 +1100,7 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
                results[0] = node;
                return 1;
        }
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        max_index = radix_tree_maxindex(node->height);
 
@@ -1109,7 +1119,8 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
                        slot = *(((void ***)results)[ret + i]);
                        if (!slot)
                                continue;
-                       results[ret + nr_found] = rcu_dereference_raw(slot);
+                       results[ret + nr_found] =
+                               indirect_to_ptr(rcu_dereference_raw(slot));
                        nr_found++;
                }
                ret += nr_found;
@@ -1159,7 +1170,7 @@ radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results,
                results[0] = (void **)&root->rnode;
                return 1;
        }
-       node = radix_tree_indirect_to_ptr(node);
+       node = indirect_to_ptr(node);
 
        max_index = radix_tree_maxindex(node->height);
 
@@ -1195,7 +1206,7 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
                void *newptr;
 
                BUG_ON(!radix_tree_is_indirect_ptr(to_free));
-               to_free = radix_tree_indirect_to_ptr(to_free);
+               to_free = indirect_to_ptr(to_free);
 
                /*
                 * The candidate node has more than one child, or its child
@@ -1208,16 +1219,39 @@ static inline void radix_tree_shrink(struct radix_tree_root *root)
 
                /*
                 * We don't need rcu_assign_pointer(), since we are simply
-                * moving the node from one part of the tree to another. If
-                * it was safe to dereference the old pointer to it
+                * moving the node from one part of the tree to another: if it
+                * was safe to dereference the old pointer to it
                 * (to_free->slots[0]), it will be safe to dereference the new
-                * one (root->rnode).
+                * one (root->rnode) as far as dependent read barriers go.
                 */
                newptr = to_free->slots[0];
                if (root->height > 1)
-                       newptr = radix_tree_ptr_to_indirect(newptr);
+                       newptr = ptr_to_indirect(newptr);
                root->rnode = newptr;
                root->height--;
+
+               /*
+                * We have a dilemma here. The node's slot[0] must not be
+                * NULLed in case there are concurrent lookups expecting to
+                * find the item. However if this was a bottom-level node,
+                * then it may be subject to the slot pointer being visible
+                * to callers dereferencing it. If item corresponding to
+                * slot[0] is subsequently deleted, these callers would expect
+                * their slot to become empty sooner or later.
+                *
+                * For example, lockless pagecache will look up a slot, deref
+                * the page pointer, and if the page is 0 refcount it means it
+                * was concurrently deleted from pagecache so try the deref
+                * again. Fortunately there is already a requirement for logic
+                * to retry the entire slot lookup -- the indirect pointer
+                * problem (replacing direct root node with an indirect pointer
+                * also results in a stale slot). So tag the slot as indirect
+                * to force callers to retry.
+                */
+               if (root->height == 0)
+                       *((unsigned long *)&to_free->slots[0]) |=
+                                               RADIX_TREE_INDIRECT_PTR;
+
                radix_tree_node_free(to_free);
        }
 }
@@ -1254,7 +1288,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
                root->rnode = NULL;
                goto out;
        }
-       slot = radix_tree_indirect_to_ptr(slot);
+       slot = indirect_to_ptr(slot);
 
        shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
        pathp->node = NULL;
@@ -1296,8 +1330,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
                        radix_tree_node_free(to_free);
 
                if (pathp->node->count) {
-                       if (pathp->node ==
-                                       radix_tree_indirect_to_ptr(root->rnode))
+                       if (pathp->node == indirect_to_ptr(root->rnode))
                                radix_tree_shrink(root);
                        goto out;
                }
index 75572b5..ea89840 100644 (file)
@@ -644,7 +644,9 @@ repeat:
        pagep = radix_tree_lookup_slot(&mapping->page_tree, offset);
        if (pagep) {
                page = radix_tree_deref_slot(pagep);
-               if (unlikely(!page || page == RADIX_TREE_RETRY))
+               if (unlikely(!page))
+                       goto out;
+               if (radix_tree_deref_retry(page))
                        goto repeat;
 
                if (!page_cache_get_speculative(page))
@@ -660,6 +662,7 @@ repeat:
                        goto repeat;
                }
        }
+out:
        rcu_read_unlock();
 
        return page;
@@ -777,12 +780,11 @@ repeat:
                page = radix_tree_deref_slot((void **)pages[i]);
                if (unlikely(!page))
                        continue;
-               /*
-                * this can only trigger if nr_found == 1, making livelock
-                * a non issue.
-                */
-               if (unlikely(page == RADIX_TREE_RETRY))
+               if (radix_tree_deref_retry(page)) {
+                       if (ret)
+                               start = pages[ret-1]->index;
                        goto restart;
+               }
 
                if (!page_cache_get_speculative(page))
                        goto repeat;
@@ -830,11 +832,7 @@ repeat:
                page = radix_tree_deref_slot((void **)pages[i]);
                if (unlikely(!page))
                        continue;
-               /*
-                * this can only trigger if nr_found == 1, making livelock
-                * a non issue.
-                */
-               if (unlikely(page == RADIX_TREE_RETRY))
+               if (radix_tree_deref_retry(page))
                        goto restart;
 
                if (page->mapping == NULL || page->index != index)
@@ -887,11 +885,7 @@ repeat:
                page = radix_tree_deref_slot((void **)pages[i]);
                if (unlikely(!page))
                        continue;
-               /*
-                * this can only trigger if nr_found == 1, making livelock
-                * a non issue.
-                */
-               if (unlikely(page == RADIX_TREE_RETRY))
+               if (radix_tree_deref_retry(page))
                        goto restart;
 
                if (!page_cache_get_speculative(page))
@@ -1029,6 +1023,9 @@ find_page:
                                goto page_not_up_to_date;
                        if (!trylock_page(page))
                                goto page_not_up_to_date;
+                       /* Did it get truncated before we got the lock? */
+                       if (!page->mapping)
+                               goto page_not_up_to_date_locked;
                        if (!mapping->a_ops->is_partially_uptodate(page,
                                                                desc, offset))
                                goto page_not_up_to_date_locked;
@@ -1563,8 +1560,10 @@ retry_find:
                        goto no_cached_page;
        }
 
-       if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags))
+       if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) {
+               page_cache_release(page);
                return ret | VM_FAULT_RETRY;
+       }
 
        /* Did it get truncated? */
        if (unlikely(page->mapping != mapping)) {
index 9a99cfa..2efa8ea 100644 (file)
@@ -4208,15 +4208,17 @@ static struct mem_cgroup *mem_cgroup_alloc(void)
 
        memset(mem, 0, size);
        mem->stat = alloc_percpu(struct mem_cgroup_stat_cpu);
-       if (!mem->stat) {
-               if (size < PAGE_SIZE)
-                       kfree(mem);
-               else
-                       vfree(mem);
-               mem = NULL;
-       }
+       if (!mem->stat)
+               goto out_free;
        spin_lock_init(&mem->pcp_counter_lock);
        return mem;
+
+out_free:
+       if (size < PAGE_SIZE)
+               kfree(mem);
+       else
+               vfree(mem);
+       return NULL;
 }
 
 /*
index 2d1bf7c..4c51338 100644 (file)
@@ -211,6 +211,7 @@ success:
        mmu_notifier_invalidate_range_end(mm, start, end);
        vm_stat_account(mm, oldflags, vma->vm_file, -nrpages);
        vm_stat_account(mm, newflags, vma->vm_file, nrpages);
+       perf_event_mmap(vma);
        return 0;
 
 fail:
@@ -299,7 +300,6 @@ SYSCALL_DEFINE3(mprotect, unsigned long, start, size_t, len,
                error = mprotect_fixup(vma, &prev, nstart, tmp, newflags);
                if (error)
                        goto out;
-               perf_event_mmap(vma);
                nstart = tmp;
 
                if (nstart < prev->vm_end)
index b8a6fdc..d31d7ce 100644 (file)
@@ -913,7 +913,7 @@ keep_lumpy:
         * back off and wait for congestion to clear because further reclaim
         * will encounter the same problem
         */
-       if (nr_dirty == nr_congested)
+       if (nr_dirty == nr_congested && nr_dirty != 0)
                zone_set_flag(zone, ZONE_CONGESTED);
 
        free_page_list(&free_pages);
index cd2e42b..42eac4d 100644 (file)
@@ -949,7 +949,7 @@ static void *vmstat_start(struct seq_file *m, loff_t *pos)
        v[PGPGIN] /= 2;         /* sectors -> kbytes */
        v[PGPGOUT] /= 2;
 #endif
-       return m->private + *pos;
+       return (unsigned long *)m->private + *pos;
 }
 
 static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos)
index 76ae683..d522d8c 100644 (file)
@@ -16,11 +16,18 @@ int connect_req_to_link_param(struct cfcnfg *cnfg,
 {
        struct dev_info *dev_info;
        enum cfcnfg_phy_preference pref;
+       int res;
+
        memset(l, 0, sizeof(*l));
-       l->priority = s->priority;
+       /* In caif protocol low value is high priority */
+       l->priority = CAIF_PRIO_MAX - s->priority + 1;
 
-       if (s->link_name[0] != '\0')
-               l->phyid = cfcnfg_get_named(cnfg, s->link_name);
+       if (s->ifindex != 0){
+               res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex);
+               if (res < 0)
+                       return res;
+               l->phyid = res;
+       }
        else {
                switch (s->link_selector) {
                case CAIF_LINK_HIGH_BANDW:
index b99369a..a42a408 100644 (file)
@@ -307,6 +307,8 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
 
        case NETDEV_UNREGISTER:
                caifd = caif_get(dev);
+               if (caifd == NULL)
+                       break;
                netdev_info(dev, "unregister\n");
                atomic_set(&caifd->state, what);
                caif_device_destroy(dev);
index 2eca2dd..1bf0cf5 100644 (file)
@@ -716,8 +716,7 @@ static int setsockopt(struct socket *sock,
 {
        struct sock *sk = sock->sk;
        struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
-       int prio, linksel;
-       struct ifreq ifreq;
+       int linksel;
 
        if (cf_sk->sk.sk_socket->state != SS_UNCONNECTED)
                return -ENOPROTOOPT;
@@ -735,33 +734,6 @@ static int setsockopt(struct socket *sock,
                release_sock(&cf_sk->sk);
                return 0;
 
-       case SO_PRIORITY:
-               if (lvl != SOL_SOCKET)
-                       goto bad_sol;
-               if (ol < sizeof(int))
-                       return -EINVAL;
-               if (copy_from_user(&prio, ov, sizeof(int)))
-                       return -EINVAL;
-               lock_sock(&(cf_sk->sk));
-               cf_sk->conn_req.priority = prio;
-               release_sock(&cf_sk->sk);
-               return 0;
-
-       case SO_BINDTODEVICE:
-               if (lvl != SOL_SOCKET)
-                       goto bad_sol;
-               if (ol < sizeof(struct ifreq))
-                       return -EINVAL;
-               if (copy_from_user(&ifreq, ov, sizeof(ifreq)))
-                       return -EFAULT;
-               lock_sock(&(cf_sk->sk));
-               strncpy(cf_sk->conn_req.link_name, ifreq.ifr_name,
-                       sizeof(cf_sk->conn_req.link_name));
-               cf_sk->conn_req.link_name
-                       [sizeof(cf_sk->conn_req.link_name)-1] = 0;
-               release_sock(&cf_sk->sk);
-               return 0;
-
        case CAIFSO_REQ_PARAM:
                if (lvl != SOL_CAIF)
                        goto bad_sol;
@@ -880,6 +852,18 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
        sock->state = SS_CONNECTING;
        sk->sk_state = CAIF_CONNECTING;
 
+       /* Check priority value comming from socket */
+       /* if priority value is out of range it will be ajusted */
+       if (cf_sk->sk.sk_priority > CAIF_PRIO_MAX)
+               cf_sk->conn_req.priority = CAIF_PRIO_MAX;
+       else if (cf_sk->sk.sk_priority < CAIF_PRIO_MIN)
+               cf_sk->conn_req.priority = CAIF_PRIO_MIN;
+       else
+               cf_sk->conn_req.priority = cf_sk->sk.sk_priority;
+
+       /*ifindex = id of the interface.*/
+       cf_sk->conn_req.ifindex = cf_sk->sk.sk_bound_dev_if;
+
        dbfs_atomic_inc(&cnt.num_connect_req);
        cf_sk->layer.receive = caif_sktrecv_cb;
        err = caif_connect_client(&cf_sk->conn_req,
@@ -905,6 +889,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
        cf_sk->maxframe = mtu - (headroom + tailroom);
        if (cf_sk->maxframe < 1) {
                pr_warn("CAIF Interface MTU too small (%d)\n", dev->mtu);
+               err = -ENODEV;
                goto out;
        }
 
@@ -1142,7 +1127,7 @@ static int caif_create(struct net *net, struct socket *sock, int protocol,
        set_rx_flow_on(cf_sk);
 
        /* Set default options on configuration */
-       cf_sk->conn_req.priority = CAIF_PRIO_NORMAL;
+       cf_sk->sk.sk_priority= CAIF_PRIO_NORMAL;
        cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY;
        cf_sk->conn_req.protocol = protocol;
        /* Increase the number of sockets created. */
index 41adafd..21ede14 100644 (file)
@@ -173,18 +173,15 @@ static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg,
        return NULL;
 }
 
-int cfcnfg_get_named(struct cfcnfg *cnfg, char *name)
+
+int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
 {
        int i;
-
-       /* Try to match with specified name */
-       for (i = 0; i < MAX_PHY_LAYERS; i++) {
-               if (cnfg->phy_layers[i].frm_layer != NULL
-                   && strcmp(cnfg->phy_layers[i].phy_layer->name,
-                             name) == 0)
-                       return cnfg->phy_layers[i].frm_layer->id;
-       }
-       return 0;
+       for (i = 0; i < MAX_PHY_LAYERS; i++)
+               if (cnfg->phy_layers[i].frm_layer != NULL &&
+                               cnfg->phy_layers[i].ifindex == ifi)
+                       return i;
+       return -ENODEV;
 }
 
 int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
index 08f267a..3cd8f97 100644 (file)
@@ -361,11 +361,10 @@ void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
        struct cfctrl_request_info *p, *tmp;
        struct cfctrl *ctrl = container_obj(layr);
        spin_lock(&ctrl->info_list_lock);
-       pr_warn("enter\n");
 
        list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
                if (p->client_layer == adap_layer) {
-                       pr_warn("cancel req :%d\n", p->sequence_no);
+                       pr_debug("cancel req :%d\n", p->sequence_no);
                        list_del(&p->list);
                        kfree(p);
                }
index 496fda9..11a2af4 100644 (file)
@@ -12,6 +12,8 @@
 #include <net/caif/cfsrvl.h>
 #include <net/caif/cfpkt.h>
 
+#define container_obj(layr) ((struct cfsrvl *) layr)
+
 static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt);
 static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt);
 
@@ -38,5 +40,17 @@ static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt)
 
 static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt)
 {
+       struct cfsrvl *service = container_obj(layr);
+       struct caif_payload_info *info;
+       int ret;
+
+       if (!cfsrvl_ready(service, &ret))
+               return ret;
+
+       /* Add info for MUX-layer to route the packet out */
+       info = cfpkt_info(pkt);
+       info->channel_id = service->layer.id;
+       info->dev_info = &service->dev_info;
+
        return layr->dn->transmit(layr->dn, pkt);
 }
index bde8481..e2fb5fa 100644 (file)
@@ -193,7 +193,7 @@ out:
 
 static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt)
 {
-       caif_assert(cfpkt_getlen(pkt) >= rfml->fragment_size);
+       caif_assert(cfpkt_getlen(pkt) < rfml->fragment_size);
 
        /* Add info for MUX-layer to route the packet out. */
        cfpkt_info(pkt)->channel_id = rfml->serv.layer.id;
index 35dfb83..0dd54a6 100644 (file)
@@ -2131,7 +2131,7 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,
        } else {
                struct sock *sk = skb->sk;
                queue_index = sk_tx_queue_get(sk);
-               if (queue_index < 0) {
+               if (queue_index < 0 || queue_index >= dev->real_num_tx_queues) {
 
                        queue_index = 0;
                        if (dev->real_num_tx_queues > 1)
index a29edf2..c079cc0 100644 (file)
@@ -47,11 +47,8 @@ extern int fib_detect_death(struct fib_info *fi, int order,
 static inline void fib_result_assign(struct fib_result *res,
                                     struct fib_info *fi)
 {
-       if (res->fi != NULL)
-               fib_info_put(res->fi);
+       /* we used to play games with refcounts, but we now use RCU */
        res->fi = fi;
-       if (fi != NULL)
-               atomic_inc(&fi->fib_clntref);
 }
 
 #endif /* _FIB_LOOKUP_H */
index ba80426..2ada171 100644 (file)
@@ -490,9 +490,11 @@ static int inet_csk_diag_dump(struct sock *sk,
 {
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
                struct inet_diag_entry entry;
-               struct rtattr *bc = (struct rtattr *)(r + 1);
+               const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
+                                                         sizeof(*r),
+                                                         INET_DIAG_REQ_BYTECODE);
                struct inet_sock *inet = inet_sk(sk);
 
                entry.family = sk->sk_family;
@@ -512,7 +514,7 @@ static int inet_csk_diag_dump(struct sock *sk,
                entry.dport = ntohs(inet->inet_dport);
                entry.userlocks = sk->sk_userlocks;
 
-               if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
+               if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
                        return 0;
        }
 
@@ -527,9 +529,11 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
 {
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
                struct inet_diag_entry entry;
-               struct rtattr *bc = (struct rtattr *)(r + 1);
+               const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
+                                                         sizeof(*r),
+                                                         INET_DIAG_REQ_BYTECODE);
 
                entry.family = tw->tw_family;
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
@@ -548,7 +552,7 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
                entry.dport = ntohs(tw->tw_dport);
                entry.userlocks = 0;
 
-               if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
+               if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
                        return 0;
        }
 
@@ -618,7 +622,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct listen_sock *lopt;
-       struct rtattr *bc = NULL;
+       const struct nlattr *bc = NULL;
        struct inet_sock *inet = inet_sk(sk);
        int j, s_j;
        int reqnum, s_reqnum;
@@ -638,8 +642,9 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
        if (!lopt || !lopt->qlen)
                goto out;
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
-               bc = (struct rtattr *)(r + 1);
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
+               bc = nlmsg_find_attr(cb->nlh, sizeof(*r),
+                                    INET_DIAG_REQ_BYTECODE);
                entry.sport = inet->inet_num;
                entry.userlocks = sk->sk_userlocks;
        }
@@ -672,8 +677,8 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
                                        &ireq->rmt_addr;
                                entry.dport = ntohs(ireq->rmt_port);
 
-                               if (!inet_diag_bc_run(RTA_DATA(bc),
-                                                   RTA_PAYLOAD(bc), &entry))
+                               if (!inet_diag_bc_run(nla_data(bc),
+                                                     nla_len(bc), &entry))
                                        continue;
                        }
 
index 3cad259..3fac340 100644 (file)
@@ -927,6 +927,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index d31b007..a846d63 100644 (file)
@@ -1124,6 +1124,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index 295c974..c04787c 100644 (file)
@@ -47,26 +47,6 @@ __nf_nat_proto_find(u_int8_t protonum)
        return rcu_dereference(nf_nat_protos[protonum]);
 }
 
-static const struct nf_nat_protocol *
-nf_nat_proto_find_get(u_int8_t protonum)
-{
-       const struct nf_nat_protocol *p;
-
-       rcu_read_lock();
-       p = __nf_nat_proto_find(protonum);
-       if (!try_module_get(p->me))
-               p = &nf_nat_unknown_protocol;
-       rcu_read_unlock();
-
-       return p;
-}
-
-static void
-nf_nat_proto_put(const struct nf_nat_protocol *p)
-{
-       module_put(p->me);
-}
-
 /* We keep an extra hash for each conntrack, for fast searching. */
 static inline unsigned int
 hash_by_src(const struct net *net, u16 zone,
@@ -588,6 +568,26 @@ static struct nf_ct_ext_type nat_extend __read_mostly = {
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_conntrack.h>
 
+static const struct nf_nat_protocol *
+nf_nat_proto_find_get(u_int8_t protonum)
+{
+       const struct nf_nat_protocol *p;
+
+       rcu_read_lock();
+       p = __nf_nat_proto_find(protonum);
+       if (!try_module_get(p->me))
+               p = &nf_nat_unknown_protocol;
+       rcu_read_unlock();
+
+       return p;
+}
+
+static void
+nf_nat_proto_put(const struct nf_nat_protocol *p)
+{
+       module_put(p->me);
+}
+
 static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
        [CTA_PROTONAT_PORT_MIN] = { .type = NLA_U16 },
        [CTA_PROTONAT_PORT_MAX] = { .type = NLA_U16 },
index 51df035..4555823 100644 (file)
@@ -1137,6 +1137,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index 25661f9..fc32833 100644 (file)
@@ -2741,6 +2741,7 @@ static void __net_exit ip6_route_net_exit(struct net *net)
        kfree(net->ipv6.ip6_prohibit_entry);
        kfree(net->ipv6.ip6_blk_hole_entry);
 #endif
+       dst_entries_destroy(&net->ipv6.ip6_dst_ops);
 }
 
 static struct pernet_operations ip6_route_net_ops = {
@@ -2832,5 +2833,6 @@ void ip6_route_cleanup(void)
        xfrm6_fini();
        fib6_gc_cleanup();
        unregister_pernet_subsys(&ip6_route_net_ops);
+       dst_entries_destroy(&ip6_dst_blackhole_ops);
        kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
 }
index 104ec3b..b8dbae8 100644 (file)
@@ -249,7 +249,7 @@ static int l2tp_dfs_seq_open(struct inode *inode, struct file *file)
        struct seq_file *seq;
        int rc = -ENOMEM;
 
-       pd = kzalloc(GFP_KERNEL, sizeof(*pd));
+       pd = kzalloc(sizeof(*pd), GFP_KERNEL);
        if (pd == NULL)
                goto out;
 
index 1eacf8d..27a5ea6 100644 (file)
@@ -1312,7 +1312,8 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int nulls)
        if (!hash) {
                *vmalloced = 1;
                printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n");
-               hash = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+               hash = __vmalloc(sz, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
+                                PAGE_KERNEL);
        }
 
        if (hash && nulls)
index ed6d929..dc7bb74 100644 (file)
@@ -292,6 +292,12 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
 
                for (i = 0; i < MAX_NF_CT_PROTO; i++)
                        proto_array[i] = &nf_conntrack_l4proto_generic;
+
+               /* Before making proto_array visible to lockless readers,
+                * we must make sure its content is committed to memory.
+                */
+               smp_wmb();
+
                nf_ct_protos[l4proto->l3proto] = proto_array;
        } else if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] !=
                                        &nf_conntrack_l4proto_generic) {
index c390156..aeec1d4 100644 (file)
@@ -134,8 +134,12 @@ static int rds_loop_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 static void rds_loop_conn_free(void *arg)
 {
        struct rds_loop_connection *lc = arg;
+       unsigned long flags;
+
        rdsdebug("lc %p\n", lc);
+       spin_lock_irqsave(&loop_conns_lock, flags);
        list_del(&lc->loop_node);
+       spin_unlock_irqrestore(&loop_conns_lock, flags);
        kfree(lc);
 }
 
index 08a8c6c..8e0a320 100644 (file)
@@ -221,7 +221,13 @@ static int rds_tcp_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 static void rds_tcp_conn_free(void *arg)
 {
        struct rds_tcp_connection *tc = arg;
+       unsigned long flags;
        rdsdebug("freeing tc %p\n", tc);
+
+       spin_lock_irqsave(&rds_tcp_conn_lock, flags);
+       list_del(&tc->t_tcp_node);
+       spin_unlock_irqrestore(&rds_tcp_conn_lock, flags);
+
        kmem_cache_free(rds_tcp_conn_slab, tc);
 }
 
index 37dff78..d49c40f 100644 (file)
@@ -34,8 +34,6 @@ struct cgroup_subsys net_cls_subsys = {
        .populate       = cgrp_populate,
 #ifdef CONFIG_NET_CLS_CGROUP
        .subsys_id      = net_cls_subsys_id,
-#else
-#define net_cls_subsys_id net_cls_subsys.subsys_id
 #endif
        .module         = THIS_MODULE,
 };
index 7632532..ea8f566 100644 (file)
@@ -103,7 +103,8 @@ retry:
 
 static void em_text_destroy(struct tcf_proto *tp, struct tcf_ematch *m)
 {
-       textsearch_destroy(EM_TEXT_PRIV(m)->config);
+       if (EM_TEXT_PRIV(m) && EM_TEXT_PRIV(m)->config)
+               textsearch_destroy(EM_TEXT_PRIV(m)->config);
 }
 
 static int em_text_dump(struct sk_buff *skb, struct tcf_ematch *m)
index 771bab0..3a8c4c4 100644 (file)
@@ -134,15 +134,15 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                case X25_FAC_CLASS_D:
                        switch (*p) {
                        case X25_FAC_CALLING_AE:
-                               if (p[1] > X25_MAX_DTE_FACIL_LEN)
-                                       break;
+                               if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
+                                       return 0;
                                dte_facs->calling_len = p[2];
                                memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
                                *vc_fac_mask |= X25_MASK_CALLING_AE;
                                break;
                        case X25_FAC_CALLED_AE:
-                               if (p[1] > X25_MAX_DTE_FACIL_LEN)
-                                       break;
+                               if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
+                                       return 0;
                                dte_facs->called_len = p[2];
                                memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
                                *vc_fac_mask |= X25_MASK_CALLED_AE;
index 6317896..f729f02 100644 (file)
@@ -119,6 +119,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                                                &x25->vc_facil_mask);
                        if (len > 0)
                                skb_pull(skb, len);
+                       else
+                               return -1;
                        /*
                         *      Copy any Call User Data.
                         */
index c0efe10..af6e9f3 100644 (file)
@@ -875,7 +875,7 @@ const char *sym_expand_string_value(const char *in)
                        symval = sym_get_string_value(sym);
                }
 
-               newlen = strlen(res) + strlen(symval) + strlen(src);
+               newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
                if (newlen > reslen) {
                        reslen = newlen;
                        res = realloc(res, reslen);
index bd72ae6..e80da95 100644 (file)
@@ -39,6 +39,18 @@ config KEYS_DEBUG_PROC_KEYS
 
          If you are unsure as to whether this is required, answer N.
 
+config SECURITY_DMESG_RESTRICT
+       bool "Restrict unprivileged access to the kernel syslog"
+       default n
+       help
+         This enforces restrictions on unprivileged users reading the kernel
+         syslog via dmesg(8).
+
+         If this option is not selected, no restrictions will be enforced
+         unless the dmesg_restrict sysctl is explicitly set to (1).
+
+         If you are unsure how to answer this question, answer N.
+
 config SECURITY
        bool "Enable different security models"
        depends on SYSFS
index 5e632b4..04b80f9 100644 (file)
@@ -895,6 +895,8 @@ int cap_syslog(int type, bool from_file)
 {
        if (type != SYSLOG_ACTION_OPEN && from_file)
                return 0;
+       if (dmesg_restrict && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
        if ((type != SYSLOG_ACTION_READ_ALL &&
             type != SYSLOG_ACTION_SIZE_BUFFER) && !capable(CAP_SYS_ADMIN))
                return -EPERM;
index f7e374e..1b9bf93 100644 (file)
@@ -625,6 +625,8 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
                        control_cache_size, (struct hpi_control_cache_info *)
                        &phw->control_cache[0]
                        );
+               if (!phw->p_cache)
+                       pao->has_control_cache = 0;
        } else
                pao->has_control_cache = 0;
 
index 22c5fc6..2672f65 100644 (file)
@@ -644,6 +644,8 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
                                interface->control_cache.size_in_bytes,
                                (struct hpi_control_cache_info *)
                                p_control_cache_virtual);
+                       if (!phw->p_cache)
+                               err = HPI_ERROR_MEMORY_ALLOC;
                }
                if (!err) {
                        err = hpios_locked_mem_get_phys_addr(&phw->
index dda4f1c..d67f4d3 100644 (file)
@@ -571,14 +571,20 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32
 {
        struct hpi_control_cache *p_cache =
                kmalloc(sizeof(*p_cache), GFP_KERNEL);
+       if (!p_cache)
+               return NULL;
+       p_cache->p_info =
+               kmalloc(sizeof(*p_cache->p_info) * number_of_controls,
+                       GFP_KERNEL);
+       if (!p_cache->p_info) {
+               kfree(p_cache);
+               return NULL;
+       }
        p_cache->cache_size_in_bytes = size_in_bytes;
        p_cache->control_count = number_of_controls;
        p_cache->p_cache =
                (struct hpi_control_cache_single *)pDSP_control_buffer;
        p_cache->init = 0;
-       p_cache->p_info =
-               kmalloc(sizeof(*p_cache->p_info) * p_cache->control_count,
-               GFP_KERNEL);
        return p_cache;
 }
 
index 3e5ca8f..e377287 100644 (file)
@@ -225,39 +225,25 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
 {
        struct dsp_spos_instance * ins = kzalloc(sizeof(struct dsp_spos_instance), GFP_KERNEL);
 
-       if (ins == NULL) 
+       if (ins == NULL)
                return NULL;
 
        /* better to use vmalloc for this big table */
-       ins->symbol_table.nsymbols = 0;
        ins->symbol_table.symbols = vmalloc(sizeof(struct dsp_symbol_entry) *
                                            DSP_MAX_SYMBOLS);
-       ins->symbol_table.highest_frag_index = 0;
-
-       if (ins->symbol_table.symbols == NULL) {
+       ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
+       ins->modules = kmalloc(sizeof(struct dsp_module_desc) * DSP_MAX_MODULES, GFP_KERNEL);
+       if (!ins->symbol_table.symbols || !ins->code.data || !ins->modules) {
                cs46xx_dsp_spos_destroy(chip);
                goto error;
        }
-
+       ins->symbol_table.nsymbols = 0;
+       ins->symbol_table.highest_frag_index = 0;
        ins->code.offset = 0;
        ins->code.size = 0;
-       ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
-
-       if (ins->code.data == NULL) {
-               cs46xx_dsp_spos_destroy(chip);
-               goto error;
-       }
-
        ins->nscb = 0;
        ins->ntask = 0;
-
        ins->nmodules = 0;
-       ins->modules = kmalloc(sizeof(struct dsp_module_desc) * DSP_MAX_MODULES, GFP_KERNEL);
-
-       if (ins->modules == NULL) {
-               cs46xx_dsp_spos_destroy(chip);
-               goto error;
-       }
 
        /* default SPDIF input sample rate
           to 48000 khz */
@@ -271,8 +257,8 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
 
        /* set left and right validity bits and
           default channel status */
-       ins->spdif_csuv_default = 
-               ins->spdif_csuv_stream =  
+       ins->spdif_csuv_default =
+               ins->spdif_csuv_stream =
         /* byte 0 */  ((unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF        & 0xff)) << 24) |
         /* byte 1 */  ((unsigned int)_wrap_all_bits( ((SNDRV_PCM_DEFAULT_CON_SPDIF >> 8) & 0xff)) << 16) |
         /* byte 3 */   (unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF >> 24) & 0xff) |
@@ -281,6 +267,9 @@ struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip)
        return ins;
 
 error:
+       kfree(ins->modules);
+       kfree(ins->code.data);
+       vfree(ins->symbol_table.symbols);
        kfree(ins);
        return NULL;
 }
index 460fb2e..18af38e 100644 (file)
@@ -1166,6 +1166,7 @@ static const char *cs420x_models[CS420X_MODELS] = {
 
 static struct snd_pci_quirk cs420x_cfg_tbl[] = {
        SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
+       SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
        SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
        SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
        SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),
index ef9af3f..1bd7a54 100644 (file)
@@ -425,7 +425,7 @@ exit:
 static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
 {
        struct snd_pcm_substream *substream = lx_stream->stream;
-       const int is_capture = lx_stream->is_capture;
+       const unsigned int is_capture = lx_stream->is_capture;
 
        int err;
 
@@ -473,7 +473,7 @@ static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
 
 static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream)
 {
-       const int is_capture = lx_stream->is_capture;
+       const unsigned int is_capture = lx_stream->is_capture;
        int err;
 
        snd_printd(LXP "stopping: stopping stream\n");
index 51afc04..aea621e 100644 (file)
@@ -60,7 +60,7 @@ struct lx_stream {
        snd_pcm_uframes_t          frame_pos;
        enum lx_stream_status      status; /* free, open, running, draining
                                            * pause */
-       int                        is_capture:1;
+       unsigned int               is_capture:1;
 };
 
 
index 3086b75..617f98b 100644 (file)
@@ -1152,7 +1152,7 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
                                           struct lx_stream *lx_stream)
 {
        struct snd_pcm_substream *substream = lx_stream->stream;
-       int is_capture = lx_stream->is_capture;
+       const unsigned int is_capture = lx_stream->is_capture;
        int err;
        unsigned long flags;
 
index 94a9d06..3b5690d 100644 (file)
@@ -25,8 +25,9 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
        select SND_SOC_CS42L51 if I2C
        select SND_SOC_CS4270 if I2C
+       select SND_SOC_CX20442
        select SND_SOC_DA7210 if I2C
-       select SND_SOC_JZ4740 if SOC_JZ4740
+       select SND_SOC_JZ4740_CODEC if SOC_JZ4740
        select SND_SOC_MAX98088 if I2C
        select SND_SOC_MAX9877 if I2C
        select SND_SOC_PCM3008
index d251ff5..c5ab8c8 100644 (file)
@@ -58,7 +58,7 @@
        (1000000000 / ((rate * 1000) / samples))
 
 #define US_TO_SAMPLES(rate, us) \
-       (rate / (1000000 / us))
+       (rate / (1000000 / (us < 1000000 ? us : 1000000)))
 
 #define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \
        ((samples * 5000) / ((burstrate * 5000) / (burstrate - playrate)))
@@ -200,7 +200,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
                      u8 *value)
 {
        struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
-       int val;
+       int val, ret = 0;
 
        *value = reg & 0xff;
 
@@ -210,6 +210,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
                if (val < 0) {
                        dev_err(codec->dev, "Read failed (%d)\n", val);
                        value[0] = dac33_read_reg_cache(codec, reg);
+                       ret = val;
                } else {
                        value[0] = val;
                        dac33_write_reg_cache(codec, reg, val);
@@ -218,7 +219,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
                value[0] = dac33_read_reg_cache(codec, reg);
        }
 
-       return 0;
+       return ret;
 }
 
 static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
@@ -329,13 +330,18 @@ static void dac33_init_chip(struct snd_soc_codec *codec)
                    dac33_read_reg_cache(codec, DAC33_LINER_TO_RLO_VOL));
 }
 
-static inline void dac33_read_id(struct snd_soc_codec *codec)
+static inline int dac33_read_id(struct snd_soc_codec *codec)
 {
+       int i, ret = 0;
        u8 reg;
 
-       dac33_read(codec, DAC33_DEVICE_ID_MSB, &reg);
-       dac33_read(codec, DAC33_DEVICE_ID_LSB, &reg);
-       dac33_read(codec, DAC33_DEVICE_REV_ID, &reg);
+       for (i = 0; i < 3; i++) {
+               ret = dac33_read(codec, DAC33_DEVICE_ID_MSB + i, &reg);
+               if (ret < 0)
+                       break;
+       }
+
+       return ret;
 }
 
 static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
@@ -1076,6 +1082,9 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
                /* Number of samples under i2c latency */
                dac33->alarm_threshold = US_TO_SAMPLES(rate,
                                                dac33->mode1_latency);
+               nsample_limit = DAC33_BUFFER_SIZE_SAMPLES -
+                               dac33->alarm_threshold;
+
                if (dac33->auto_fifo_config) {
                        if (period_size <= dac33->alarm_threshold)
                                /*
@@ -1086,6 +1095,8 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
                                       ((dac33->alarm_threshold / period_size) +
                                       (dac33->alarm_threshold % period_size ?
                                       1 : 0));
+                       else if (period_size > nsample_limit)
+                               dac33->nsample = nsample_limit;
                        else
                                dac33->nsample = period_size;
                } else {
@@ -1097,8 +1108,7 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
                         */
                        dac33->nsample_max = substream->runtime->buffer_size -
                                                period_size;
-                       nsample_limit = DAC33_BUFFER_SIZE_SAMPLES -
-                                       dac33->alarm_threshold;
+
                        if (dac33->nsample_max > nsample_limit)
                                dac33->nsample_max = nsample_limit;
 
@@ -1414,9 +1424,15 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
                dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
                goto err_power;
        }
-       dac33_read_id(codec);
+       ret = dac33_read_id(codec);
        dac33_hard_power(codec, 0);
 
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to read chip ID: %d\n", ret);
+               ret = -ENODEV;
+               goto err_power;
+       }
+
        /* Check if the IRQ number is valid and request it */
        if (dac33->irq >= 0) {
                ret = request_irq(dac33->irq, dac33_interrupt_handler,
index 329acc1..ee4fb20 100644 (file)
@@ -119,13 +119,13 @@ static int tpa6130a2_power(int power)
 {
        struct  tpa6130a2_data *data;
        u8      val;
-       int     ret;
+       int     ret = 0;
 
        BUG_ON(tpa6130a2_client == NULL);
        data = i2c_get_clientdata(tpa6130a2_client);
 
        mutex_lock(&data->mutex);
-       if (power) {
+       if (power && !data->power_state) {
                /* Power on */
                if (data->power_gpio >= 0)
                        gpio_set_value(data->power_gpio, 1);
@@ -153,7 +153,7 @@ static int tpa6130a2_power(int power)
                val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
                val &= ~TPA6130A2_SWS;
                tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
-       } else {
+       } else if (!power && data->power_state) {
                /* set SWS */
                val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
                val |= TPA6130A2_SWS;
index b4f1172..aca4b1e 100644 (file)
@@ -186,7 +186,6 @@ static int wm8900_volatile_register(unsigned int reg)
 {
        switch (reg) {
        case WM8900_REG_ID:
-       case WM8900_REG_POWER1:
                return 1;
        default:
                return 0;
@@ -1200,11 +1199,6 @@ static int wm8900_probe(struct snd_soc_codec *codec)
                return -ENODEV;
        }
 
-       /* Read back from the chip */
-       reg = snd_soc_read(codec, WM8900_REG_POWER1);
-       reg = (reg >> 12) & 0xf;
-       dev_info(codec->dev, "WM8900 revision %d\n", reg);
-
        wm8900_reset(codec);
 
        /* Turn the chip on */
index 2cb8153..19ca782 100644 (file)
@@ -123,7 +123,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                        reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
                        break;
                default:
-                       WARN(1, "Unknown DCS readback method");
+                       WARN(1, "Unknown DCS readback method\n");
                        break;
                }
 
index a3bfb2e..73d0edd 100644 (file)
@@ -79,7 +79,7 @@ static void tosa_ext_control(struct snd_soc_codec *codec)
 static int tosa_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_codec *codec = rtd->card->codec;
+       struct snd_soc_codec *codec = rtd->codec;
 
        /* check the jack status at stream startup */
        tosa_ext_control(codec);
index 1c8f3f5..614a8b3 100644 (file)
@@ -165,8 +165,11 @@ static ssize_t pmdown_time_set(struct device *dev,
 {
        struct snd_soc_pcm_runtime *rtd =
                        container_of(dev, struct snd_soc_pcm_runtime, dev);
+       int ret;
 
-       strict_strtol(buf, 10, &rtd->pmdown_time);
+       ret = strict_strtol(buf, 10, &rtd->pmdown_time);
+       if (ret)
+               return ret;
 
        return count;
 }
index 7dae05d..782f741 100644 (file)
@@ -60,7 +60,7 @@ static const struct rc_config {
        { USB_ID(0x041e, 0x3000), 0, 1, 2, 1,  18, 0x0013 }, /* Extigy       */
        { USB_ID(0x041e, 0x3020), 2, 1, 6, 6,  18, 0x0013 }, /* Audigy 2 NX  */
        { USB_ID(0x041e, 0x3040), 2, 2, 6, 6,  2,  0x6e91 }, /* Live! 24-bit */
-       { USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi */
+       { USB_ID(0x041e, 0x3042), 0, 1, 1, 1,  1,  0x000d }, /* Usb X-Fi S51 */
        { USB_ID(0x041e, 0x3048), 2, 2, 6, 6,  2,  0x6e91 }, /* Toshiba SB0500 */
 };
 
@@ -183,7 +183,13 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
        if (value > 1)
                return -EINVAL;
        changed = value != mixer->audigy2nx_leds[index];
-       err = snd_usb_ctl_msg(mixer->chip->dev,
+       if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042))
+               err = snd_usb_ctl_msg(mixer->chip->dev,
+                             usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+                             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+                             !value, 0, NULL, 0, 100);
+       else
+               err = snd_usb_ctl_msg(mixer->chip->dev,
                              usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
                              USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
                              value, index + 2, NULL, 0, 100);
@@ -225,8 +231,12 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
        int i, err;
 
        for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
+               /* USB X-Fi S51 doesn't have a CMSS LED */
+               if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0)
+                       continue;
                if (i > 1 && /* Live24ext has 2 LEDs only */
                        (mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+                        mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
                         mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
                        break; 
                err = snd_ctl_add(mixer->chip->card,
@@ -365,6 +375,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 
        if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) ||
            mixer->chip->usb_id == USB_ID(0x041e, 0x3040) ||
+           mixer->chip->usb_id == USB_ID(0x041e, 0x3042) ||
            mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) {
                if ((err = snd_audigy2nx_controls_create(mixer)) < 0)
                        return err;
index cff3a3c..4132522 100644 (file)
@@ -676,8 +676,10 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
        if (!needs_knot)
                return 0;
 
-       subs->rate_list.count = count;
        subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL);
+       if (!subs->rate_list.list)
+               return -ENOMEM;
+       subs->rate_list.count = count;
        subs->rate_list.mask = 0;
        count = 0;
        list_for_each_entry(fp, &subs->fmt_list, list) {