Merge branch 'pm-devfreq' into pm-for-linus
Rafael J. Wysocki [Fri, 7 Oct 2011 21:17:18 +0000 (23:17 +0200)]
* pm-devfreq:
  PM / devfreq: Add basic governors
  PM / devfreq: Add common sysfs interfaces
  PM: Introduce devfreq: generic DVFS framework with device-specific OPPs
  PM / OPP: Add OPP availability change notifier.

186 files changed:
Documentation/networking/ip-sysctl.txt
Documentation/networking/scaling.txt
Documentation/power/pm_qos_interface.txt
Documentation/power/runtime_pm.txt
Documentation/usb/power-management.txt
MAINTAINERS
Makefile
arch/arm/mach-msm/clock.c
arch/arm/mach-omap1/pm_bus.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/include/mach/common.h
arch/arm/mach-shmobile/include/mach/sh7372.h
arch/arm/mach-shmobile/pm-sh7372.c
arch/arm/mach-shmobile/pm_runtime.c
arch/arm/mach-shmobile/setup-sh7372.c
arch/arm/mach-shmobile/sleep-sh7372.S
arch/powerpc/platforms/powermac/pci.c
arch/s390/include/asm/elf.h
arch/s390/mm/pgtable.c
arch/sparc/include/asm/spitfire.h
arch/sparc/include/asm/xor_64.h
arch/sparc/kernel/cpu.c
arch/sparc/kernel/cpumap.c
arch/sparc/kernel/head_64.S
arch/sparc/kernel/process_32.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/setup_32.c
arch/sparc/kernel/setup_64.c
arch/sparc/mm/init_64.c
arch/x86/kernel/rtc.c
arch/x86/pci/acpi.c
arch/x86/platform/mrst/vrtc.c
block/blk-core.c
block/blk-sysfs.c
drivers/acpi/processor_idle.c
drivers/base/power/Makefile
drivers/base/power/clock_ops.c
drivers/base/power/common.c [new file with mode: 0644]
drivers/base/power/domain.c
drivers/base/power/main.c
drivers/base/power/power.h
drivers/base/power/qos.c [new file with mode: 0644]
drivers/base/power/runtime.c
drivers/bluetooth/btusb.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/governors/ladder.c
drivers/cpuidle/governors/menu.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cursor.c
drivers/gpu/drm/radeon/rv770.c
drivers/hid/hid-picolcd.c
drivers/hid/usbhid/hid-core.c
drivers/hwmon/coretemp.c
drivers/ide/ide-disk.c
drivers/infiniband/hw/cxgb3/iwch_cm.c
drivers/input/tablet/wacom_wac.c
drivers/md/dm-crypt.c
drivers/md/dm-flakey.c
drivers/md/dm-raid.c
drivers/md/dm-table.c
drivers/md/md.c
drivers/md/md.h
drivers/md/multipath.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/media/video/omap/omap_vout.c
drivers/media/video/omap3isp/ispccdc.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_entity.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-device.c
drivers/media/video/via-camera.c
drivers/mfd/jz4740-adc.c
drivers/misc/lis3lv02d/lis3lv02d.c
drivers/net/bnx2x/bnx2x_dcb.c
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bnx2x/bnx2x_reg.h
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/cxgb3/cxgb3_offload.c
drivers/net/cxgb3/l2t.c
drivers/net/cxgb3/l2t.h
drivers/net/cxgb4/cxgb4_main.c
drivers/net/e1000e/netdev.c
drivers/net/ibmveth.c
drivers/net/macvlan.c
drivers/net/pch_gbe/pch_gbe_main.c
drivers/net/phy/dp83640.c
drivers/net/usb/usbnet.c
drivers/net/wimax/i2400m/usb.c
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/iwlegacy/iwl-core.c
drivers/net/wireless/iwlegacy/iwl-hcmd.c
drivers/net/wireless/iwlegacy/iwl-tx.c
drivers/net/wireless/iwlegacy/iwl3945-base.c
drivers/net/wireless/iwlegacy/iwl4965-base.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/rtlwifi/usb.c
drivers/net/xen-netback/interface.c
drivers/pci/pci.c
drivers/pci/probe.c
drivers/s390/cio/cio.c
drivers/scsi/3w-9xxx.c
drivers/scsi/Makefile
drivers/scsi/aacraid/commsup.c
drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/qla2xxx/qla_os.c
drivers/spi/spi-topcliff-pch.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/core/driver.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/serial/sierra.c
drivers/usb/serial/usb_wwan.c
fs/btrfs/file.c
include/linux/device-mapper.h
include/linux/device.h
include/linux/irqdomain.h
include/linux/netdevice.h
include/linux/pci.h
include/linux/pm.h
include/linux/pm_clock.h [new file with mode: 0644]
include/linux/pm_domain.h
include/linux/pm_qos.h [new file with mode: 0644]
include/linux/pm_qos_params.h [deleted file]
include/linux/pm_runtime.h
include/linux/ptp_classify.h
include/linux/sched.h
include/sound/pcm.h
include/trace/events/rpm.h [new file with mode: 0644]
include/trace/events/writeback.h
init/main.c
kernel/Makefile
kernel/irq/irqdomain.c
kernel/posix-cpu-timers.c
kernel/power/Makefile
kernel/power/qos.c [moved from kernel/pm_qos_params.c with 71% similarity]
kernel/resource.c
kernel/sched.c
kernel/sched_rt.c
kernel/trace/Makefile
kernel/trace/rpm-traces.c [new file with mode: 0644]
net/batman-adv/soft-interface.c
net/bridge/br_device.c
net/can/bcm.c
net/ceph/ceph_common.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv6/ip6mr.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/scan.c
net/netfilter/ipvs/ip_vs_ctl.c
net/packet/af_packet.c
net/rds/iw_rdma.c
net/wireless/nl80211.c
net/xfrm/xfrm_policy.c
sound/core/pcm_native.c
sound/pci/hda/hda_intel.c
sound/soc/codecs/wm8753.c
sound/soc/omap/mcpdm.c
sound/soc/omap/mcpdm.h
sound/soc/pxa/zylonite.c
sound/usb/card.c
tools/perf/util/evsel.c

index 8154699..ca5cdcd 100644 (file)
@@ -1042,7 +1042,7 @@ conf/interface/*:
        The functional behaviour for certain settings is different
        depending on whether local forwarding is enabled or not.
 
-accept_ra - BOOLEAN
+accept_ra - INTEGER
        Accept Router Advertisements; autoconfigure using them.
 
        Possible values are:
@@ -1106,7 +1106,7 @@ dad_transmits - INTEGER
        The amount of Duplicate Address Detection probes to send.
        Default: 1
 
-forwarding - BOOLEAN
+forwarding - INTEGER
        Configure interface-specific Host/Router behaviour.
 
        Note: It is recommended to have the same setting on all
index 58fd741..fe67b5c 100644 (file)
@@ -27,7 +27,7 @@ applying a filter to each packet that assigns it to one of a small number
 of logical flows. Packets for each flow are steered to a separate receive
 queue, which in turn can be processed by separate CPUs. This mechanism is
 generally known as “Receive-side Scaling” (RSS). The goal of RSS and
-the other scaling techniques to increase performance uniformly.
+the other scaling techniques is to increase performance uniformly.
 Multi-queue distribution can also be used for traffic prioritization, but
 that is not the focus of these techniques.
 
@@ -186,10 +186,10 @@ are steered using plain RPS. Multiple table entries may point to the
 same CPU. Indeed, with many flows and few CPUs, it is very likely that
 a single application thread handles flows with many different flow hashes.
 
-rps_sock_table is a global flow table that contains the *desired* CPU for
-flows: the CPU that is currently processing the flow in userspace. Each
-table value is a CPU index that is updated during calls to recvmsg and
-sendmsg (specifically, inet_recvmsg(), inet_sendmsg(), inet_sendpage()
+rps_sock_flow_table is a global flow table that contains the *desired* CPU
+for flows: the CPU that is currently processing the flow in userspace.
+Each table value is a CPU index that is updated during calls to recvmsg
+and sendmsg (specifically, inet_recvmsg(), inet_sendmsg(), inet_sendpage()
 and tcp_splice_read()).
 
 When the scheduler moves a thread to a new CPU while it has outstanding
@@ -243,7 +243,7 @@ configured. The number of entries in the global flow table is set through:
 
 The number of entries in the per-queue flow table are set through:
 
- /sys/class/net/<dev>/queues/tx-<n>/rps_flow_cnt
+ /sys/class/net/<dev>/queues/rx-<n>/rps_flow_cnt
 
 == Suggested Configuration
 
index bfed898..17e130a 100644 (file)
@@ -4,14 +4,19 @@ This interface provides a kernel and user mode interface for registering
 performance expectations by drivers, subsystems and user space applications on
 one of the parameters.
 
-Currently we have {cpu_dma_latency, network_latency, network_throughput} as the
-initial set of pm_qos parameters.
+Two different PM QoS frameworks are available:
+1. PM QoS classes for cpu_dma_latency, network_latency, network_throughput.
+2. the per-device PM QoS framework provides the API to manage the per-device latency
+constraints.
 
 Each parameters have defined units:
  * latency: usec
  * timeout: usec
  * throughput: kbs (kilo bit / sec)
 
+
+1. PM QoS framework
+
 The infrastructure exposes multiple misc device nodes one per implemented
 parameter.  The set of parameters implement is defined by pm_qos_power_init()
 and pm_qos_params.h.  This is done because having the available parameters
@@ -23,14 +28,18 @@ an aggregated target value.  The aggregated target value is updated with
 changes to the request list or elements of the list.  Typically the
 aggregated target value is simply the max or min of the request values held
 in the parameter list elements.
+Note: the aggregated target value is implemented as an atomic variable so that
+reading the aggregated value does not require any locking mechanism.
+
 
 From kernel mode the use of this interface is simple:
 
-handle = pm_qos_add_request(param_class, target_value):
-Will insert an element into the list for that identified PM_QOS class with the
+void pm_qos_add_request(handle, param_class, target_value):
+Will insert an element into the list for that identified PM QoS class with the
 target value.  Upon change to this list the new target is recomputed and any
 registered notifiers are called only if the target value is now different.
-Clients of pm_qos need to save the returned handle.
+Clients of pm_qos need to save the returned handle for future use in other
+pm_qos API functions.
 
 void pm_qos_update_request(handle, new_target_value):
 Will update the list element pointed to by the handle with the new target value
@@ -42,6 +51,20 @@ Will remove the element.  After removal it will update the aggregate target and
 call the notification tree if the target was changed as a result of removing
 the request.
 
+int pm_qos_request(param_class):
+Returns the aggregated value for a given PM QoS class.
+
+int pm_qos_request_active(handle):
+Returns if the request is still active, i.e. it has not been removed from a
+PM QoS class constraints list.
+
+int pm_qos_add_notifier(param_class, notifier):
+Adds a notification callback function to the PM QoS class. The callback is
+called when the aggregated value for the PM QoS class is changed.
+
+int pm_qos_remove_notifier(int param_class, notifier):
+Removes the notification callback function for the PM QoS class.
+
 
 From user mode:
 Only processes can register a pm_qos request.  To provide for automatic
@@ -63,4 +86,63 @@ To remove the user mode request for a target value simply close the device
 node.
 
 
+2. PM QoS per-device latency framework
+
+For each device a list of performance requests is maintained along with
+an aggregated target value.  The aggregated target value is updated with
+changes to the request list or elements of the list.  Typically the
+aggregated target value is simply the max or min of the request values held
+in the parameter list elements.
+Note: the aggregated target value is implemented as an atomic variable so that
+reading the aggregated value does not require any locking mechanism.
+
+
+From kernel mode the use of this interface is the following:
+
+int dev_pm_qos_add_request(device, handle, value):
+Will insert an element into the list for that identified device with the
+target value.  Upon change to this list the new target is recomputed and any
+registered notifiers are called only if the target value is now different.
+Clients of dev_pm_qos need to save the handle for future use in other
+dev_pm_qos API functions.
+
+int dev_pm_qos_update_request(handle, new_value):
+Will update the list element pointed to by the handle with the new target value
+and recompute the new aggregated target, calling the notification trees if the
+target is changed.
+
+int dev_pm_qos_remove_request(handle):
+Will remove the element.  After removal it will update the aggregate target and
+call the notification trees if the target was changed as a result of removing
+the request.
+
+s32 dev_pm_qos_read_value(device):
+Returns the aggregated value for a given device's constraints list.
+
+
+Notification mechanisms:
+The per-device PM QoS framework has 2 different and distinct notification trees:
+a per-device notification tree and a global notification tree.
+
+int dev_pm_qos_add_notifier(device, notifier):
+Adds a notification callback function for the device.
+The callback is called when the aggregated value of the device constraints list
+is changed.
+
+int dev_pm_qos_remove_notifier(device, notifier):
+Removes the notification callback function for the device.
+
+int dev_pm_qos_add_global_notifier(notifier):
+Adds a notification callback function in the global notification tree of the
+framework.
+The callback is called when the aggregated value for any device is changed.
+
+int dev_pm_qos_remove_global_notifier(notifier):
+Removes the notification callback function from the global notification tree
+of the framework.
+
+
+From user mode:
+No API for user space access to the per-device latency constraints is provided
+yet - still under discussion.
 
index 6066e3a..1f05404 100644 (file)
@@ -477,12 +477,14 @@ pm_runtime_autosuspend_expiration()
 If pm_runtime_irq_safe() has been called for a device then the following helper
 functions may also be used in interrupt context:
 
+pm_runtime_idle()
 pm_runtime_suspend()
 pm_runtime_autosuspend()
 pm_runtime_resume()
 pm_runtime_get_sync()
 pm_runtime_put_sync()
 pm_runtime_put_sync_suspend()
+pm_runtime_put_sync_autosuspend()
 
 5. Runtime PM Initialization, Device Probing and Removal
 
index c9ffa9c..e8662a5 100644 (file)
@@ -439,10 +439,10 @@ cause autosuspends to fail with -EBUSY if the driver needs to use the
 device.
 
 External suspend calls should never be allowed to fail in this way,
-only autosuspend calls.  The driver can tell them apart by checking
-the PM_EVENT_AUTO bit in the message.event argument to the suspend
-method; this bit will be set for internal PM events (autosuspend) and
-clear for external PM events.
+only autosuspend calls.  The driver can tell them apart by applying
+the PMSG_IS_AUTO() macro to the message argument to the suspend
+method; it will return True for internal PM events (autosuspend) and
+False for external PM events.
 
 
        Mutual exclusion
index ae8820e..ace8f9c 100644 (file)
@@ -6374,7 +6374,6 @@ S:        Supported
 F:     arch/arm/mach-tegra
 
 TEHUTI ETHERNET DRIVER
-M:     Alexander Indenbaum <baum@tehutinetworks.net>
 M:     Andy Gospodarek <andy@greyhouse.net>
 L:     netdev@vger.kernel.org
 S:     Supported
index 73bb458..31f967c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 1
 SUBLEVEL = 0
-EXTRAVERSION = -rc8
+EXTRAVERSION = -rc9
 NAME = "Divemaster Edition"
 
 # *DOCUMENTATION*
index 22a5376..d9145df 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/list.h>
 #include <linux/err.h>
 #include <linux/spinlock.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/mutex.h>
 #include <linux/clk.h>
 #include <linux/string.h>
index 943072d..7868e75 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
 #include <linux/clk.h>
index 523f608..d6c8ae8 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/leds.h>
 #include <linux/input/sh_keysc.h>
 #include <linux/usb/r8a66597.h>
+#include <linux/pm_clock.h>
 
 #include <media/sh_mobile_ceu.h>
 #include <media/sh_mobile_csi2.h>
index 17c19dc..19f5d49 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
-#include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
 #include <linux/smsc911x.h>
 #include <linux/sh_intc.h>
 #include <linux/tca6416_keypad.h>
index 06aecb3..c0cdbf9 100644 (file)
@@ -35,8 +35,8 @@ extern void sh7372_add_standard_devices(void);
 extern void sh7372_clock_init(void);
 extern void sh7372_pinmux_init(void);
 extern void sh7372_pm_init(void);
-extern void sh7372_cpu_suspend(void);
-extern void sh7372_cpu_resume(void);
+extern void sh7372_resume_core_standby_a3sm(void);
+extern int sh7372_do_idle_a3sm(unsigned long unused);
 extern struct clk sh7372_extal1_clk;
 extern struct clk sh7372_extal2_clk;
 
index 24e63a8..efc984c 100644 (file)
@@ -498,9 +498,12 @@ extern struct sh7372_pm_domain sh7372_a3sg;
 extern void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd);
 extern void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
                                        struct platform_device *pdev);
+extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
+                                   struct sh7372_pm_domain *sh7372_sd);
 #else
 #define sh7372_init_pm_domain(pd) do { } while(0)
 #define sh7372_add_device_to_domain(pd, pdev) do { } while(0)
+#define sh7372_pm_add_subdomain(pd, sd) do { } while(0)
 #endif /* CONFIG_PM */
 
 #endif /* __ASM_SH7372_H__ */
index 933fb41..8e0944f 100644 (file)
 #include <linux/list.h>
 #include <linux/err.h>
 #include <linux/slab.h>
-#include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/bitrev.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/tlbflush.h>
+#include <asm/suspend.h>
 #include <mach/common.h>
 #include <mach/sh7372.h>
 
-#define SMFRAM 0xe6a70000
-#define SYSTBCR 0xe6150024
-#define SBAR 0xe6180020
-#define APARMBAREA 0xe6f10020
+/* DBG */
+#define DBGREG1 0xe6100020
+#define DBGREG9 0xe6100040
 
+/* CPGA */
+#define SYSTBCR 0xe6150024
+#define MSTPSR0 0xe6150030
+#define MSTPSR1 0xe6150038
+#define MSTPSR2 0xe6150040
+#define MSTPSR3 0xe6150048
+#define MSTPSR4 0xe615004c
+#define PLLC01STPCR 0xe61500c8
+
+/* SYSC */
 #define SPDCR 0xe6180008
 #define SWUCR 0xe6180014
+#define SBAR 0xe6180020
+#define WUPSMSK 0xe618002c
+#define WUPSMSK2 0xe6180048
 #define PSTR 0xe6180080
+#define WUPSFAC 0xe6180098
+#define IRQCR 0xe618022c
+#define IRQCR2 0xe6180238
+#define IRQCR3 0xe6180244
+#define IRQCR4 0xe6180248
+#define PDNSEL 0xe6180254
+
+/* INTC */
+#define ICR1A 0xe6900000
+#define ICR2A 0xe6900004
+#define ICR3A 0xe6900008
+#define ICR4A 0xe690000c
+#define INTMSK00A 0xe6900040
+#define INTMSK10A 0xe6900044
+#define INTMSK20A 0xe6900048
+#define INTMSK30A 0xe690004c
+
+/* MFIS */
+#define SMFRAM 0xe6a70000
+
+/* AP-System Core */
+#define APARMBAREA 0xe6f10020
 
 #define PSTR_RETRIES 100
 #define PSTR_DELAY_US 10
@@ -91,35 +128,6 @@ static int pd_power_up(struct generic_pm_domain *genpd)
        return ret;
 }
 
-static int pd_power_up_a3rv(struct generic_pm_domain *genpd)
-{
-       int ret = pd_power_up(genpd);
-
-       /* force A4LC on after A3RV has been requested on */
-       pm_genpd_poweron(&sh7372_a4lc.genpd);
-
-       return ret;
-}
-
-static int pd_power_down_a3rv(struct generic_pm_domain *genpd)
-{
-       int ret = pd_power_down(genpd);
-
-       /* try to power down A4LC after A3RV is requested off */
-       genpd_queue_power_off_work(&sh7372_a4lc.genpd);
-
-       return ret;
-}
-
-static int pd_power_down_a4lc(struct generic_pm_domain *genpd)
-{
-       /* only power down A4LC if A3RV is off */
-       if (!(__raw_readl(PSTR) & (1 << sh7372_a3rv.bit_shift)))
-               return pd_power_down(genpd);
-
-       return -EBUSY;
-}
-
 static bool pd_active_wakeup(struct device *dev)
 {
        return true;
@@ -132,18 +140,10 @@ void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd)
        pm_genpd_init(genpd, NULL, false);
        genpd->stop_device = pm_clk_suspend;
        genpd->start_device = pm_clk_resume;
+       genpd->dev_irq_safe = true;
        genpd->active_wakeup = pd_active_wakeup;
-
-       if (sh7372_pd == &sh7372_a4lc) {
-               genpd->power_off = pd_power_down_a4lc;
-               genpd->power_on = pd_power_up;
-       } else if (sh7372_pd == &sh7372_a3rv) {
-               genpd->power_off = pd_power_down_a3rv;
-               genpd->power_on = pd_power_up_a3rv;
-       } else {
-               genpd->power_off = pd_power_down;
-               genpd->power_on = pd_power_up;
-       }
+       genpd->power_off = pd_power_down;
+       genpd->power_on = pd_power_up;
        genpd->power_on(&sh7372_pd->genpd);
 }
 
@@ -152,11 +152,15 @@ void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
 {
        struct device *dev = &pdev->dev;
 
-       if (!dev->power.subsys_data) {
-               pm_clk_init(dev);
-               pm_clk_add(dev, NULL);
-       }
        pm_genpd_add_device(&sh7372_pd->genpd, dev);
+       if (pm_clk_no_clocks(dev))
+               pm_clk_add(dev, NULL);
+}
+
+void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
+                            struct sh7372_pm_domain *sh7372_sd)
+{
+       pm_genpd_add_subdomain(&sh7372_pd->genpd, &sh7372_sd->genpd);
 }
 
 struct sh7372_pm_domain sh7372_a4lc = {
@@ -185,33 +189,175 @@ struct sh7372_pm_domain sh7372_a3sg = {
 
 #endif /* CONFIG_PM */
 
+#if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
+static int sh7372_do_idle_core_standby(unsigned long unused)
+{
+       cpu_do_idle(); /* WFI when SYSTBCR == 0x10 -> Core Standby */
+       return 0;
+}
+
 static void sh7372_enter_core_standby(void)
 {
-       void __iomem *smfram = (void __iomem *)SMFRAM;
+       /* set reset vector, translate 4k */
+       __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR);
+       __raw_writel(0, APARMBAREA);
+
+       /* enter sleep mode with SYSTBCR to 0x10 */
+       __raw_writel(0x10, SYSTBCR);
+       cpu_suspend(0, sh7372_do_idle_core_standby);
+       __raw_writel(0, SYSTBCR);
+
+        /* disable reset vector translation */
+       __raw_writel(0, SBAR);
+}
+#endif
+
+#ifdef CONFIG_SUSPEND
+static void sh7372_enter_a3sm_common(int pllc0_on)
+{
+       /* set reset vector, translate 4k */
+       __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR);
+       __raw_writel(0, APARMBAREA);
+
+       if (pllc0_on)
+               __raw_writel(0, PLLC01STPCR);
+       else
+               __raw_writel(1 << 28, PLLC01STPCR);
+
+       __raw_writel(0, PDNSEL); /* power-down A3SM only, not A4S */
+       __raw_readl(WUPSFAC); /* read wakeup int. factor before sleep */
+       cpu_suspend(0, sh7372_do_idle_a3sm);
+       __raw_readl(WUPSFAC); /* read wakeup int. factor after wakeup */
+
+        /* disable reset vector translation */
+       __raw_writel(0, SBAR);
+}
 
-       __raw_writel(0, APARMBAREA); /* translate 4k */
-       __raw_writel(__pa(sh7372_cpu_resume), SBAR); /* set reset vector */
-       __raw_writel(0x10, SYSTBCR); /* enable core standby */
+static int sh7372_a3sm_valid(unsigned long *mskp, unsigned long *msk2p)
+{
+       unsigned long mstpsr0, mstpsr1, mstpsr2, mstpsr3, mstpsr4;
+       unsigned long msk, msk2;
 
-       __raw_writel(0, smfram + 0x3c); /* clear page table address */
+       /* check active clocks to determine potential wakeup sources */
 
-       sh7372_cpu_suspend();
-       cpu_init();
+       mstpsr0 = __raw_readl(MSTPSR0);
+       if ((mstpsr0 & 0x00000003) != 0x00000003) {
+               pr_debug("sh7372 mstpsr0 0x%08lx\n", mstpsr0);
+               return 0;
+       }
+
+       mstpsr1 = __raw_readl(MSTPSR1);
+       if ((mstpsr1 & 0xff079b7f) != 0xff079b7f) {
+               pr_debug("sh7372 mstpsr1 0x%08lx\n", mstpsr1);
+               return 0;
+       }
+
+       mstpsr2 = __raw_readl(MSTPSR2);
+       if ((mstpsr2 & 0x000741ff) != 0x000741ff) {
+               pr_debug("sh7372 mstpsr2 0x%08lx\n", mstpsr2);
+               return 0;
+       }
 
-       /* if page table address is non-NULL then we have been powered down */
-       if (__raw_readl(smfram + 0x3c)) {
-               __raw_writel(__raw_readl(smfram + 0x40),
-                            __va(__raw_readl(smfram + 0x3c)));
+       mstpsr3 = __raw_readl(MSTPSR3);
+       if ((mstpsr3 & 0x1a60f010) != 0x1a60f010) {
+               pr_debug("sh7372 mstpsr3 0x%08lx\n", mstpsr3);
+               return 0;
+       }
 
-               flush_tlb_all();
-               set_cr(__raw_readl(smfram + 0x38));
+       mstpsr4 = __raw_readl(MSTPSR4);
+       if ((mstpsr4 & 0x00008cf0) != 0x00008cf0) {
+               pr_debug("sh7372 mstpsr4 0x%08lx\n", mstpsr4);
+               return 0;
        }
 
-       __raw_writel(0, SYSTBCR); /* disable core standby */
-       __raw_writel(0, SBAR); /* disable reset vector translation */
+       msk = 0;
+       msk2 = 0;
+
+       /* make bitmaps of limited number of wakeup sources */
+
+       if ((mstpsr2 & (1 << 23)) == 0) /* SPU2 */
+               msk |= 1 << 31;
+
+       if ((mstpsr2 & (1 << 12)) == 0) /* MFI_MFIM */
+               msk |= 1 << 21;
+
+       if ((mstpsr4 & (1 << 3)) == 0) /* KEYSC */
+               msk |= 1 << 2;
+
+       if ((mstpsr1 & (1 << 24)) == 0) /* CMT0 */
+               msk |= 1 << 1;
+
+       if ((mstpsr3 & (1 << 29)) == 0) /* CMT1 */
+               msk |= 1 << 1;
+
+       if ((mstpsr4 & (1 << 0)) == 0) /* CMT2 */
+               msk |= 1 << 1;
+
+       if ((mstpsr2 & (1 << 13)) == 0) /* MFI_MFIS */
+               msk2 |= 1 << 17;
+
+       *mskp = msk;
+       *msk2p = msk2;
+
+       return 1;
 }
 
+static void sh7372_icr_to_irqcr(unsigned long icr, u16 *irqcr1p, u16 *irqcr2p)
+{
+       u16 tmp, irqcr1, irqcr2;
+       int k;
+
+       irqcr1 = 0;
+       irqcr2 = 0;
+
+       /* convert INTCA ICR register layout to SYSC IRQCR+IRQCR2 */
+       for (k = 0; k <= 7; k++) {
+               tmp = (icr >> ((7 - k) * 4)) & 0xf;
+               irqcr1 |= (tmp & 0x03) << (k * 2);
+               irqcr2 |= (tmp >> 2) << (k * 2);
+       }
+
+       *irqcr1p = irqcr1;
+       *irqcr2p = irqcr2;
+}
+
+static void sh7372_setup_a3sm(unsigned long msk, unsigned long msk2)
+{
+       u16 irqcrx_low, irqcrx_high, irqcry_low, irqcry_high;
+       unsigned long tmp;
+
+       /* read IRQ0A -> IRQ15A mask */
+       tmp = bitrev8(__raw_readb(INTMSK00A));
+       tmp |= bitrev8(__raw_readb(INTMSK10A)) << 8;
+
+       /* setup WUPSMSK from clocks and external IRQ mask */
+       msk = (~msk & 0xc030000f) | (tmp << 4);
+       __raw_writel(msk, WUPSMSK);
+
+       /* propage level/edge trigger for external IRQ 0->15 */
+       sh7372_icr_to_irqcr(__raw_readl(ICR1A), &irqcrx_low, &irqcry_low);
+       sh7372_icr_to_irqcr(__raw_readl(ICR2A), &irqcrx_high, &irqcry_high);
+       __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR);
+       __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR2);
+
+       /* read IRQ16A -> IRQ31A mask */
+       tmp = bitrev8(__raw_readb(INTMSK20A));
+       tmp |= bitrev8(__raw_readb(INTMSK30A)) << 8;
+
+       /* setup WUPSMSK2 from clocks and external IRQ mask */
+       msk2 = (~msk2 & 0x00030000) | tmp;
+       __raw_writel(msk2, WUPSMSK2);
+
+       /* propage level/edge trigger for external IRQ 16->31 */
+       sh7372_icr_to_irqcr(__raw_readl(ICR3A), &irqcrx_low, &irqcry_low);
+       sh7372_icr_to_irqcr(__raw_readl(ICR4A), &irqcrx_high, &irqcry_high);
+       __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR3);
+       __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR4);
+}
+#endif
+
 #ifdef CONFIG_CPU_IDLE
+
 static void sh7372_cpuidle_setup(struct cpuidle_device *dev)
 {
        struct cpuidle_state *state;
@@ -239,9 +385,25 @@ static void sh7372_cpuidle_init(void) {}
 #endif
 
 #ifdef CONFIG_SUSPEND
+
 static int sh7372_enter_suspend(suspend_state_t suspend_state)
 {
-       sh7372_enter_core_standby();
+       unsigned long msk, msk2;
+
+       /* check active clocks to determine potential wakeup sources */
+       if (sh7372_a3sm_valid(&msk, &msk2)) {
+
+               /* convert INTC mask and sense to SYSC mask and sense */
+               sh7372_setup_a3sm(msk, msk2);
+
+               /* enter A3SM sleep with PLLC0 off */
+               pr_debug("entering A3SM\n");
+               sh7372_enter_a3sm_common(0);
+       } else {
+               /* default to Core Standby that supports all wakeup sources */
+               pr_debug("entering Core Standby\n");
+               sh7372_enter_core_standby();
+       }
        return 0;
 }
 
@@ -253,9 +415,6 @@ static void sh7372_suspend_init(void)
 static void sh7372_suspend_init(void) {}
 #endif
 
-#define DBGREG1 0xe6100020
-#define DBGREG9 0xe6100040
-
 void __init sh7372_pm_init(void)
 {
        /* enable DBG hardware block to kick SYSC */
index 6ec454e..bd5c6a3 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_domain.h>
+#include <linux/pm_clock.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/sh_clk.h>
index 2d9b1b1..d317c22 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
+#include <linux/pm_domain.h>
 #include <mach/hardware.h>
 #include <mach/sh7372.h>
 #include <asm/mach-types.h>
@@ -994,6 +995,8 @@ void __init sh7372_add_standard_devices(void)
        sh7372_init_pm_domain(&sh7372_a3ri);
        sh7372_init_pm_domain(&sh7372_a3sg);
 
+       sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv);
+
        platform_add_devices(sh7372_early_devices,
                            ARRAY_SIZE(sh7372_early_devices));
 
index d37d3ca..f3ab3c5 100644 (file)
  */
 
 #include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/memory.h>
 #include <asm/assembler.h>
 
-#define SMFRAM 0xe6a70000
-
-       .align
-kernel_flush:
-       .word   v7_flush_dcache_all
-
-       .align  3
-ENTRY(sh7372_cpu_suspend)
-       stmfd   sp!, {r0-r12, lr}       @ save registers on stack
-
-       ldr     r8, =SMFRAM
-
-       mov     r4, sp                  @ Store sp
-       mrs     r5, spsr                @ Store spsr
-       mov     r6, lr                  @ Store lr
-       stmia   r8!, {r4-r6}
-
-       mrc     p15, 0, r4, c1, c0, 2   @ Coprocessor access control register
-       mrc     p15, 0, r5, c2, c0, 0   @ TTBR0
-       mrc     p15, 0, r6, c2, c0, 1   @ TTBR1
-       mrc     p15, 0, r7, c2, c0, 2   @ TTBCR
-       stmia   r8!, {r4-r7}
-
-       mrc     p15, 0, r4, c3, c0, 0   @ Domain access Control Register
-       mrc     p15, 0, r5, c10, c2, 0  @ PRRR
-       mrc     p15, 0, r6, c10, c2, 1  @ NMRR
-       stmia   r8!,{r4-r6}
-
-       mrc     p15, 0, r4, c13, c0, 1  @ Context ID
-       mrc     p15, 0, r5, c13, c0, 2  @ User r/w thread and process ID
-       mrc     p15, 0, r6, c12, c0, 0  @ Secure or NS vector base address
-       mrs     r7, cpsr                @ Store current cpsr
-       stmia   r8!, {r4-r7}
-
-       mrc     p15, 0, r4, c1, c0, 0   @ save control register
-       stmia   r8!, {r4}
-
-       /*
-        * jump out to kernel flush routine
-        *  - reuse that code is better
-        *  - it executes in a cached space so is faster than refetch per-block
-        *  - should be faster and will change with kernel
-        *  - 'might' have to copy address, load and jump to it
-        * Flush all data from the L1 data cache before disabling
-        * SCTLR.C bit.
-        */
-       ldr     r1, kernel_flush
-       mov     lr, pc
-       bx      r1
+#if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
+       .align  12
+       .text
+       .global sh7372_resume_core_standby_a3sm
+sh7372_resume_core_standby_a3sm:
+       ldr     pc, 1f
+1:     .long   cpu_resume - PAGE_OFFSET + PLAT_PHYS_OFFSET
 
+       .global sh7372_do_idle_a3sm
+sh7372_do_idle_a3sm:
        /*
         * Clear the SCTLR.C bit to prevent further data cache
         * allocation. Clearing SCTLR.C would make all the data accesses
@@ -92,10 +54,13 @@ ENTRY(sh7372_cpu_suspend)
        mcr     p15, 0, r0, c1, c0, 0
        isb
 
+       /* disable L2 cache in the aux control register */
+       mrc     p15, 0, r10, c1, c0, 1
+       bic     r10, r10, #2
+       mcr     p15, 0, r10, c1, c0, 1
+
        /*
-        * Invalidate L1 data cache. Even though only invalidate is
-        * necessary exported flush API is used here. Doing clean
-        * on already clean cache would be almost NOP.
+        * Invalidate data cache again.
         */
        ldr     r1, kernel_flush
        blx     r1
@@ -115,146 +80,16 @@ ENTRY(sh7372_cpu_suspend)
        dsb
        dmb
 
-/*
- * ===================================
- * == WFI instruction => Enter idle ==
- * ===================================
- */
-       wfi                             @ wait for interrupt
-
-/*
- * ===================================
- * == Resume path for non-OFF modes ==
- * ===================================
- */
-       mrc     p15, 0, r0, c1, c0, 0
-       tst     r0, #(1 << 2)           @ Check C bit enabled?
-       orreq   r0, r0, #(1 << 2)       @ Enable the C bit if cleared
-       mcreq   p15, 0, r0, c1, c0, 0
-       isb
-
-/*
- * ===================================
- * == Exit point from non-OFF modes ==
- * ===================================
- */
-       ldmfd   sp!, {r0-r12, pc}       @ restore regs and return
+#define SPDCR 0xe6180008
+#define A3SM (1 << 12)
 
-       .pool
+       /* A3SM power down */
+       ldr     r0, =SPDCR
+       ldr     r1, =A3SM
+       str     r1, [r0]
+1:
+       b      1b
 
-       .align  12
-       .text
-       .global sh7372_cpu_resume
-sh7372_cpu_resume:
-
-       mov     r1, #0
-       /*
-        * Invalidate all instruction caches to PoU
-        * and flush branch target cache
-        */
-       mcr     p15, 0, r1, c7, c5, 0
-
-       ldr     r3, =SMFRAM
-
-       ldmia   r3!, {r4-r6}
-       mov     sp, r4                  @ Restore sp
-       msr     spsr_cxsf, r5           @ Restore spsr
-       mov     lr, r6                  @ Restore lr
-
-       ldmia   r3!, {r4-r7}
-       mcr     p15, 0, r4, c1, c0, 2   @ Coprocessor access Control Register
-       mcr     p15, 0, r5, c2, c0, 0   @ TTBR0
-       mcr     p15, 0, r6, c2, c0, 1   @ TTBR1
-       mcr     p15, 0, r7, c2, c0, 2   @ TTBCR
-
-       ldmia   r3!,{r4-r6}
-       mcr     p15, 0, r4, c3, c0, 0   @ Domain access Control Register
-       mcr     p15, 0, r5, c10, c2, 0  @ PRRR
-       mcr     p15, 0, r6, c10, c2, 1  @ NMRR
-
-       ldmia   r3!,{r4-r7}
-       mcr     p15, 0, r4, c13, c0, 1  @ Context ID
-       mcr     p15, 0, r5, c13, c0, 2  @ User r/w thread and process ID
-       mrc     p15, 0, r6, c12, c0, 0  @ Secure or NS vector base address
-       msr     cpsr, r7                @ store cpsr
-
-       /* Starting to enable MMU here */
-       mrc     p15, 0, r7, c2, c0, 2   @ Read TTBRControl
-       /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1 */
-       and     r7, #0x7
-       cmp     r7, #0x0
-       beq     usettbr0
-ttbr_error:
-       /*
-        * More work needs to be done to support N[0:2] value other than 0
-        * So looping here so that the error can be detected
-        */
-       b       ttbr_error
-
-       .align
-cache_pred_disable_mask:
-       .word   0xFFFFE7FB
-ttbrbit_mask:
-       .word   0xFFFFC000
-table_index_mask:
-       .word   0xFFF00000
-table_entry:
-       .word   0x00000C02
-usettbr0:
-
-       mrc     p15, 0, r2, c2, c0, 0
-       ldr     r5, ttbrbit_mask
-       and     r2, r5
-       mov     r4, pc
-       ldr     r5, table_index_mask
-       and     r4, r5                  @ r4 = 31 to 20 bits of pc
-       /* Extract the value to be written to table entry */
-       ldr     r6, table_entry
-       /* r6 has the value to be written to table entry */
-       add     r6, r6, r4
-       /* Getting the address of table entry to modify */
-       lsr     r4, #18
-       /* r2 has the location which needs to be modified */
-       add     r2, r4
-       ldr     r4, [r2]
-       str     r6, [r2] /* modify the table entry */
-
-       mov     r7, r6
-       mov     r5, r2
-       mov     r6, r4
-       /* r5 = original page table address */
-       /* r6 = original page table data */
-
-       mov     r0, #0
-       mcr     p15, 0, r0, c7, c5, 4   @ Flush prefetch buffer
-       mcr     p15, 0, r0, c7, c5, 6   @ Invalidate branch predictor array
-       mcr     p15, 0, r0, c8, c5, 0   @ Invalidate instruction TLB
-       mcr     p15, 0, r0, c8, c6, 0   @ Invalidate data TLB
-
-       /*
-        * Restore control register. This enables the MMU.
-        * The caches and prediction are not enabled here, they
-        * will be enabled after restoring the MMU table entry.
-        */
-       ldmia   r3!, {r4}
-       stmia   r3!, {r5} /* save original page table address */
-       stmia   r3!, {r6} /* save original page table data */
-       stmia   r3!, {r7} /* save modified page table data */
-
-       ldr     r2, cache_pred_disable_mask
-       and     r4, r2
-       mcr     p15, 0, r4, c1, c0, 0
-       dsb
-       isb
-
-       ldr     r0, =restoremmu_on
-       bx      r0
-
-/*
- * ==============================
- * == Exit point from OFF mode ==
- * ==============================
- */
-restoremmu_on:
-
-       ldmfd   sp!, {r0-r12, pc}       @ restore regs and return
+kernel_flush:
+       .word v7_flush_dcache_all
+#endif
index 5cc8385..31a7d3a 100644 (file)
@@ -561,6 +561,20 @@ static struct pci_ops u4_pcie_pci_ops =
        .write = u4_pcie_write_config,
 };
 
+static void __devinit pmac_pci_fixup_u4_of_node(struct pci_dev *dev)
+{
+       /* Apple's device-tree "hides" the root complex virtual P2P bridge
+        * on U4. However, Linux sees it, causing the PCI <-> OF matching
+        * code to fail to properly match devices below it. This works around
+        * it by setting the node of the bridge to point to the PHB node,
+        * which is not entirely correct but fixes the matching code and
+        * doesn't break anything else. It's also the simplest possible fix.
+        */
+       if (dev->dev.of_node == NULL)
+               dev->dev.of_node = pcibios_get_phb_of_node(dev->bus);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, 0x5b, pmac_pci_fixup_u4_of_node);
+
 #endif /* CONFIG_PPC64 */
 
 #ifdef CONFIG_PPC32
index 64b61bf..547f1a6 100644 (file)
@@ -188,7 +188,8 @@ extern char elf_platform[];
 #define SET_PERSONALITY(ex)                                    \
 do {                                                           \
        if (personality(current->personality) != PER_LINUX32)   \
-               set_personality(PER_LINUX);                     \
+               set_personality(PER_LINUX |                     \
+                       (current->personality & ~PER_MASK));    \
        if ((ex).e_ident[EI_CLASS] == ELFCLASS32)               \
                set_thread_flag(TIF_31BIT);                     \
        else                                                    \
index f69ff3c..5d56c2b 100644 (file)
@@ -303,15 +303,15 @@ int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len)
                /* Walk the guest addr space page table */
                table = gmap->table + (((to + off) >> 53) & 0x7ff);
                if (*table & _REGION_ENTRY_INV)
-                       return 0;
+                       goto out;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                table = table + (((to + off) >> 42) & 0x7ff);
                if (*table & _REGION_ENTRY_INV)
-                       return 0;
+                       goto out;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                table = table + (((to + off) >> 31) & 0x7ff);
                if (*table & _REGION_ENTRY_INV)
-                       return 0;
+                       goto out;
                table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
                table = table + (((to + off) >> 20) & 0x7ff);
 
@@ -319,6 +319,7 @@ int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len)
                flush |= gmap_unlink_segment(gmap, table);
                *table = _SEGMENT_ENTRY_INV;
        }
+out:
        up_read(&gmap->mm->mmap_sem);
        if (flush)
                gmap_flush_tlb(gmap);
index 55a17c6..d06a266 100644 (file)
@@ -43,6 +43,8 @@
 #define SUN4V_CHIP_NIAGARA1    0x01
 #define SUN4V_CHIP_NIAGARA2    0x02
 #define SUN4V_CHIP_NIAGARA3    0x03
+#define SUN4V_CHIP_NIAGARA4    0x04
+#define SUN4V_CHIP_NIAGARA5    0x05
 #define SUN4V_CHIP_UNKNOWN     0xff
 
 #ifndef __ASSEMBLY__
index 9ed6ff6..ee8edc6 100644 (file)
@@ -66,6 +66,8 @@ static struct xor_block_template xor_block_niagara = {
        ((tlb_type == hypervisor && \
          (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 || \
           sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || \
-          sun4v_chip_type == SUN4V_CHIP_NIAGARA3)) ? \
+          sun4v_chip_type == SUN4V_CHIP_NIAGARA3 || \
+          sun4v_chip_type == SUN4V_CHIP_NIAGARA4 || \
+          sun4v_chip_type == SUN4V_CHIP_NIAGARA5)) ? \
         &xor_block_niagara : \
         &xor_block_VIS)
index 9810fd8..ba9b1ce 100644 (file)
@@ -481,6 +481,18 @@ static void __init sun4v_cpu_probe(void)
                sparc_pmu_type = "niagara3";
                break;
 
+       case SUN4V_CHIP_NIAGARA4:
+               sparc_cpu_type = "UltraSparc T4 (Niagara4)";
+               sparc_fpu_type = "UltraSparc T4 integrated FPU";
+               sparc_pmu_type = "niagara4";
+               break;
+
+       case SUN4V_CHIP_NIAGARA5:
+               sparc_cpu_type = "UltraSparc T5 (Niagara5)";
+               sparc_fpu_type = "UltraSparc T5 integrated FPU";
+               sparc_pmu_type = "niagara5";
+               break;
+
        default:
                printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
                       prom_cpu_compatible);
index 4197e8d..9323eaf 100644 (file)
@@ -325,6 +325,8 @@ static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)
        case SUN4V_CHIP_NIAGARA1:
        case SUN4V_CHIP_NIAGARA2:
        case SUN4V_CHIP_NIAGARA3:
+       case SUN4V_CHIP_NIAGARA4:
+       case SUN4V_CHIP_NIAGARA5:
                rover_inc_table = niagara_iterate_method;
                break;
        default:
index 0eac1b2..0d810c2 100644 (file)
@@ -133,7 +133,7 @@ prom_sun4v_name:
 prom_niagara_prefix:
        .asciz  "SUNW,UltraSPARC-T"
 prom_sparc_prefix:
-       .asciz  "SPARC-T"
+       .asciz  "SPARC-"
        .align  4
 prom_root_compatible:
        .skip   64
@@ -396,7 +396,7 @@ sun4v_chip_type:
        or      %g1, %lo(prom_cpu_compatible), %g1
        sethi   %hi(prom_sparc_prefix), %g7
        or      %g7, %lo(prom_sparc_prefix), %g7
-       mov     7, %g3
+       mov     6, %g3
 90:    ldub    [%g7], %g2
        ldub    [%g1], %g4
        cmp     %g2, %g4
@@ -408,10 +408,23 @@ sun4v_chip_type:
 
        sethi   %hi(prom_cpu_compatible), %g1
        or      %g1, %lo(prom_cpu_compatible), %g1
-       ldub    [%g1 + 7], %g2
+       ldub    [%g1 + 6], %g2
+       cmp     %g2, 'T'
+       be,pt   %xcc, 70f
+        cmp    %g2, 'M'
+       bne,pn  %xcc, 4f
+        nop
+
+70:    ldub    [%g1 + 7], %g2
        cmp     %g2, '3'
        be,pt   %xcc, 5f
         mov    SUN4V_CHIP_NIAGARA3, %g4
+       cmp     %g2, '4'
+       be,pt   %xcc, 5f
+        mov    SUN4V_CHIP_NIAGARA4, %g4
+       cmp     %g2, '5'
+       be,pt   %xcc, 5f
+        mov    SUN4V_CHIP_NIAGARA5, %g4
        ba,pt   %xcc, 4f
         nop
 
@@ -545,6 +558,12 @@ niagara_tlb_fixup:
        cmp     %g1, SUN4V_CHIP_NIAGARA3
        be,pt   %xcc, niagara2_patch
         nop
+       cmp     %g1, SUN4V_CHIP_NIAGARA4
+       be,pt   %xcc, niagara2_patch
+        nop
+       cmp     %g1, SUN4V_CHIP_NIAGARA5
+       be,pt   %xcc, niagara2_patch
+        nop
 
        call    generic_patch_copyops
         nop
index c8cc461..f793742 100644 (file)
@@ -380,8 +380,7 @@ void flush_thread(void)
 #endif
        }
 
-       /* Now, this task is no longer a kernel thread. */
-       current->thread.current_ds = USER_DS;
+       /* This task is no longer a kernel thread. */
        if (current->thread.flags & SPARC_FLAG_KTHREAD) {
                current->thread.flags &= ~SPARC_FLAG_KTHREAD;
 
index c158a95..d959cd0 100644 (file)
@@ -368,9 +368,6 @@ void flush_thread(void)
 
        /* Clear FPU register state. */
        t->fpsaved[0] = 0;
-       
-       if (get_thread_current_ds() != ASI_AIUS)
-               set_fs(USER_DS);
 }
 
 /* It's a bit more tricky when 64-bit tasks are involved... */
index d26e1f6..3e3e291 100644 (file)
@@ -137,7 +137,7 @@ static void __init process_switch(char c)
                prom_halt();
                break;
        case 'p':
-               /* Just ignore, this behavior is now the default.  */
+               prom_early_console.flags &= ~CON_BOOT;
                break;
        default:
                printk("Unknown boot switch (-%c)\n", c);
index 3c5bb78..c965595 100644 (file)
@@ -106,7 +106,7 @@ static void __init process_switch(char c)
                prom_halt();
                break;
        case 'p':
-               /* Just ignore, this behavior is now the default.  */
+               prom_early_console.flags &= ~CON_BOOT;
                break;
        case 'P':
                /* Force UltraSPARC-III P-Cache on. */
@@ -425,10 +425,14 @@ static void __init init_sparc64_elf_hwcap(void)
        else if (tlb_type == hypervisor) {
                if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
                    sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
-                   sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
                        cap |= HWCAP_SPARC_BLKINIT;
                if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
-                   sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
+                   sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
                        cap |= HWCAP_SPARC_N2;
        }
 
@@ -452,11 +456,15 @@ static void __init init_sparc64_elf_hwcap(void)
                        if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1)
                                cap |= AV_SPARC_ASI_BLK_INIT;
                        if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
-                           sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+                           sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
+                           sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
+                           sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
                                cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 |
                                        AV_SPARC_ASI_BLK_INIT |
                                        AV_SPARC_POPC);
-                       if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
+                       if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
+                           sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
+                           sun4v_chip_type == SUN4V_CHIP_NIAGARA5)
                                cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC |
                                        AV_SPARC_FMAF);
                }
index 581531d..8e073d8 100644 (file)
@@ -511,6 +511,11 @@ static void __init read_obp_translations(void)
                for (i = 0; i < prom_trans_ents; i++)
                        prom_trans[i].data &= ~0x0003fe0000000000UL;
        }
+
+       /* Force execute bit on.  */
+       for (i = 0; i < prom_trans_ents; i++)
+               prom_trans[i].data |= (tlb_type == hypervisor ?
+                                      _PAGE_EXEC_4V : _PAGE_EXEC_4U);
 }
 
 static void __init hypervisor_tlb_lock(unsigned long vaddr,
index 3f2ad26..ccdbc16 100644 (file)
@@ -42,8 +42,11 @@ int mach_set_rtc_mmss(unsigned long nowtime)
 {
        int real_seconds, real_minutes, cmos_minutes;
        unsigned char save_control, save_freq_select;
+       unsigned long flags;
        int retval = 0;
 
+       spin_lock_irqsave(&rtc_lock, flags);
+
         /* tell the clock it's being set */
        save_control = CMOS_READ(RTC_CONTROL);
        CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
@@ -93,12 +96,17 @@ int mach_set_rtc_mmss(unsigned long nowtime)
        CMOS_WRITE(save_control, RTC_CONTROL);
        CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
 
+       spin_unlock_irqrestore(&rtc_lock, flags);
+
        return retval;
 }
 
 unsigned long mach_get_cmos_time(void)
 {
        unsigned int status, year, mon, day, hour, min, sec, century = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rtc_lock, flags);
 
        /*
         * If UIP is clear, then we have >= 244 microseconds before
@@ -125,6 +133,8 @@ unsigned long mach_get_cmos_time(void)
        status = CMOS_READ(RTC_CONTROL);
        WARN_ON_ONCE(RTC_ALWAYS_BCD && (status & RTC_DM_BINARY));
 
+       spin_unlock_irqrestore(&rtc_lock, flags);
+
        if (RTC_ALWAYS_BCD || !(status & RTC_DM_BINARY)) {
                sec = bcd2bin(sec);
                min = bcd2bin(min);
@@ -169,24 +179,15 @@ EXPORT_SYMBOL(rtc_cmos_write);
 
 int update_persistent_clock(struct timespec now)
 {
-       unsigned long flags;
-       int retval;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       retval = x86_platform.set_wallclock(now.tv_sec);
-       spin_unlock_irqrestore(&rtc_lock, flags);
-
-       return retval;
+       return x86_platform.set_wallclock(now.tv_sec);
 }
 
 /* not static: needed by APM */
 void read_persistent_clock(struct timespec *ts)
 {
-       unsigned long retval, flags;
+       unsigned long retval;
 
-       spin_lock_irqsave(&rtc_lock, flags);
        retval = x86_platform.get_wallclock();
-       spin_unlock_irqrestore(&rtc_lock, flags);
 
        ts->tv_sec = retval;
        ts->tv_nsec = 0;
index 039d913..404f21a 100644 (file)
@@ -43,6 +43,17 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "ALiveSATA2-GLAN"),
                 },
         },
+       /* https://bugzilla.kernel.org/show_bug.cgi?id=30552 */
+       /* 2006 AMD HT/VIA system with two host bridges */
+       {
+               .callback = set_use_crs,
+               .ident = "ASUS M2V-MX SE",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "M2V-MX SE"),
+                       DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+               },
+       },
        {}
 };
 
index 73d70d6..6d5dbcd 100644 (file)
@@ -58,8 +58,11 @@ EXPORT_SYMBOL_GPL(vrtc_cmos_write);
 unsigned long vrtc_get_time(void)
 {
        u8 sec, min, hour, mday, mon;
+       unsigned long flags;
        u32 year;
 
+       spin_lock_irqsave(&rtc_lock, flags);
+
        while ((vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP))
                cpu_relax();
 
@@ -70,6 +73,8 @@ unsigned long vrtc_get_time(void)
        mon = vrtc_cmos_read(RTC_MONTH);
        year = vrtc_cmos_read(RTC_YEAR);
 
+       spin_unlock_irqrestore(&rtc_lock, flags);
+
        /* vRTC YEAR reg contains the offset to 1960 */
        year += 1960;
 
@@ -83,8 +88,10 @@ unsigned long vrtc_get_time(void)
 int vrtc_set_mmss(unsigned long nowtime)
 {
        int real_sec, real_min;
+       unsigned long flags;
        int vrtc_min;
 
+       spin_lock_irqsave(&rtc_lock, flags);
        vrtc_min = vrtc_cmos_read(RTC_MINUTES);
 
        real_sec = nowtime % 60;
@@ -95,6 +102,8 @@ int vrtc_set_mmss(unsigned long nowtime)
 
        vrtc_cmos_write(real_sec, RTC_SECONDS);
        vrtc_cmos_write(real_min, RTC_MINUTES);
+       spin_unlock_irqrestore(&rtc_lock, flags);
+
        return 0;
 }
 
index b2ed78a..d34433a 100644 (file)
@@ -348,9 +348,10 @@ void blk_put_queue(struct request_queue *q)
 EXPORT_SYMBOL(blk_put_queue);
 
 /*
- * Note: If a driver supplied the queue lock, it should not zap that lock
- * unexpectedly as some queue cleanup components like elevator_exit() and
- * blk_throtl_exit() need queue lock.
+ * Note: If a driver supplied the queue lock, it is disconnected
+ * by this function. The actual state of the lock doesn't matter
+ * here as the request_queue isn't accessible after this point
+ * (QUEUE_FLAG_DEAD is set) and no other requests will be queued.
  */
 void blk_cleanup_queue(struct request_queue *q)
 {
@@ -367,10 +368,8 @@ void blk_cleanup_queue(struct request_queue *q)
        queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);
        mutex_unlock(&q->sysfs_lock);
 
-       if (q->elevator)
-               elevator_exit(q->elevator);
-
-       blk_throtl_exit(q);
+       if (q->queue_lock != &q->__queue_lock)
+               q->queue_lock = &q->__queue_lock;
 
        blk_put_queue(q);
 }
index e681805..60fda88 100644 (file)
@@ -479,6 +479,11 @@ static void blk_release_queue(struct kobject *kobj)
 
        blk_sync_queue(q);
 
+       if (q->elevator)
+               elevator_exit(q->elevator);
+
+       blk_throtl_exit(q);
+
        if (rl->rq_pool)
                mempool_destroy(rl->rq_pool);
 
index 431ab11..2e69e09 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/dmi.h>
 #include <linux/moduleparam.h>
 #include <linux/sched.h>       /* need_resched() */
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/clockchips.h>
 #include <linux/cpuidle.h>
 #include <linux/irqflags.h>
index 2639ae7..81676dd 100644 (file)
@@ -1,4 +1,4 @@
-obj-$(CONFIG_PM)       += sysfs.o generic_ops.o
+obj-$(CONFIG_PM)       += sysfs.o generic_ops.o common.o qos.o
 obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
 obj-$(CONFIG_PM_RUNTIME)       += runtime.o
 obj-$(CONFIG_PM_TRACE_RTC)     += trace.o
@@ -6,4 +6,4 @@ obj-$(CONFIG_PM_OPP)    += opp.o
 obj-$(CONFIG_PM_GENERIC_DOMAINS)       +=  domain.o
 obj-$(CONFIG_HAVE_CLK) += clock_ops.o
 
-ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
\ No newline at end of file
+ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
index b97294e..b876e60 100644 (file)
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/pm.h>
-#include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 
 #ifdef CONFIG_PM
 
-struct pm_clk_data {
-       struct list_head clock_list;
-       spinlock_t lock;
-};
-
 enum pce_status {
        PCE_STATUS_NONE = 0,
        PCE_STATUS_ACQUIRED,
@@ -36,11 +31,6 @@ struct pm_clock_entry {
        enum pce_status status;
 };
 
-static struct pm_clk_data *__to_pcd(struct device *dev)
-{
-       return dev ? dev->power.subsys_data : NULL;
-}
-
 /**
  * pm_clk_acquire - Acquire a device clock.
  * @dev: Device whose clock is to be acquired.
@@ -67,10 +57,10 @@ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
  */
 int pm_clk_add(struct device *dev, const char *con_id)
 {
-       struct pm_clk_data *pcd = __to_pcd(dev);
+       struct pm_subsys_data *psd = dev_to_psd(dev);
        struct pm_clock_entry *ce;
 
-       if (!pcd)
+       if (!psd)
                return -EINVAL;
 
        ce = kzalloc(sizeof(*ce), GFP_KERNEL);
@@ -91,9 +81,9 @@ int pm_clk_add(struct device *dev, const char *con_id)
 
        pm_clk_acquire(dev, ce);
 
-       spin_lock_irq(&pcd->lock);
-       list_add_tail(&ce->node, &pcd->clock_list);
-       spin_unlock_irq(&pcd->lock);
+       spin_lock_irq(&psd->lock);
+       list_add_tail(&ce->node, &psd->clock_list);
+       spin_unlock_irq(&psd->lock);
        return 0;
 }
 
@@ -130,15 +120,15 @@ static void __pm_clk_remove(struct pm_clock_entry *ce)
  */
 void pm_clk_remove(struct device *dev, const char *con_id)
 {
-       struct pm_clk_data *pcd = __to_pcd(dev);
+       struct pm_subsys_data *psd = dev_to_psd(dev);
        struct pm_clock_entry *ce;
 
-       if (!pcd)
+       if (!psd)
                return;
 
-       spin_lock_irq(&pcd->lock);
+       spin_lock_irq(&psd->lock);
 
-       list_for_each_entry(ce, &pcd->clock_list, node) {
+       list_for_each_entry(ce, &psd->clock_list, node) {
                if (!con_id && !ce->con_id)
                        goto remove;
                else if (!con_id || !ce->con_id)
@@ -147,12 +137,12 @@ void pm_clk_remove(struct device *dev, const char *con_id)
                        goto remove;
        }
 
-       spin_unlock_irq(&pcd->lock);
+       spin_unlock_irq(&psd->lock);
        return;
 
  remove:
        list_del(&ce->node);
-       spin_unlock_irq(&pcd->lock);
+       spin_unlock_irq(&psd->lock);
 
        __pm_clk_remove(ce);
 }
@@ -161,23 +151,27 @@ void pm_clk_remove(struct device *dev, const char *con_id)
  * pm_clk_init - Initialize a device's list of power management clocks.
  * @dev: Device to initialize the list of PM clocks for.
  *
- * Allocate a struct pm_clk_data object, initialize its lock member and
- * make the @dev's power.subsys_data field point to it.
+ * Initialize the lock and clock_list members of the device's pm_subsys_data
+ * object.
  */
-int pm_clk_init(struct device *dev)
+void pm_clk_init(struct device *dev)
 {
-       struct pm_clk_data *pcd;
-
-       pcd = kzalloc(sizeof(*pcd), GFP_KERNEL);
-       if (!pcd) {
-               dev_err(dev, "Not enough memory for PM clock data.\n");
-               return -ENOMEM;
-       }
+       struct pm_subsys_data *psd = dev_to_psd(dev);
+       if (psd)
+               INIT_LIST_HEAD(&psd->clock_list);
+}
 
-       INIT_LIST_HEAD(&pcd->clock_list);
-       spin_lock_init(&pcd->lock);
-       dev->power.subsys_data = pcd;
-       return 0;
+/**
+ * pm_clk_create - Create and initialize a device's list of PM clocks.
+ * @dev: Device to create and initialize the list of PM clocks for.
+ *
+ * Allocate a struct pm_subsys_data object, initialize its lock and clock_list
+ * members and make the @dev's power.subsys_data field point to it.
+ */
+int pm_clk_create(struct device *dev)
+{
+       int ret = dev_pm_get_subsys_data(dev);
+       return ret < 0 ? ret : 0;
 }
 
 /**
@@ -185,29 +179,28 @@ int pm_clk_init(struct device *dev)
  * @dev: Device to destroy the list of PM clocks for.
  *
  * Clear the @dev's power.subsys_data field, remove the list of clock entries
- * from the struct pm_clk_data object pointed to by it before and free
+ * from the struct pm_subsys_data object pointed to by it before and free
  * that object.
  */
 void pm_clk_destroy(struct device *dev)
 {
-       struct pm_clk_data *pcd = __to_pcd(dev);
+       struct pm_subsys_data *psd = dev_to_psd(dev);
        struct pm_clock_entry *ce, *c;
        struct list_head list;
 
-       if (!pcd)
+       if (!psd)
                return;
 
-       dev->power.subsys_data = NULL;
        INIT_LIST_HEAD(&list);
 
-       spin_lock_irq(&pcd->lock);
+       spin_lock_irq(&psd->lock);
 
-       list_for_each_entry_safe_reverse(ce, c, &pcd->clock_list, node)
+       list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
                list_move(&ce->node, &list);
 
-       spin_unlock_irq(&pcd->lock);
+       spin_unlock_irq(&psd->lock);
 
-       kfree(pcd);
+       dev_pm_put_subsys_data(dev);
 
        list_for_each_entry_safe_reverse(ce, c, &list, node) {
                list_del(&ce->node);
@@ -225,25 +218,25 @@ void pm_clk_destroy(struct device *dev)
  */
 int pm_clk_suspend(struct device *dev)
 {
-       struct pm_clk_data *pcd = __to_pcd(dev);
+       struct pm_subsys_data *psd = dev_to_psd(dev);
        struct pm_clock_entry *ce;
        unsigned long flags;
 
        dev_dbg(dev, "%s()\n", __func__);
 
-       if (!pcd)
+       if (!psd)
                return 0;
 
-       spin_lock_irqsave(&pcd->lock, flags);
+       spin_lock_irqsave(&psd->lock, flags);
 
-       list_for_each_entry_reverse(ce, &pcd->clock_list, node) {
+       list_for_each_entry_reverse(ce, &psd->clock_list, node) {
                if (ce->status < PCE_STATUS_ERROR) {
                        clk_disable(ce->clk);
                        ce->status = PCE_STATUS_ACQUIRED;
                }
        }
 
-       spin_unlock_irqrestore(&pcd->lock, flags);
+       spin_unlock_irqrestore(&psd->lock, flags);
 
        return 0;
 }
@@ -254,25 +247,25 @@ int pm_clk_suspend(struct device *dev)
  */
 int pm_clk_resume(struct device *dev)
 {
-       struct pm_clk_data *pcd = __to_pcd(dev);
+       struct pm_subsys_data *psd = dev_to_psd(dev);
        struct pm_clock_entry *ce;
        unsigned long flags;
 
        dev_dbg(dev, "%s()\n", __func__);
 
-       if (!pcd)
+       if (!psd)
                return 0;
 
-       spin_lock_irqsave(&pcd->lock, flags);
+       spin_lock_irqsave(&psd->lock, flags);
 
-       list_for_each_entry(ce, &pcd->clock_list, node) {
+       list_for_each_entry(ce, &psd->clock_list, node) {
                if (ce->status < PCE_STATUS_ERROR) {
                        clk_enable(ce->clk);
                        ce->status = PCE_STATUS_ENABLED;
                }
        }
 
-       spin_unlock_irqrestore(&pcd->lock, flags);
+       spin_unlock_irqrestore(&psd->lock, flags);
 
        return 0;
 }
@@ -310,7 +303,7 @@ static int pm_clk_notify(struct notifier_block *nb,
                if (dev->pm_domain)
                        break;
 
-               error = pm_clk_init(dev);
+               error = pm_clk_create(dev);
                if (error)
                        break;
 
@@ -345,22 +338,22 @@ static int pm_clk_notify(struct notifier_block *nb,
  */
 int pm_clk_suspend(struct device *dev)
 {
-       struct pm_clk_data *pcd = __to_pcd(dev);
+       struct pm_subsys_data *psd = dev_to_psd(dev);
        struct pm_clock_entry *ce;
        unsigned long flags;
 
        dev_dbg(dev, "%s()\n", __func__);
 
        /* If there is no driver, the clocks are already disabled. */
-       if (!pcd || !dev->driver)
+       if (!psd || !dev->driver)
                return 0;
 
-       spin_lock_irqsave(&pcd->lock, flags);
+       spin_lock_irqsave(&psd->lock, flags);
 
-       list_for_each_entry_reverse(ce, &pcd->clock_list, node)
+       list_for_each_entry_reverse(ce, &psd->clock_list, node)
                clk_disable(ce->clk);
 
-       spin_unlock_irqrestore(&pcd->lock, flags);
+       spin_unlock_irqrestore(&psd->lock, flags);
 
        return 0;
 }
@@ -371,22 +364,22 @@ int pm_clk_suspend(struct device *dev)
  */
 int pm_clk_resume(struct device *dev)
 {
-       struct pm_clk_data *pcd = __to_pcd(dev);
+       struct pm_subsys_data *psd = dev_to_psd(dev);
        struct pm_clock_entry *ce;
        unsigned long flags;
 
        dev_dbg(dev, "%s()\n", __func__);
 
        /* If there is no driver, the clocks should remain disabled. */
-       if (!pcd || !dev->driver)
+       if (!psd || !dev->driver)
                return 0;
 
-       spin_lock_irqsave(&pcd->lock, flags);
+       spin_lock_irqsave(&psd->lock, flags);
 
-       list_for_each_entry(ce, &pcd->clock_list, node)
+       list_for_each_entry(ce, &psd->clock_list, node)
                clk_enable(ce->clk);
 
-       spin_unlock_irqrestore(&pcd->lock, flags);
+       spin_unlock_irqrestore(&psd->lock, flags);
 
        return 0;
 }
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
new file mode 100644 (file)
index 0000000..29820c3
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * drivers/base/power/common.c - Common device power management code.
+ *
+ * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pm_clock.h>
+
+/**
+ * dev_pm_get_subsys_data - Create or refcount power.subsys_data for device.
+ * @dev: Device to handle.
+ *
+ * If power.subsys_data is NULL, point it to a new object, otherwise increment
+ * its reference counter.  Return 1 if a new object has been created, otherwise
+ * return 0 or error code.
+ */
+int dev_pm_get_subsys_data(struct device *dev)
+{
+       struct pm_subsys_data *psd;
+       int ret = 0;
+
+       psd = kzalloc(sizeof(*psd), GFP_KERNEL);
+       if (!psd)
+               return -ENOMEM;
+
+       spin_lock_irq(&dev->power.lock);
+
+       if (dev->power.subsys_data) {
+               dev->power.subsys_data->refcount++;
+       } else {
+               spin_lock_init(&psd->lock);
+               psd->refcount = 1;
+               dev->power.subsys_data = psd;
+               pm_clk_init(dev);
+               psd = NULL;
+               ret = 1;
+       }
+
+       spin_unlock_irq(&dev->power.lock);
+
+       /* kfree() verifies that its argument is nonzero. */
+       kfree(psd);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data);
+
+/**
+ * dev_pm_put_subsys_data - Drop reference to power.subsys_data.
+ * @dev: Device to handle.
+ *
+ * If the reference counter of power.subsys_data is zero after dropping the
+ * reference, power.subsys_data is removed.  Return 1 if that happens or 0
+ * otherwise.
+ */
+int dev_pm_put_subsys_data(struct device *dev)
+{
+       struct pm_subsys_data *psd;
+       int ret = 0;
+
+       spin_lock_irq(&dev->power.lock);
+
+       psd = dev_to_psd(dev);
+       if (!psd) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (--psd->refcount == 0) {
+               dev->power.subsys_data = NULL;
+               kfree(psd);
+               ret = 1;
+       }
+
+ out:
+       spin_unlock_irq(&dev->power.lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data);
index 1c37457..22fe029 100644 (file)
@@ -29,10 +29,20 @@ static struct generic_pm_domain *dev_to_genpd(struct device *dev)
        return pd_to_genpd(dev->pm_domain);
 }
 
-static void genpd_sd_counter_dec(struct generic_pm_domain *genpd)
+static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
 {
-       if (!WARN_ON(genpd->sd_count == 0))
-                       genpd->sd_count--;
+       bool ret = false;
+
+       if (!WARN_ON(atomic_read(&genpd->sd_count) == 0))
+               ret = !!atomic_dec_and_test(&genpd->sd_count);
+
+       return ret;
+}
+
+static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
+{
+       atomic_inc(&genpd->sd_count);
+       smp_mb__after_atomic_inc();
 }
 
 static void genpd_acquire_lock(struct generic_pm_domain *genpd)
@@ -71,81 +81,119 @@ static void genpd_set_active(struct generic_pm_domain *genpd)
 }
 
 /**
- * pm_genpd_poweron - Restore power to a given PM domain and its parents.
+ * __pm_genpd_poweron - Restore power to a given PM domain and its masters.
  * @genpd: PM domain to power up.
  *
- * Restore power to @genpd and all of its parents so that it is possible to
+ * Restore power to @genpd and all of its masters so that it is possible to
  * resume a device belonging to it.
  */
-int pm_genpd_poweron(struct generic_pm_domain *genpd)
+int __pm_genpd_poweron(struct generic_pm_domain *genpd)
+       __releases(&genpd->lock) __acquires(&genpd->lock)
 {
-       struct generic_pm_domain *parent = genpd->parent;
+       struct gpd_link *link;
+       DEFINE_WAIT(wait);
        int ret = 0;
 
- start:
-       if (parent) {
-               genpd_acquire_lock(parent);
-               mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
-       } else {
+       /* If the domain's master is being waited for, we have to wait too. */
+       for (;;) {
+               prepare_to_wait(&genpd->status_wait_queue, &wait,
+                               TASK_UNINTERRUPTIBLE);
+               if (genpd->status != GPD_STATE_WAIT_MASTER)
+                       break;
+               mutex_unlock(&genpd->lock);
+
+               schedule();
+
                mutex_lock(&genpd->lock);
        }
+       finish_wait(&genpd->status_wait_queue, &wait);
 
        if (genpd->status == GPD_STATE_ACTIVE
            || (genpd->prepared_count > 0 && genpd->suspend_power_off))
-               goto out;
+               return 0;
 
        if (genpd->status != GPD_STATE_POWER_OFF) {
                genpd_set_active(genpd);
-               goto out;
+               return 0;
        }
 
-       if (parent && parent->status != GPD_STATE_ACTIVE) {
+       /*
+        * The list is guaranteed not to change while the loop below is being
+        * executed, unless one of the masters' .power_on() callbacks fiddles
+        * with it.
+        */
+       list_for_each_entry(link, &genpd->slave_links, slave_node) {
+               genpd_sd_counter_inc(link->master);
+               genpd->status = GPD_STATE_WAIT_MASTER;
+
                mutex_unlock(&genpd->lock);
-               genpd_release_lock(parent);
 
-               ret = pm_genpd_poweron(parent);
-               if (ret)
-                       return ret;
+               ret = pm_genpd_poweron(link->master);
 
-               goto start;
+               mutex_lock(&genpd->lock);
+
+               /*
+                * The "wait for parent" status is guaranteed not to change
+                * while the master is powering on.
+                */
+               genpd->status = GPD_STATE_POWER_OFF;
+               wake_up_all(&genpd->status_wait_queue);
+               if (ret) {
+                       genpd_sd_counter_dec(link->master);
+                       goto err;
+               }
        }
 
        if (genpd->power_on) {
                ret = genpd->power_on(genpd);
                if (ret)
-                       goto out;
+                       goto err;
        }
 
        genpd_set_active(genpd);
-       if (parent)
-               parent->sd_count++;
 
- out:
-       mutex_unlock(&genpd->lock);
-       if (parent)
-               genpd_release_lock(parent);
+       return 0;
+
+ err:
+       list_for_each_entry_continue_reverse(link, &genpd->slave_links, slave_node)
+               genpd_sd_counter_dec(link->master);
 
        return ret;
 }
 
+/**
+ * pm_genpd_poweron - Restore power to a given PM domain and its masters.
+ * @genpd: PM domain to power up.
+ */
+int pm_genpd_poweron(struct generic_pm_domain *genpd)
+{
+       int ret;
+
+       mutex_lock(&genpd->lock);
+       ret = __pm_genpd_poweron(genpd);
+       mutex_unlock(&genpd->lock);
+       return ret;
+}
+
 #endif /* CONFIG_PM */
 
 #ifdef CONFIG_PM_RUNTIME
 
 /**
  * __pm_genpd_save_device - Save the pre-suspend state of a device.
- * @dle: Device list entry of the device to save the state of.
+ * @pdd: Domain data of the device to save the state of.
  * @genpd: PM domain the device belongs to.
  */
-static int __pm_genpd_save_device(struct dev_list_entry *dle,
+static int __pm_genpd_save_device(struct pm_domain_data *pdd,
                                  struct generic_pm_domain *genpd)
        __releases(&genpd->lock) __acquires(&genpd->lock)
 {
-       struct device *dev = dle->dev;
+       struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
+       struct device *dev = pdd->dev;
        struct device_driver *drv = dev->driver;
        int ret = 0;
 
-       if (dle->need_restore)
+       if (gpd_data->need_restore)
                return 0;
 
        mutex_unlock(&genpd->lock);
@@ -163,24 +211,25 @@ static int __pm_genpd_save_device(struct dev_list_entry *dle,
        mutex_lock(&genpd->lock);
 
        if (!ret)
-               dle->need_restore = true;
+               gpd_data->need_restore = true;
 
        return ret;
 }
 
 /**
  * __pm_genpd_restore_device - Restore the pre-suspend state of a device.
- * @dle: Device list entry of the device to restore the state of.
+ * @pdd: Domain data of the device to restore the state of.
  * @genpd: PM domain the device belongs to.
  */
-static void __pm_genpd_restore_device(struct dev_list_entry *dle,
+static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
                                      struct generic_pm_domain *genpd)
        __releases(&genpd->lock) __acquires(&genpd->lock)
 {
-       struct device *dev = dle->dev;
+       struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
+       struct device *dev = pdd->dev;
        struct device_driver *drv = dev->driver;
 
-       if (!dle->need_restore)
+       if (!gpd_data->need_restore)
                return;
 
        mutex_unlock(&genpd->lock);
@@ -197,7 +246,7 @@ static void __pm_genpd_restore_device(struct dev_list_entry *dle,
 
        mutex_lock(&genpd->lock);
 
-       dle->need_restore = false;
+       gpd_data->need_restore = false;
 }
 
 /**
@@ -211,7 +260,8 @@ static void __pm_genpd_restore_device(struct dev_list_entry *dle,
  */
 static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
 {
-       return genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
+       return genpd->status == GPD_STATE_WAIT_MASTER
+               || genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
 }
 
 /**
@@ -238,8 +288,8 @@ void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
 static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
        __releases(&genpd->lock) __acquires(&genpd->lock)
 {
-       struct generic_pm_domain *parent;
-       struct dev_list_entry *dle;
+       struct pm_domain_data *pdd;
+       struct gpd_link *link;
        unsigned int not_suspended;
        int ret = 0;
 
@@ -247,19 +297,22 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
        /*
         * Do not try to power off the domain in the following situations:
         * (1) The domain is already in the "power off" state.
-        * (2) System suspend is in progress.
+        * (2) The domain is waiting for its master to power up.
         * (3) One of the domain's devices is being resumed right now.
+        * (4) System suspend is in progress.
         */
-       if (genpd->status == GPD_STATE_POWER_OFF || genpd->prepared_count > 0
-           || genpd->resume_count > 0)
+       if (genpd->status == GPD_STATE_POWER_OFF
+           || genpd->status == GPD_STATE_WAIT_MASTER
+           || genpd->resume_count > 0 || genpd->prepared_count > 0)
                return 0;
 
-       if (genpd->sd_count > 0)
+       if (atomic_read(&genpd->sd_count) > 0)
                return -EBUSY;
 
        not_suspended = 0;
-       list_for_each_entry(dle, &genpd->dev_list, node)
-               if (dle->dev->driver && !pm_runtime_suspended(dle->dev))
+       list_for_each_entry(pdd, &genpd->dev_list, list_node)
+               if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
+                   || pdd->dev->power.irq_safe))
                        not_suspended++;
 
        if (not_suspended > genpd->in_progress)
@@ -282,54 +335,50 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
        genpd->status = GPD_STATE_BUSY;
        genpd->poweroff_task = current;
 
-       list_for_each_entry_reverse(dle, &genpd->dev_list, node) {
-               ret = __pm_genpd_save_device(dle, genpd);
+       list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
+               ret = atomic_read(&genpd->sd_count) == 0 ?
+                       __pm_genpd_save_device(pdd, genpd) : -EBUSY;
+
+               if (genpd_abort_poweroff(genpd))
+                       goto out;
+
                if (ret) {
                        genpd_set_active(genpd);
                        goto out;
                }
 
-               if (genpd_abort_poweroff(genpd))
-                       goto out;
-
                if (genpd->status == GPD_STATE_REPEAT) {
                        genpd->poweroff_task = NULL;
                        goto start;
                }
        }
 
-       parent = genpd->parent;
-       if (parent) {
-               mutex_unlock(&genpd->lock);
-
-               genpd_acquire_lock(parent);
-               mutex_lock_nested(&genpd->lock, SINGLE_DEPTH_NESTING);
-
-               if (genpd_abort_poweroff(genpd)) {
-                       genpd_release_lock(parent);
+       if (genpd->power_off) {
+               if (atomic_read(&genpd->sd_count) > 0) {
+                       ret = -EBUSY;
                        goto out;
                }
-       }
 
-       if (genpd->power_off) {
+               /*
+                * If sd_count > 0 at this point, one of the subdomains hasn't
+                * managed to call pm_genpd_poweron() for the master yet after
+                * incrementing it.  In that case pm_genpd_poweron() will wait
+                * for us to drop the lock, so we can call .power_off() and let
+                * the pm_genpd_poweron() restore power for us (this shouldn't
+                * happen very often).
+                */
                ret = genpd->power_off(genpd);
                if (ret == -EBUSY) {
                        genpd_set_active(genpd);
-                       if (parent)
-                               genpd_release_lock(parent);
-
                        goto out;
                }
        }
 
        genpd->status = GPD_STATE_POWER_OFF;
 
-       if (parent) {
-               genpd_sd_counter_dec(parent);
-               if (parent->sd_count == 0)
-                       genpd_queue_power_off_work(parent);
-
-               genpd_release_lock(parent);
+       list_for_each_entry(link, &genpd->slave_links, slave_node) {
+               genpd_sd_counter_dec(link->master);
+               genpd_queue_power_off_work(link->master);
        }
 
  out:
@@ -371,12 +420,21 @@ static int pm_genpd_runtime_suspend(struct device *dev)
        if (IS_ERR(genpd))
                return -EINVAL;
 
+       might_sleep_if(!genpd->dev_irq_safe);
+
        if (genpd->stop_device) {
                int ret = genpd->stop_device(dev);
                if (ret)
                        return ret;
        }
 
+       /*
+        * If power.irq_safe is set, this routine will be run with interrupts
+        * off, so it can't use mutexes.
+        */
+       if (dev->power.irq_safe)
+               return 0;
+
        mutex_lock(&genpd->lock);
        genpd->in_progress++;
        pm_genpd_poweroff(genpd);
@@ -387,24 +445,6 @@ static int pm_genpd_runtime_suspend(struct device *dev)
 }
 
 /**
- * __pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
- * @dev: Device to resume.
- * @genpd: PM domain the device belongs to.
- */
-static void __pm_genpd_runtime_resume(struct device *dev,
-                                     struct generic_pm_domain *genpd)
-{
-       struct dev_list_entry *dle;
-
-       list_for_each_entry(dle, &genpd->dev_list, node) {
-               if (dle->dev == dev) {
-                       __pm_genpd_restore_device(dle, genpd);
-                       break;
-               }
-       }
-}
-
-/**
  * pm_genpd_runtime_resume - Resume a device belonging to I/O PM domain.
  * @dev: Device to resume.
  *
@@ -424,11 +464,18 @@ static int pm_genpd_runtime_resume(struct device *dev)
        if (IS_ERR(genpd))
                return -EINVAL;
 
-       ret = pm_genpd_poweron(genpd);
-       if (ret)
-               return ret;
+       might_sleep_if(!genpd->dev_irq_safe);
+
+       /* If power.irq_safe, the PM domain is never powered off. */
+       if (dev->power.irq_safe)
+               goto out;
 
        mutex_lock(&genpd->lock);
+       ret = __pm_genpd_poweron(genpd);
+       if (ret) {
+               mutex_unlock(&genpd->lock);
+               return ret;
+       }
        genpd->status = GPD_STATE_BUSY;
        genpd->resume_count++;
        for (;;) {
@@ -448,12 +495,13 @@ static int pm_genpd_runtime_resume(struct device *dev)
                mutex_lock(&genpd->lock);
        }
        finish_wait(&genpd->status_wait_queue, &wait);
-       __pm_genpd_runtime_resume(dev, genpd);
+       __pm_genpd_restore_device(dev->power.subsys_data->domain_data, genpd);
        genpd->resume_count--;
        genpd_set_active(genpd);
        wake_up_all(&genpd->status_wait_queue);
        mutex_unlock(&genpd->lock);
 
+ out:
        if (genpd->start_device)
                genpd->start_device(dev);
 
@@ -478,8 +526,6 @@ void pm_genpd_poweroff_unused(void)
 #else
 
 static inline void genpd_power_off_work_fn(struct work_struct *work) {}
-static inline void __pm_genpd_runtime_resume(struct device *dev,
-                                            struct generic_pm_domain *genpd) {}
 
 #define pm_genpd_runtime_suspend       NULL
 #define pm_genpd_runtime_resume                NULL
@@ -489,11 +535,11 @@ static inline void __pm_genpd_runtime_resume(struct device *dev,
 #ifdef CONFIG_PM_SLEEP
 
 /**
- * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its parents.
+ * pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
  * @genpd: PM domain to power off, if possible.
  *
  * Check if the given PM domain can be powered off (during system suspend or
- * hibernation) and do that if so.  Also, in that case propagate to its parent.
+ * hibernation) and do that if so.  Also, in that case propagate to its masters.
  *
  * This function is only called in "noirq" stages of system power transitions,
  * so it need not acquire locks (all of the "noirq" callbacks are executed
@@ -501,21 +547,23 @@ static inline void __pm_genpd_runtime_resume(struct device *dev,
  */
 static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
 {
-       struct generic_pm_domain *parent = genpd->parent;
+       struct gpd_link *link;
 
        if (genpd->status == GPD_STATE_POWER_OFF)
                return;
 
-       if (genpd->suspended_count != genpd->device_count || genpd->sd_count > 0)
+       if (genpd->suspended_count != genpd->device_count
+           || atomic_read(&genpd->sd_count) > 0)
                return;
 
        if (genpd->power_off)
                genpd->power_off(genpd);
 
        genpd->status = GPD_STATE_POWER_OFF;
-       if (parent) {
-               genpd_sd_counter_dec(parent);
-               pm_genpd_sync_poweroff(parent);
+
+       list_for_each_entry(link, &genpd->slave_links, slave_node) {
+               genpd_sd_counter_dec(link->master);
+               pm_genpd_sync_poweroff(link->master);
        }
 }
 
@@ -1034,7 +1082,8 @@ static void pm_genpd_complete(struct device *dev)
  */
 int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
 {
-       struct dev_list_entry *dle;
+       struct generic_pm_domain_data *gpd_data;
+       struct pm_domain_data *pdd;
        int ret = 0;
 
        dev_dbg(dev, "%s()\n", __func__);
@@ -1054,26 +1103,26 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
                goto out;
        }
 
-       list_for_each_entry(dle, &genpd->dev_list, node)
-               if (dle->dev == dev) {
+       list_for_each_entry(pdd, &genpd->dev_list, list_node)
+               if (pdd->dev == dev) {
                        ret = -EINVAL;
                        goto out;
                }
 
-       dle = kzalloc(sizeof(*dle), GFP_KERNEL);
-       if (!dle) {
+       gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
+       if (!gpd_data) {
                ret = -ENOMEM;
                goto out;
        }
 
-       dle->dev = dev;
-       dle->need_restore = false;
-       list_add_tail(&dle->node, &genpd->dev_list);
        genpd->device_count++;
 
-       spin_lock_irq(&dev->power.lock);
        dev->pm_domain = &genpd->domain;
-       spin_unlock_irq(&dev->power.lock);
+       dev_pm_get_subsys_data(dev);
+       dev->power.subsys_data->domain_data = &gpd_data->base;
+       gpd_data->base.dev = dev;
+       gpd_data->need_restore = false;
+       list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
 
  out:
        genpd_release_lock(genpd);
@@ -1089,7 +1138,7 @@ int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
 int pm_genpd_remove_device(struct generic_pm_domain *genpd,
                           struct device *dev)
 {
-       struct dev_list_entry *dle;
+       struct pm_domain_data *pdd;
        int ret = -EINVAL;
 
        dev_dbg(dev, "%s()\n", __func__);
@@ -1104,17 +1153,17 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
                goto out;
        }
 
-       list_for_each_entry(dle, &genpd->dev_list, node) {
-               if (dle->dev != dev)
+       list_for_each_entry(pdd, &genpd->dev_list, list_node) {
+               if (pdd->dev != dev)
                        continue;
 
-               spin_lock_irq(&dev->power.lock);
+               list_del_init(&pdd->list_node);
+               pdd->dev = NULL;
+               dev_pm_put_subsys_data(dev);
                dev->pm_domain = NULL;
-               spin_unlock_irq(&dev->power.lock);
+               kfree(to_gpd_data(pdd));
 
                genpd->device_count--;
-               list_del(&dle->node);
-               kfree(dle);
 
                ret = 0;
                break;
@@ -1129,48 +1178,55 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 /**
  * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
  * @genpd: Master PM domain to add the subdomain to.
- * @new_subdomain: Subdomain to be added.
+ * @subdomain: Subdomain to be added.
  */
 int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
-                          struct generic_pm_domain *new_subdomain)
+                          struct generic_pm_domain *subdomain)
 {
-       struct generic_pm_domain *subdomain;
+       struct gpd_link *link;
        int ret = 0;
 
-       if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(new_subdomain))
+       if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
                return -EINVAL;
 
  start:
        genpd_acquire_lock(genpd);
-       mutex_lock_nested(&new_subdomain->lock, SINGLE_DEPTH_NESTING);
+       mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
 
-       if (new_subdomain->status != GPD_STATE_POWER_OFF
-           && new_subdomain->status != GPD_STATE_ACTIVE) {
-               mutex_unlock(&new_subdomain->lock);
+       if (subdomain->status != GPD_STATE_POWER_OFF
+           && subdomain->status != GPD_STATE_ACTIVE) {
+               mutex_unlock(&subdomain->lock);
                genpd_release_lock(genpd);
                goto start;
        }
 
        if (genpd->status == GPD_STATE_POWER_OFF
-           &&  new_subdomain->status != GPD_STATE_POWER_OFF) {
+           &&  subdomain->status != GPD_STATE_POWER_OFF) {
                ret = -EINVAL;
                goto out;
        }
 
-       list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
-               if (subdomain == new_subdomain) {
+       list_for_each_entry(link, &genpd->slave_links, slave_node) {
+               if (link->slave == subdomain && link->master == genpd) {
                        ret = -EINVAL;
                        goto out;
                }
        }
 
-       list_add_tail(&new_subdomain->sd_node, &genpd->sd_list);
-       new_subdomain->parent = genpd;
+       link = kzalloc(sizeof(*link), GFP_KERNEL);
+       if (!link) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       link->master = genpd;
+       list_add_tail(&link->master_node, &genpd->master_links);
+       link->slave = subdomain;
+       list_add_tail(&link->slave_node, &subdomain->slave_links);
        if (subdomain->status != GPD_STATE_POWER_OFF)
-               genpd->sd_count++;
+               genpd_sd_counter_inc(genpd);
 
  out:
-       mutex_unlock(&new_subdomain->lock);
+       mutex_unlock(&subdomain->lock);
        genpd_release_lock(genpd);
 
        return ret;
@@ -1179,22 +1235,22 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
 /**
  * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
  * @genpd: Master PM domain to remove the subdomain from.
- * @target: Subdomain to be removed.
+ * @subdomain: Subdomain to be removed.
  */
 int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
-                             struct generic_pm_domain *target)
+                             struct generic_pm_domain *subdomain)
 {
-       struct generic_pm_domain *subdomain;
+       struct gpd_link *link;
        int ret = -EINVAL;
 
-       if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(target))
+       if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
                return -EINVAL;
 
  start:
        genpd_acquire_lock(genpd);
 
-       list_for_each_entry(subdomain, &genpd->sd_list, sd_node) {
-               if (subdomain != target)
+       list_for_each_entry(link, &genpd->master_links, master_node) {
+               if (link->slave != subdomain)
                        continue;
 
                mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
@@ -1206,8 +1262,9 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
                        goto start;
                }
 
-               list_del(&subdomain->sd_node);
-               subdomain->parent = NULL;
+               list_del(&link->master_node);
+               list_del(&link->slave_node);
+               kfree(link);
                if (subdomain->status != GPD_STATE_POWER_OFF)
                        genpd_sd_counter_dec(genpd);
 
@@ -1234,15 +1291,14 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
        if (IS_ERR_OR_NULL(genpd))
                return;
 
-       INIT_LIST_HEAD(&genpd->sd_node);
-       genpd->parent = NULL;
+       INIT_LIST_HEAD(&genpd->master_links);
+       INIT_LIST_HEAD(&genpd->slave_links);
        INIT_LIST_HEAD(&genpd->dev_list);
-       INIT_LIST_HEAD(&genpd->sd_list);
        mutex_init(&genpd->lock);
        genpd->gov = gov;
        INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn);
        genpd->in_progress = 0;
-       genpd->sd_count = 0;
+       atomic_set(&genpd->sd_count, 0);
        genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
        init_waitqueue_head(&genpd->status_wait_queue);
        genpd->poweroff_task = NULL;
index a854591..c6291ab 100644 (file)
@@ -65,6 +65,7 @@ void device_pm_init(struct device *dev)
        spin_lock_init(&dev->power.lock);
        pm_runtime_init(dev);
        INIT_LIST_HEAD(&dev->power.entry);
+       dev->power.power_state = PMSG_INVALID;
 }
 
 /**
@@ -96,6 +97,7 @@ void device_pm_add(struct device *dev)
                dev_warn(dev, "parent %s should not be sleeping\n",
                        dev_name(dev->parent));
        list_add_tail(&dev->power.entry, &dpm_list);
+       dev_pm_qos_constraints_init(dev);
        mutex_unlock(&dpm_list_mtx);
 }
 
@@ -109,6 +111,7 @@ void device_pm_remove(struct device *dev)
                 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
        complete_all(&dev->power.completion);
        mutex_lock(&dpm_list_mtx);
+       dev_pm_qos_constraints_destroy(dev);
        list_del_init(&dev->power.entry);
        mutex_unlock(&dpm_list_mtx);
        device_wakeup_disable(dev);
index f2a25f1..9bf6232 100644 (file)
@@ -1,3 +1,5 @@
+#include <linux/pm_qos.h>
+
 #ifdef CONFIG_PM_RUNTIME
 
 extern void pm_runtime_init(struct device *dev);
@@ -35,15 +37,21 @@ extern void device_pm_move_last(struct device *);
 static inline void device_pm_init(struct device *dev)
 {
        spin_lock_init(&dev->power.lock);
+       dev->power.power_state = PMSG_INVALID;
        pm_runtime_init(dev);
 }
 
+static inline void device_pm_add(struct device *dev)
+{
+       dev_pm_qos_constraints_init(dev);
+}
+
 static inline void device_pm_remove(struct device *dev)
 {
+       dev_pm_qos_constraints_destroy(dev);
        pm_runtime_remove(dev);
 }
 
-static inline void device_pm_add(struct device *dev) {}
 static inline void device_pm_move_before(struct device *deva,
                                         struct device *devb) {}
 static inline void device_pm_move_after(struct device *deva,
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
new file mode 100644 (file)
index 0000000..91e0614
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Devices PM QoS constraints management
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * 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 module exposes the interface to kernel space for specifying
+ * per-device PM QoS dependencies. It provides infrastructure for registration
+ * of:
+ *
+ * Dependents on a QoS value : register requests
+ * Watchers of QoS value : get notified when target QoS value changes
+ *
+ * This QoS design is best effort based. Dependents register their QoS needs.
+ * Watchers register to keep track of the current QoS needs of the system.
+ * Watchers can register different types of notification callbacks:
+ *  . a per-device notification callback using the dev_pm_qos_*_notifier API.
+ *    The notification chain data is stored in the per-device constraint
+ *    data struct.
+ *  . a system-wide notification callback using the dev_pm_qos_*_global_notifier
+ *    API. The notification chain data is stored in a static variable.
+ *
+ * Note about the per-device constraint data struct allocation:
+ * . The per-device constraints data struct ptr is tored into the device
+ *    dev_pm_info.
+ * . To minimize the data usage by the per-device constraints, the data struct
+ *   is only allocated at the first call to dev_pm_qos_add_request.
+ * . The data is later free'd when the device is removed from the system.
+ *  . A global mutex protects the constraints users from the data being
+ *     allocated and free'd.
+ */
+
+#include <linux/pm_qos.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+
+
+static DEFINE_MUTEX(dev_pm_qos_mtx);
+
+static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
+
+/**
+ * dev_pm_qos_read_value - Get PM QoS constraint for a given device.
+ * @dev: Device to get the PM QoS constraint value for.
+ */
+s32 dev_pm_qos_read_value(struct device *dev)
+{
+       struct pm_qos_constraints *c;
+       unsigned long flags;
+       s32 ret = 0;
+
+       spin_lock_irqsave(&dev->power.lock, flags);
+
+       c = dev->power.constraints;
+       if (c)
+               ret = pm_qos_read_value(c);
+
+       spin_unlock_irqrestore(&dev->power.lock, flags);
+
+       return ret;
+}
+
+/*
+ * apply_constraint
+ * @req: constraint request to apply
+ * @action: action to perform add/update/remove, of type enum pm_qos_req_action
+ * @value: defines the qos request
+ *
+ * Internal function to update the constraints list using the PM QoS core
+ * code and if needed call the per-device and the global notification
+ * callbacks
+ */
+static int apply_constraint(struct dev_pm_qos_request *req,
+                           enum pm_qos_req_action action, int value)
+{
+       int ret, curr_value;
+
+       ret = pm_qos_update_target(req->dev->power.constraints,
+                                  &req->node, action, value);
+
+       if (ret) {
+               /* Call the global callbacks if needed */
+               curr_value = pm_qos_read_value(req->dev->power.constraints);
+               blocking_notifier_call_chain(&dev_pm_notifiers,
+                                            (unsigned long)curr_value,
+                                            req);
+       }
+
+       return ret;
+}
+
+/*
+ * dev_pm_qos_constraints_allocate
+ * @dev: device to allocate data for
+ *
+ * Called at the first call to add_request, for constraint data allocation
+ * Must be called with the dev_pm_qos_mtx mutex held
+ */
+static int dev_pm_qos_constraints_allocate(struct device *dev)
+{
+       struct pm_qos_constraints *c;
+       struct blocking_notifier_head *n;
+
+       c = kzalloc(sizeof(*c), GFP_KERNEL);
+       if (!c)
+               return -ENOMEM;
+
+       n = kzalloc(sizeof(*n), GFP_KERNEL);
+       if (!n) {
+               kfree(c);
+               return -ENOMEM;
+       }
+       BLOCKING_INIT_NOTIFIER_HEAD(n);
+
+       plist_head_init(&c->list);
+       c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
+       c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
+       c->type = PM_QOS_MIN;
+       c->notifiers = n;
+
+       spin_lock_irq(&dev->power.lock);
+       dev->power.constraints = c;
+       spin_unlock_irq(&dev->power.lock);
+
+       return 0;
+}
+
+/**
+ * dev_pm_qos_constraints_init - Initalize device's PM QoS constraints pointer.
+ * @dev: target device
+ *
+ * Called from the device PM subsystem during device insertion under
+ * device_pm_lock().
+ */
+void dev_pm_qos_constraints_init(struct device *dev)
+{
+       mutex_lock(&dev_pm_qos_mtx);
+       dev->power.constraints = NULL;
+       dev->power.power_state = PMSG_ON;
+       mutex_unlock(&dev_pm_qos_mtx);
+}
+
+/**
+ * dev_pm_qos_constraints_destroy
+ * @dev: target device
+ *
+ * Called from the device PM subsystem on device removal under device_pm_lock().
+ */
+void dev_pm_qos_constraints_destroy(struct device *dev)
+{
+       struct dev_pm_qos_request *req, *tmp;
+       struct pm_qos_constraints *c;
+
+       mutex_lock(&dev_pm_qos_mtx);
+
+       dev->power.power_state = PMSG_INVALID;
+       c = dev->power.constraints;
+       if (!c)
+               goto out;
+
+       /* Flush the constraints list for the device */
+       plist_for_each_entry_safe(req, tmp, &c->list, node) {
+               /*
+                * Update constraints list and call the notification
+                * callbacks if needed
+                */
+               apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
+               memset(req, 0, sizeof(*req));
+       }
+
+       spin_lock_irq(&dev->power.lock);
+       dev->power.constraints = NULL;
+       spin_unlock_irq(&dev->power.lock);
+
+       kfree(c->notifiers);
+       kfree(c);
+
+ out:
+       mutex_unlock(&dev_pm_qos_mtx);
+}
+
+/**
+ * dev_pm_qos_add_request - inserts new qos request into the list
+ * @dev: target device for the constraint
+ * @req: pointer to a preallocated handle
+ * @value: defines the qos request
+ *
+ * This function inserts a new entry in the device constraints list of
+ * requested qos performance characteristics. It recomputes the aggregate
+ * QoS expectations of parameters and initializes the dev_pm_qos_request
+ * handle.  Caller needs to save this handle for later use in updates and
+ * removal.
+ *
+ * Returns 1 if the aggregated constraint value has changed,
+ * 0 if the aggregated constraint value has not changed,
+ * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
+ * to allocate for data structures, -ENODEV if the device has just been removed
+ * from the system.
+ */
+int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
+                          s32 value)
+{
+       int ret = 0;
+
+       if (!dev || !req) /*guard against callers passing in null */
+               return -EINVAL;
+
+       if (dev_pm_qos_request_active(req)) {
+               WARN(1, KERN_ERR "dev_pm_qos_add_request() called for already "
+                       "added request\n");
+               return -EINVAL;
+       }
+
+       req->dev = dev;
+
+       mutex_lock(&dev_pm_qos_mtx);
+
+       if (!dev->power.constraints) {
+               if (dev->power.power_state.event == PM_EVENT_INVALID) {
+                       /* The device has been removed from the system. */
+                       req->dev = NULL;
+                       ret = -ENODEV;
+                       goto out;
+               } else {
+                       /*
+                        * Allocate the constraints data on the first call to
+                        * add_request, i.e. only if the data is not already
+                        * allocated and if the device has not been removed.
+                        */
+                       ret = dev_pm_qos_constraints_allocate(dev);
+               }
+       }
+
+       if (!ret)
+               ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
+
+ out:
+       mutex_unlock(&dev_pm_qos_mtx);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
+
+/**
+ * dev_pm_qos_update_request - modifies an existing qos request
+ * @req : handle to list element holding a dev_pm_qos request to use
+ * @new_value: defines the qos request
+ *
+ * Updates an existing dev PM qos request along with updating the
+ * target value.
+ *
+ * Attempts are made to make this code callable on hot code paths.
+ *
+ * Returns 1 if the aggregated constraint value has changed,
+ * 0 if the aggregated constraint value has not changed,
+ * -EINVAL in case of wrong parameters, -ENODEV if the device has been
+ * removed from the system
+ */
+int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
+                             s32 new_value)
+{
+       int ret = 0;
+
+       if (!req) /*guard against callers passing in null */
+               return -EINVAL;
+
+       if (!dev_pm_qos_request_active(req)) {
+               WARN(1, KERN_ERR "dev_pm_qos_update_request() called for "
+                       "unknown object\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev_pm_qos_mtx);
+
+       if (req->dev->power.constraints) {
+               if (new_value != req->node.prio)
+                       ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
+                                              new_value);
+       } else {
+               /* Return if the device has been removed */
+               ret = -ENODEV;
+       }
+
+       mutex_unlock(&dev_pm_qos_mtx);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
+
+/**
+ * dev_pm_qos_remove_request - modifies an existing qos request
+ * @req: handle to request list element
+ *
+ * Will remove pm qos request from the list of constraints and
+ * recompute the current target value. Call this on slow code paths.
+ *
+ * Returns 1 if the aggregated constraint value has changed,
+ * 0 if the aggregated constraint value has not changed,
+ * -EINVAL in case of wrong parameters, -ENODEV if the device has been
+ * removed from the system
+ */
+int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
+{
+       int ret = 0;
+
+       if (!req) /*guard against callers passing in null */
+               return -EINVAL;
+
+       if (!dev_pm_qos_request_active(req)) {
+               WARN(1, KERN_ERR "dev_pm_qos_remove_request() called for "
+                       "unknown object\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev_pm_qos_mtx);
+
+       if (req->dev->power.constraints) {
+               ret = apply_constraint(req, PM_QOS_REMOVE_REQ,
+                                      PM_QOS_DEFAULT_VALUE);
+               memset(req, 0, sizeof(*req));
+       } else {
+               /* Return if the device has been removed */
+               ret = -ENODEV;
+       }
+
+       mutex_unlock(&dev_pm_qos_mtx);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
+
+/**
+ * dev_pm_qos_add_notifier - sets notification entry for changes to target value
+ * of per-device PM QoS constraints
+ *
+ * @dev: target device for the constraint
+ * @notifier: notifier block managed by caller.
+ *
+ * Will register the notifier into a notification chain that gets called
+ * upon changes to the target value for the device.
+ */
+int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
+{
+       int retval = 0;
+
+       mutex_lock(&dev_pm_qos_mtx);
+
+       /* Silently return if the constraints object is not present. */
+       if (dev->power.constraints)
+               retval = blocking_notifier_chain_register(
+                               dev->power.constraints->notifiers,
+                               notifier);
+
+       mutex_unlock(&dev_pm_qos_mtx);
+       return retval;
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
+
+/**
+ * dev_pm_qos_remove_notifier - deletes notification for changes to target value
+ * of per-device PM QoS constraints
+ *
+ * @dev: target device for the constraint
+ * @notifier: notifier block to be removed.
+ *
+ * Will remove the notifier from the notification chain that gets called
+ * upon changes to the target value.
+ */
+int dev_pm_qos_remove_notifier(struct device *dev,
+                              struct notifier_block *notifier)
+{
+       int retval = 0;
+
+       mutex_lock(&dev_pm_qos_mtx);
+
+       /* Silently return if the constraints object is not present. */
+       if (dev->power.constraints)
+               retval = blocking_notifier_chain_unregister(
+                               dev->power.constraints->notifiers,
+                               notifier);
+
+       mutex_unlock(&dev_pm_qos_mtx);
+       return retval;
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
+
+/**
+ * dev_pm_qos_add_global_notifier - sets notification entry for changes to
+ * target value of the PM QoS constraints for any device
+ *
+ * @notifier: notifier block managed by caller.
+ *
+ * Will register the notifier into a notification chain that gets called
+ * upon changes to the target value for any device.
+ */
+int dev_pm_qos_add_global_notifier(struct notifier_block *notifier)
+{
+       return blocking_notifier_chain_register(&dev_pm_notifiers, notifier);
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_add_global_notifier);
+
+/**
+ * dev_pm_qos_remove_global_notifier - deletes notification for changes to
+ * target value of PM QoS constraints for any device
+ *
+ * @notifier: notifier block to be removed.
+ *
+ * Will remove the notifier from the notification chain that gets called
+ * upon changes to the target value for any device.
+ */
+int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier)
+{
+       return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier);
+}
+EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
index acb3f83..7a6fb5e 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/sched.h>
 #include <linux/pm_runtime.h>
+#include <trace/events/rpm.h>
 #include "power.h"
 
 static int rpm_resume(struct device *dev, int rpmflags);
@@ -155,6 +156,31 @@ static int rpm_check_suspend_allowed(struct device *dev)
 }
 
 /**
+ * __rpm_callback - Run a given runtime PM callback for a given device.
+ * @cb: Runtime PM callback to run.
+ * @dev: Device to run the callback for.
+ */
+static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
+       __releases(&dev->power.lock) __acquires(&dev->power.lock)
+{
+       int retval;
+
+       if (dev->power.irq_safe)
+               spin_unlock(&dev->power.lock);
+       else
+               spin_unlock_irq(&dev->power.lock);
+
+       retval = cb(dev);
+
+       if (dev->power.irq_safe)
+               spin_lock(&dev->power.lock);
+       else
+               spin_lock_irq(&dev->power.lock);
+
+       return retval;
+}
+
+/**
  * rpm_idle - Notify device bus type if the device can be suspended.
  * @dev: Device to notify the bus type about.
  * @rpmflags: Flag bits.
@@ -171,6 +197,7 @@ static int rpm_idle(struct device *dev, int rpmflags)
        int (*callback)(struct device *);
        int retval;
 
+       trace_rpm_idle(dev, rpmflags);
        retval = rpm_check_suspend_allowed(dev);
        if (retval < 0)
                ;       /* Conditions are wrong. */
@@ -225,24 +252,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
        else
                callback = NULL;
 
-       if (callback) {
-               if (dev->power.irq_safe)
-                       spin_unlock(&dev->power.lock);
-               else
-                       spin_unlock_irq(&dev->power.lock);
-
-               callback(dev);
-
-               if (dev->power.irq_safe)
-                       spin_lock(&dev->power.lock);
-               else
-                       spin_lock_irq(&dev->power.lock);
-       }
+       if (callback)
+               __rpm_callback(callback, dev);
 
        dev->power.idle_notification = false;
        wake_up_all(&dev->power.wait_queue);
 
  out:
+       trace_rpm_return_int(dev, _THIS_IP_, retval);
        return retval;
 }
 
@@ -252,22 +269,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
  * @dev: Device to run the callback for.
  */
 static int rpm_callback(int (*cb)(struct device *), struct device *dev)
-       __releases(&dev->power.lock) __acquires(&dev->power.lock)
 {
        int retval;
 
        if (!cb)
                return -ENOSYS;
 
-       if (dev->power.irq_safe) {
-               retval = cb(dev);
-       } else {
-               spin_unlock_irq(&dev->power.lock);
-
-               retval = cb(dev);
+       retval = __rpm_callback(cb, dev);
 
-               spin_lock_irq(&dev->power.lock);
-       }
        dev->power.runtime_error = retval;
        return retval != -EACCES ? retval : -EIO;
 }
@@ -295,7 +304,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
        struct device *parent = NULL;
        int retval;
 
-       dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
+       trace_rpm_suspend(dev, rpmflags);
 
  repeat:
        retval = rpm_check_suspend_allowed(dev);
@@ -347,6 +356,15 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                        goto out;
                }
 
+               if (dev->power.irq_safe) {
+                       spin_unlock(&dev->power.lock);
+
+                       cpu_relax();
+
+                       spin_lock(&dev->power.lock);
+                       goto repeat;
+               }
+
                /* Wait for the other suspend running in parallel with us. */
                for (;;) {
                        prepare_to_wait(&dev->power.wait_queue, &wait,
@@ -430,7 +448,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
        }
 
  out:
-       dev_dbg(dev, "%s returns %d\n", __func__, retval);
+       trace_rpm_return_int(dev, _THIS_IP_, retval);
 
        return retval;
 }
@@ -459,7 +477,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
        struct device *parent = NULL;
        int retval = 0;
 
-       dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
+       trace_rpm_resume(dev, rpmflags);
 
  repeat:
        if (dev->power.runtime_error)
@@ -496,6 +514,15 @@ static int rpm_resume(struct device *dev, int rpmflags)
                        goto out;
                }
 
+               if (dev->power.irq_safe) {
+                       spin_unlock(&dev->power.lock);
+
+                       cpu_relax();
+
+                       spin_lock(&dev->power.lock);
+                       goto repeat;
+               }
+
                /* Wait for the operation carried out in parallel with us. */
                for (;;) {
                        prepare_to_wait(&dev->power.wait_queue, &wait,
@@ -615,7 +642,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
                spin_lock_irq(&dev->power.lock);
        }
 
-       dev_dbg(dev, "%s returns %d\n", __func__, retval);
+       trace_rpm_return_int(dev, _THIS_IP_, retval);
 
        return retval;
 }
@@ -732,13 +759,16 @@ EXPORT_SYMBOL_GPL(pm_schedule_suspend);
  * return immediately if it is larger than zero.  Then carry out an idle
  * notification, either synchronous or asynchronous.
  *
- * This routine may be called in atomic context if the RPM_ASYNC flag is set.
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set,
+ * or if pm_runtime_irq_safe() has been called.
  */
 int __pm_runtime_idle(struct device *dev, int rpmflags)
 {
        unsigned long flags;
        int retval;
 
+       might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
+
        if (rpmflags & RPM_GET_PUT) {
                if (!atomic_dec_and_test(&dev->power.usage_count))
                        return 0;
@@ -761,13 +791,16 @@ EXPORT_SYMBOL_GPL(__pm_runtime_idle);
  * return immediately if it is larger than zero.  Then carry out a suspend,
  * either synchronous or asynchronous.
  *
- * This routine may be called in atomic context if the RPM_ASYNC flag is set.
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set,
+ * or if pm_runtime_irq_safe() has been called.
  */
 int __pm_runtime_suspend(struct device *dev, int rpmflags)
 {
        unsigned long flags;
        int retval;
 
+       might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
+
        if (rpmflags & RPM_GET_PUT) {
                if (!atomic_dec_and_test(&dev->power.usage_count))
                        return 0;
@@ -789,13 +822,16 @@ EXPORT_SYMBOL_GPL(__pm_runtime_suspend);
  * If the RPM_GET_PUT flag is set, increment the device's usage count.  Then
  * carry out a resume, either synchronous or asynchronous.
  *
- * This routine may be called in atomic context if the RPM_ASYNC flag is set.
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set,
+ * or if pm_runtime_irq_safe() has been called.
  */
 int __pm_runtime_resume(struct device *dev, int rpmflags)
 {
        unsigned long flags;
        int retval;
 
+       might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
+
        if (rpmflags & RPM_GET_PUT)
                atomic_inc(&dev->power.usage_count);
 
index 9cbac6b..6767b4a 100644 (file)
@@ -1116,7 +1116,7 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
                return 0;
 
        spin_lock_irq(&data->txlock);
-       if (!((message.event & PM_EVENT_AUTO) && data->tx_in_flight)) {
+       if (!(PMSG_IS_AUTO(message) && data->tx_in_flight)) {
                set_bit(BTUSB_SUSPENDING, &data->flags);
                spin_unlock_irq(&data->txlock);
        } else {
index d4c5423..0df0141 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/notifier.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/cpu.h>
 #include <linux/cpuidle.h>
 #include <linux/ktime.h>
index 12c9890..f62fde2 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/cpuidle.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/moduleparam.h>
 #include <linux/jiffies.h>
 
index c47f3d0..3600f19 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/cpuidle.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/time.h>
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
index ce045a8..f07e425 100644 (file)
@@ -67,11 +67,11 @@ module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
 MODULE_PARM_DESC(i915_enable_rc6,
                "Enable power-saving render C-state 6 (default: true)");
 
-unsigned int i915_enable_fbc __read_mostly = 1;
+unsigned int i915_enable_fbc __read_mostly = -1;
 module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
 MODULE_PARM_DESC(i915_enable_fbc,
                "Enable frame buffer compression for power savings "
-               "(default: false)");
+               "(default: -1 (use per-chip default))");
 
 unsigned int i915_lvds_downclock __read_mostly = 0;
 module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
index 56a8554..04411ad 100644 (file)
@@ -1799,6 +1799,7 @@ static void intel_update_fbc(struct drm_device *dev)
        struct drm_framebuffer *fb;
        struct intel_framebuffer *intel_fb;
        struct drm_i915_gem_object *obj;
+       int enable_fbc;
 
        DRM_DEBUG_KMS("\n");
 
@@ -1839,8 +1840,15 @@ static void intel_update_fbc(struct drm_device *dev)
        intel_fb = to_intel_framebuffer(fb);
        obj = intel_fb->obj;
 
-       if (!i915_enable_fbc) {
-               DRM_DEBUG_KMS("fbc disabled per module param (default off)\n");
+       enable_fbc = i915_enable_fbc;
+       if (enable_fbc < 0) {
+               DRM_DEBUG_KMS("fbc set to per-chip default\n");
+               enable_fbc = 1;
+               if (INTEL_INFO(dev)->gen <= 5)
+                       enable_fbc = 0;
+       }
+       if (!enable_fbc) {
+               DRM_DEBUG_KMS("fbc disabled per module param\n");
                dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
                goto out_disable;
        }
@@ -4687,13 +4695,13 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
                bpc = 6; /* min is 18bpp */
                break;
        case 24:
-               bpc = min((unsigned int)8, display_bpc);
+               bpc = 8;
                break;
        case 30:
-               bpc = min((unsigned int)10, display_bpc);
+               bpc = 10;
                break;
        case 48:
-               bpc = min((unsigned int)12, display_bpc);
+               bpc = 12;
                break;
        default:
                DRM_DEBUG("unsupported depth, assuming 24 bits\n");
@@ -4701,10 +4709,12 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
                break;
        }
 
+       display_bpc = min(display_bpc, bpc);
+
        DRM_DEBUG_DRIVER("setting pipe bpc to %d (max display bpc %d)\n",
                         bpc, display_bpc);
 
-       *pipe_bpp = bpc * 3;
+       *pipe_bpp = display_bpc * 3;
 
        return display_bpc != bpc;
 }
index 0b2ee9d..fe1099d 100644 (file)
@@ -337,9 +337,6 @@ extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
                                           struct drm_connector *connector,
                                           struct intel_load_detect_pipe *old);
 
-extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
-extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
-extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable);
 extern void intelfb_restore(void);
 extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
                                    u16 blue, int regno);
index 30fe554..6348c49 100644 (file)
@@ -92,6 +92,11 @@ struct intel_sdvo {
        */
        uint16_t attached_output;
 
+       /*
+        * Hotplug activation bits for this device
+        */
+       uint8_t hotplug_active[2];
+
        /**
         * This is used to select the color range of RBG outputs in HDMI mode.
         * It is only valid when using TMDS encoding and 8 bit per color mode.
@@ -1208,74 +1213,20 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in
        return true;
 }
 
-/* No use! */
-#if 0
-struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB)
-{
-       struct drm_connector *connector = NULL;
-       struct intel_sdvo *iout = NULL;
-       struct intel_sdvo *sdvo;
-
-       /* find the sdvo connector */
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               iout = to_intel_sdvo(connector);
-
-               if (iout->type != INTEL_OUTPUT_SDVO)
-                       continue;
-
-               sdvo = iout->dev_priv;
-
-               if (sdvo->sdvo_reg == SDVOB && sdvoB)
-                       return connector;
-
-               if (sdvo->sdvo_reg == SDVOC && !sdvoB)
-                       return connector;
-
-       }
-
-       return NULL;
-}
-
-int intel_sdvo_supports_hotplug(struct drm_connector *connector)
+static int intel_sdvo_supports_hotplug(struct intel_sdvo *intel_sdvo)
 {
        u8 response[2];
-       u8 status;
-       struct intel_sdvo *intel_sdvo;
-       DRM_DEBUG_KMS("\n");
-
-       if (!connector)
-               return 0;
-
-       intel_sdvo = to_intel_sdvo(connector);
 
        return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
                                    &response, 2) && response[0];
 }
 
-void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
+static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
 {
-       u8 response[2];
-       u8 status;
-       struct intel_sdvo *intel_sdvo = to_intel_sdvo(connector);
-
-       intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
-       intel_sdvo_read_response(intel_sdvo, &response, 2);
-
-       if (on) {
-               intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
-               status = intel_sdvo_read_response(intel_sdvo, &response, 2);
-
-               intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
-       } else {
-               response[0] = 0;
-               response[1] = 0;
-               intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
-       }
+       struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
 
-       intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
-       intel_sdvo_read_response(intel_sdvo, &response, 2);
+       intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &intel_sdvo->hotplug_active, 2);
 }
-#endif
 
 static bool
 intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
@@ -2045,6 +1996,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
 {
        struct drm_encoder *encoder = &intel_sdvo->base.base;
        struct drm_connector *connector;
+       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
        struct intel_connector *intel_connector;
        struct intel_sdvo_connector *intel_sdvo_connector;
 
@@ -2062,7 +2014,17 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
 
        intel_connector = &intel_sdvo_connector->base;
        connector = &intel_connector->base;
-       connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
+       if (intel_sdvo_supports_hotplug(intel_sdvo) & (1 << device)) {
+               connector->polled = DRM_CONNECTOR_POLL_HPD;
+               intel_sdvo->hotplug_active[0] |= 1 << device;
+               /* Some SDVO devices have one-shot hotplug interrupts.
+                * Ensure that they get re-enabled when an interrupt happens.
+                */
+               intel_encoder->hot_plug = intel_sdvo_enable_hotplug;
+               intel_sdvo_enable_hotplug(intel_encoder);
+       }
+       else
+               connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
        encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
        connector->connector_type = DRM_MODE_CONNECTOR_DVID;
 
@@ -2569,6 +2531,14 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
        if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
                goto err;
 
+       /* Set up hotplug command - note paranoia about contents of reply.
+        * We assume that the hardware is in a sane state, and only touch
+        * the bits we think we understand.
+        */
+       intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG,
+                            &intel_sdvo->hotplug_active, 2);
+       intel_sdvo->hotplug_active[0] &= ~0x3;
+
        if (intel_sdvo_output_setup(intel_sdvo,
                                    intel_sdvo->caps.output_flags) != true) {
                DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
index 7ad43c6..4da2388 100644 (file)
@@ -115,6 +115,7 @@ static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
        u8 msg[20];
        int msg_bytes = send_bytes + 4;
        u8 ack;
+       unsigned retry;
 
        if (send_bytes > 16)
                return -1;
@@ -125,20 +126,20 @@ static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
        msg[3] = (msg_bytes << 4) | (send_bytes - 1);
        memcpy(&msg[4], send, send_bytes);
 
-       while (1) {
+       for (retry = 0; retry < 4; retry++) {
                ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
                                            msg, msg_bytes, NULL, 0, delay, &ack);
                if (ret < 0)
                        return ret;
                if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
-                       break;
+                       return send_bytes;
                else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
                        udelay(400);
                else
                        return -EIO;
        }
 
-       return send_bytes;
+       return -EIO;
 }
 
 static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
@@ -149,26 +150,29 @@ static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
        int msg_bytes = 4;
        u8 ack;
        int ret;
+       unsigned retry;
 
        msg[0] = address;
        msg[1] = address >> 8;
        msg[2] = AUX_NATIVE_READ << 4;
        msg[3] = (msg_bytes << 4) | (recv_bytes - 1);
 
-       while (1) {
+       for (retry = 0; retry < 4; retry++) {
                ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
                                            msg, msg_bytes, recv, recv_bytes, delay, &ack);
-               if (ret == 0)
-                       return -EPROTO;
                if (ret < 0)
                        return ret;
                if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
                        return ret;
                else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
                        udelay(400);
+               else if (ret == 0)
+                       return -EPROTO;
                else
                        return -EIO;
        }
+
+       return -EIO;
 }
 
 static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector,
index e8a7467..c4ffa14 100644 (file)
@@ -1590,48 +1590,6 @@ static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
        return backend_map;
 }
 
-static void evergreen_program_channel_remap(struct radeon_device *rdev)
-{
-       u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp;
-
-       tmp = RREG32(MC_SHARED_CHMAP);
-       switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
-       case 0:
-       case 1:
-       case 2:
-       case 3:
-       default:
-               /* default mapping */
-               mc_shared_chremap = 0x00fac688;
-               break;
-       }
-
-       switch (rdev->family) {
-       case CHIP_HEMLOCK:
-       case CHIP_CYPRESS:
-       case CHIP_BARTS:
-               tcp_chan_steer_lo = 0x54763210;
-               tcp_chan_steer_hi = 0x0000ba98;
-               break;
-       case CHIP_JUNIPER:
-       case CHIP_REDWOOD:
-       case CHIP_CEDAR:
-       case CHIP_PALM:
-       case CHIP_SUMO:
-       case CHIP_SUMO2:
-       case CHIP_TURKS:
-       case CHIP_CAICOS:
-       default:
-               tcp_chan_steer_lo = 0x76543210;
-               tcp_chan_steer_hi = 0x0000ba98;
-               break;
-       }
-
-       WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo);
-       WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi);
-       WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
 static void evergreen_gpu_init(struct radeon_device *rdev)
 {
        u32 cc_rb_backend_disable = 0;
@@ -2078,8 +2036,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
        WREG32(HDP_ADDR_CONFIG, gb_addr_config);
 
-       evergreen_program_channel_remap(rdev);
-
        num_shader_engines = ((RREG32(GB_ADDR_CONFIG) & NUM_SHADER_ENGINES(3)) >> 12) + 1;
        grbm_gfx_index = INSTANCE_BROADCAST_WRITES;
 
index 99fbd79..8c79ca9 100644 (file)
@@ -569,36 +569,6 @@ static u32 cayman_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
        return backend_map;
 }
 
-static void cayman_program_channel_remap(struct radeon_device *rdev)
-{
-       u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp;
-
-       tmp = RREG32(MC_SHARED_CHMAP);
-       switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
-       case 0:
-       case 1:
-       case 2:
-       case 3:
-       default:
-               /* default mapping */
-               mc_shared_chremap = 0x00fac688;
-               break;
-       }
-
-       switch (rdev->family) {
-       case CHIP_CAYMAN:
-       default:
-               //tcp_chan_steer_lo = 0x54763210
-               tcp_chan_steer_lo = 0x76543210;
-               tcp_chan_steer_hi = 0x0000ba98;
-               break;
-       }
-
-       WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo);
-       WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi);
-       WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
 static u32 cayman_get_disable_mask_per_asic(struct radeon_device *rdev,
                                            u32 disable_mask_per_se,
                                            u32 max_disable_mask_per_se,
@@ -842,8 +812,6 @@ static void cayman_gpu_init(struct radeon_device *rdev)
        WREG32(DMIF_ADDR_CONFIG, gb_addr_config);
        WREG32(HDP_ADDR_CONFIG, gb_addr_config);
 
-       cayman_program_channel_remap(rdev);
-
        /* primary versions */
        WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable);
        WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable);
index c4b8741..bce63fd 100644 (file)
@@ -68,11 +68,11 @@ void radeon_connector_hotplug(struct drm_connector *connector)
        if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
                int saved_dpms = connector->dpms;
 
-               if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
-                   radeon_dp_needs_link_train(radeon_connector))
-                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
-               else
+               /* Only turn off the display it it's physically disconnected */
+               if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
                        drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+               else if (radeon_dp_needs_link_train(radeon_connector))
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
                connector->dpms = saved_dpms;
        }
 }
index 3189a7e..fde25c0 100644 (file)
@@ -208,23 +208,25 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
        int xorigin = 0, yorigin = 0;
        int w = radeon_crtc->cursor_width;
 
-       if (x < 0)
-               xorigin = -x + 1;
-       if (y < 0)
-               yorigin = -y + 1;
-       if (xorigin >= CURSOR_WIDTH)
-               xorigin = CURSOR_WIDTH - 1;
-       if (yorigin >= CURSOR_HEIGHT)
-               yorigin = CURSOR_HEIGHT - 1;
-
        if (ASIC_IS_AVIVO(rdev)) {
-               int i = 0;
-               struct drm_crtc *crtc_p;
-
                /* avivo cursor are offset into the total surface */
                x += crtc->x;
                y += crtc->y;
-               DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
+       }
+       DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
+
+       if (x < 0) {
+               xorigin = min(-x, CURSOR_WIDTH - 1);
+               x = 0;
+       }
+       if (y < 0) {
+               yorigin = min(-y, CURSOR_HEIGHT - 1);
+               y = 0;
+       }
+
+       if (ASIC_IS_AVIVO(rdev)) {
+               int i = 0;
+               struct drm_crtc *crtc_p;
 
                /* avivo cursor image can't end on 128 pixel boundary or
                 * go past the end of the frame if both crtcs are enabled
@@ -253,16 +255,12 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
 
        radeon_lock_cursor(crtc, true);
        if (ASIC_IS_DCE4(rdev)) {
-               WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset,
-                      ((xorigin ? 0 : x) << 16) |
-                      (yorigin ? 0 : y));
+               WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
                WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
                WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset,
                       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
        } else if (ASIC_IS_AVIVO(rdev)) {
-               WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset,
-                            ((xorigin ? 0 : x) << 16) |
-                            (yorigin ? 0 : y));
+               WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y);
                WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
                WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
                       ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
@@ -276,8 +274,8 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
                        | yorigin));
                WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
                       (RADEON_CUR_LOCK
-                       | ((xorigin ? 0 : x) << 16)
-                       | (yorigin ? 0 : y)));
+                       | (x << 16)
+                       | y));
                /* offset is from DISP(2)_BASE_ADDRESS */
                WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset +
                                                                      (yorigin * 256)));
index 4720d00..b13c2ee 100644 (file)
@@ -536,55 +536,6 @@ static u32 r700_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
        return backend_map;
 }
 
-static void rv770_program_channel_remap(struct radeon_device *rdev)
-{
-       u32 tcp_chan_steer, mc_shared_chremap, tmp;
-       bool force_no_swizzle;
-
-       switch (rdev->family) {
-       case CHIP_RV770:
-       case CHIP_RV730:
-               force_no_swizzle = false;
-               break;
-       case CHIP_RV710:
-       case CHIP_RV740:
-       default:
-               force_no_swizzle = true;
-               break;
-       }
-
-       tmp = RREG32(MC_SHARED_CHMAP);
-       switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
-       case 0:
-       case 1:
-       default:
-               /* default mapping */
-               mc_shared_chremap = 0x00fac688;
-               break;
-       case 2:
-       case 3:
-               if (force_no_swizzle)
-                       mc_shared_chremap = 0x00fac688;
-               else
-                       mc_shared_chremap = 0x00bbc298;
-               break;
-       }
-
-       if (rdev->family == CHIP_RV740)
-               tcp_chan_steer = 0x00ef2a60;
-       else
-               tcp_chan_steer = 0x00fac688;
-
-       /* RV770 CE has special chremap setup */
-       if (rdev->pdev->device == 0x944e) {
-               tcp_chan_steer = 0x00b08b08;
-               mc_shared_chremap = 0x00b08b08;
-       }
-
-       WREG32(TCP_CHAN_STEER, tcp_chan_steer);
-       WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
-}
-
 static void rv770_gpu_init(struct radeon_device *rdev)
 {
        int i, j, num_qd_pipes;
@@ -785,8 +736,6 @@ static void rv770_gpu_init(struct radeon_device *rdev)
        WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff));
        WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff));
 
-       rv770_program_channel_remap(rdev);
-
        WREG32(CC_RB_BACKEND_DISABLE,      cc_rb_backend_disable);
        WREG32(CC_GC_SHADER_PIPE_CONFIG,   cc_gc_shader_pipe_config);
        WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config);
index 9d8710f..1782693 100644 (file)
@@ -2409,7 +2409,7 @@ static int picolcd_raw_event(struct hid_device *hdev,
 #ifdef CONFIG_PM
 static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
 {
-       if (message.event & PM_EVENT_AUTO)
+       if (PMSG_IS_AUTO(message))
                return 0;
 
        picolcd_suspend_backlight(hid_get_drvdata(hdev));
index ad978f5..a9fa294 100644 (file)
@@ -1332,7 +1332,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
        struct usbhid_device *usbhid = hid->driver_data;
        int status;
 
-       if (message.event & PM_EVENT_AUTO) {
+       if (PMSG_IS_AUTO(message)) {
                spin_lock_irq(&usbhid->lock);   /* Sync with error handler */
                if (!test_bit(HID_RESET_PENDING, &usbhid->iofl)
                    && !test_bit(HID_CLEAR_HALT, &usbhid->iofl)
@@ -1367,7 +1367,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
                        return -EIO;
        }
 
-       if (!ignoreled && (message.event & PM_EVENT_AUTO)) {
+       if (!ignoreled && PMSG_IS_AUTO(message)) {
                spin_lock_irq(&usbhid->lock);
                if (test_bit(HID_LED_ON, &usbhid->iofl)) {
                        spin_unlock_irq(&usbhid->lock);
@@ -1380,8 +1380,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
        hid_cancel_delayed_stuff(usbhid);
        hid_cease_io(usbhid);
 
-       if ((message.event & PM_EVENT_AUTO) &&
-                       test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
+       if (PMSG_IS_AUTO(message) && test_bit(HID_KEYS_PRESSED, &usbhid->iofl)) {
                /* lost race against keypresses */
                status = hid_start_in(hid);
                if (status < 0)
index 44b2391..9323837 100644 (file)
@@ -377,9 +377,9 @@ exit_free:
 }
 
 
-static int __devinit chk_ucode_version(struct platform_device *pdev)
+static int __cpuinit chk_ucode_version(unsigned int cpu)
 {
-       struct cpuinfo_x86 *c = &cpu_data(pdev->id);
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
        int err;
        u32 edx;
 
@@ -390,17 +390,15 @@ static int __devinit chk_ucode_version(struct platform_device *pdev)
         */
        if (c->x86_model == 0xe && c->x86_mask < 0xc) {
                /* check for microcode update */
-               err = smp_call_function_single(pdev->id, get_ucode_rev_on_cpu,
+               err = smp_call_function_single(cpu, get_ucode_rev_on_cpu,
                                               &edx, 1);
                if (err) {
-                       dev_err(&pdev->dev,
-                               "Cannot determine microcode revision of "
-                               "CPU#%u (%d)!\n", pdev->id, err);
+                       pr_err("Cannot determine microcode revision of "
+                              "CPU#%u (%d)!\n", cpu, err);
                        return -ENODEV;
                } else if (edx < 0x39) {
-                       dev_err(&pdev->dev,
-                               "Errata AE18 not fixed, update BIOS or "
-                               "microcode of the CPU!\n");
+                       pr_err("Errata AE18 not fixed, update BIOS or "
+                              "microcode of the CPU!\n");
                        return -ENODEV;
                }
        }
@@ -508,6 +506,7 @@ static int create_core_data(struct platform_device *pdev,
 
        return 0;
 exit_free:
+       pdata->core_data[attr_no] = NULL;
        kfree(tdata);
        return err;
 }
@@ -544,11 +543,6 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
        struct platform_data *pdata;
        int err;
 
-       /* Check the microcode version of the CPU */
-       err = chk_ucode_version(pdev);
-       if (err)
-               return err;
-
        /* Initialize the per-package data structures */
        pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL);
        if (!pdata)
@@ -630,7 +624,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
        }
 
        pdev_entry->pdev = pdev;
-       pdev_entry->phys_proc_id = TO_PHYS_ID(cpu);
+       pdev_entry->phys_proc_id = pdev->id;
 
        list_add_tail(&pdev_entry->list, &pdev_list);
        mutex_unlock(&pdev_list_mutex);
@@ -691,6 +685,10 @@ static void __cpuinit get_core_online(unsigned int cpu)
                return;
 
        if (!pdev) {
+               /* Check the microcode version of the CPU */
+               if (chk_ucode_version(cpu))
+                       return;
+
                /*
                 * Alright, we have DTS support.
                 * We are bringing the _first_ core in this pkg
index 2747980..16f69be 100644 (file)
@@ -435,7 +435,12 @@ static int idedisk_prep_fn(struct request_queue *q, struct request *rq)
        if (!(rq->cmd_flags & REQ_FLUSH))
                return BLKPREP_OK;
 
-       cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+       if (rq->special) {
+               cmd = rq->special;
+               memset(cmd, 0, sizeof(*cmd));
+       } else {
+               cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+       }
 
        /* FIXME: map struct ide_taskfile on rq->cmd[] */
        BUG_ON(cmd == NULL);
index 17bf9d9..6cd642a 100644 (file)
@@ -287,7 +287,7 @@ void __free_ep(struct kref *kref)
        if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) {
                cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid);
                dst_release(ep->dst);
-               l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+               l2t_release(ep->com.tdev, ep->l2t);
        }
        kfree(ep);
 }
@@ -1178,7 +1178,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
                release_tid(ep->com.tdev, GET_TID(rpl), NULL);
        cxgb3_free_atid(ep->com.tdev, ep->atid);
        dst_release(ep->dst);
-       l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+       l2t_release(ep->com.tdev, ep->l2t);
        put_ep(&ep->com);
        return CPL_RET_BUF_DONE;
 }
@@ -1377,7 +1377,7 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
        if (!child_ep) {
                printk(KERN_ERR MOD "%s - failed to allocate ep entry!\n",
                       __func__);
-               l2t_release(L2DATA(tdev), l2t);
+               l2t_release(tdev, l2t);
                dst_release(dst);
                goto reject;
        }
@@ -1956,7 +1956,7 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
        if (!err)
                goto out;
 
-       l2t_release(L2DATA(h->rdev.t3cdev_p), ep->l2t);
+       l2t_release(h->rdev.t3cdev_p, ep->l2t);
 fail4:
        dst_release(ep->dst);
 fail3:
@@ -2127,7 +2127,7 @@ int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new,
        PDBG("%s ep %p redirect to dst %p l2t %p\n", __func__, ep, new,
             l2t);
        dst_hold(new);
-       l2t_release(L2DATA(ep->com.tdev), ep->l2t);
+       l2t_release(ep->com.tdev, ep->l2t);
        ep->l2t = l2t;
        dst_release(old);
        ep->dst = new;
index 0dc97ec..9dea718 100644 (file)
@@ -1124,11 +1124,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
                for (i = 0; i < 8; i++)
                        __set_bit(BTN_0 + i, input_dev->keybit);
 
-               if (wacom_wac->features.type != WACOM_21UX2) {
-                       input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
-                       input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
-               }
-
+               input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
+               input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
                input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
 
                __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
index 49da55c..8c2a000 100644 (file)
@@ -1698,6 +1698,8 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
 
        ti->num_flush_requests = 1;
+       ti->discard_zeroes_data_unsupported = 1;
+
        return 0;
 
 bad:
index 89f73ca..f84c080 100644 (file)
@@ -81,8 +81,10 @@ static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
                 * corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>
                 */
                if (!strcasecmp(arg_name, "corrupt_bio_byte")) {
-                       if (!argc)
+                       if (!argc) {
                                ti->error = "Feature corrupt_bio_byte requires parameters";
+                               return -EINVAL;
+                       }
 
                        r = dm_read_arg(_args + 1, as, &fc->corrupt_bio_byte, &ti->error);
                        if (r)
index a002dd8..86df8b2 100644 (file)
@@ -449,7 +449,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
                                rs->ti->error = "write_mostly option is only valid for RAID1";
                                return -EINVAL;
                        }
-                       if (value > rs->md.raid_disks) {
+                       if (value >= rs->md.raid_disks) {
                                rs->ti->error = "Invalid write_mostly drive index given";
                                return -EINVAL;
                        }
index 986b875..bc04518 100644 (file)
@@ -1238,14 +1238,15 @@ static void dm_table_set_integrity(struct dm_table *t)
                return;
 
        template_disk = dm_table_get_integrity_disk(t, true);
-       if (!template_disk &&
-           blk_integrity_is_initialized(dm_disk(t->md))) {
+       if (template_disk)
+               blk_integrity_register(dm_disk(t->md),
+                                      blk_get_integrity(template_disk));
+       else if (blk_integrity_is_initialized(dm_disk(t->md)))
                DMWARN("%s: device no longer has a valid integrity profile",
                       dm_device_name(t->md));
-               return;
-       }
-       blk_integrity_register(dm_disk(t->md),
-                              blk_get_integrity(template_disk));
+       else
+               DMWARN("%s: unable to establish an integrity profile",
+                      dm_device_name(t->md));
 }
 
 static int device_flush_capable(struct dm_target *ti, struct dm_dev *dev,
@@ -1282,6 +1283,22 @@ static bool dm_table_supports_flush(struct dm_table *t, unsigned flush)
        return 0;
 }
 
+static bool dm_table_discard_zeroes_data(struct dm_table *t)
+{
+       struct dm_target *ti;
+       unsigned i = 0;
+
+       /* Ensure that all targets supports discard_zeroes_data. */
+       while (i < dm_table_get_num_targets(t)) {
+               ti = dm_table_get_target(t, i++);
+
+               if (ti->discard_zeroes_data_unsupported)
+                       return 0;
+       }
+
+       return 1;
+}
+
 void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
                               struct queue_limits *limits)
 {
@@ -1304,6 +1321,9 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
        }
        blk_queue_flush(q, flush);
 
+       if (!dm_table_discard_zeroes_data(t))
+               q->limits.discard_zeroes_data = 0;
+
        dm_table_set_integrity(t);
 
        /*
index 5404b22..5c95ccb 100644 (file)
 static void autostart_arrays(int part);
 #endif
 
+/* pers_list is a list of registered personalities protected
+ * by pers_lock.
+ * pers_lock does extra service to protect accesses to
+ * mddev->thread when the mutex cannot be held.
+ */
 static LIST_HEAD(pers_list);
 static DEFINE_SPINLOCK(pers_lock);
 
@@ -739,7 +744,12 @@ static void mddev_unlock(mddev_t * mddev)
        } else
                mutex_unlock(&mddev->reconfig_mutex);
 
+       /* was we've dropped the mutex we need a spinlock to
+        * make sur the thread doesn't disappear
+        */
+       spin_lock(&pers_lock);
        md_wakeup_thread(mddev->thread);
+       spin_unlock(&pers_lock);
 }
 
 static mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr)
@@ -6429,11 +6439,18 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev,
        return thread;
 }
 
-void md_unregister_thread(mdk_thread_t *thread)
+void md_unregister_thread(mdk_thread_t **threadp)
 {
+       mdk_thread_t *thread = *threadp;
        if (!thread)
                return;
        dprintk("interrupting MD-thread pid %d\n", task_pid_nr(thread->tsk));
+       /* Locking ensures that mddev_unlock does not wake_up a
+        * non-existent thread
+        */
+       spin_lock(&pers_lock);
+       *threadp = NULL;
+       spin_unlock(&pers_lock);
 
        kthread_stop(thread->tsk);
        kfree(thread);
@@ -7340,8 +7357,7 @@ static void reap_sync_thread(mddev_t *mddev)
        mdk_rdev_t *rdev;
 
        /* resync has finished, collect result */
-       md_unregister_thread(mddev->sync_thread);
-       mddev->sync_thread = NULL;
+       md_unregister_thread(&mddev->sync_thread);
        if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
            !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
                /* success...*/
index 1e586bb..0a309dc 100644 (file)
@@ -560,7 +560,7 @@ extern int register_md_personality(struct mdk_personality *p);
 extern int unregister_md_personality(struct mdk_personality *p);
 extern mdk_thread_t * md_register_thread(void (*run) (mddev_t *mddev),
                                mddev_t *mddev, const char *name);
-extern void md_unregister_thread(mdk_thread_t *thread);
+extern void md_unregister_thread(mdk_thread_t **threadp);
 extern void md_wakeup_thread(mdk_thread_t *thread);
 extern void md_check_recovery(mddev_t *mddev);
 extern void md_write_start(mddev_t *mddev, struct bio *bi);
index 3535c23..d5b5fb3 100644 (file)
@@ -514,8 +514,7 @@ static int multipath_stop (mddev_t *mddev)
 {
        multipath_conf_t *conf = mddev->private;
 
-       md_unregister_thread(mddev->thread);
-       mddev->thread = NULL;
+       md_unregister_thread(&mddev->thread);
        blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
        mempool_destroy(conf->pool);
        kfree(conf->multipaths);
index f4622dd..d9587df 100644 (file)
@@ -2562,8 +2562,7 @@ static int stop(mddev_t *mddev)
        raise_barrier(conf);
        lower_barrier(conf);
 
-       md_unregister_thread(mddev->thread);
-       mddev->thread = NULL;
+       md_unregister_thread(&mddev->thread);
        if (conf->r1bio_pool)
                mempool_destroy(conf->r1bio_pool);
        kfree(conf->mirrors);
index d7a8468..0cd9672 100644 (file)
@@ -2955,7 +2955,7 @@ static int run(mddev_t *mddev)
        return 0;
 
 out_free_conf:
-       md_unregister_thread(mddev->thread);
+       md_unregister_thread(&mddev->thread);
        if (conf->r10bio_pool)
                mempool_destroy(conf->r10bio_pool);
        safe_put_page(conf->tmppage);
@@ -2973,8 +2973,7 @@ static int stop(mddev_t *mddev)
        raise_barrier(conf, 0);
        lower_barrier(conf);
 
-       md_unregister_thread(mddev->thread);
-       mddev->thread = NULL;
+       md_unregister_thread(&mddev->thread);
        blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
        if (conf->r10bio_pool)
                mempool_destroy(conf->r10bio_pool);
index 43709fa..ac5e8b5 100644 (file)
@@ -4941,8 +4941,7 @@ static int run(mddev_t *mddev)
 
        return 0;
 abort:
-       md_unregister_thread(mddev->thread);
-       mddev->thread = NULL;
+       md_unregister_thread(&mddev->thread);
        if (conf) {
                print_raid5_conf(conf);
                free_conf(conf);
@@ -4956,8 +4955,7 @@ static int stop(mddev_t *mddev)
 {
        raid5_conf_t *conf = mddev->private;
 
-       md_unregister_thread(mddev->thread);
-       mddev->thread = NULL;
+       md_unregister_thread(&mddev->thread);
        if (mddev->queue)
                mddev->queue->backing_dev_info.congested_fn = NULL;
        free_conf(conf);
index b5ef362..b3a5ecd 100644 (file)
@@ -2194,19 +2194,6 @@ static int __init omap_vout_probe(struct platform_device *pdev)
                                        "'%s' Display already enabled\n",
                                        def_display->name);
                        }
-                       /* set the update mode */
-                       if (def_display->caps &
-                                       OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-                               if (dssdrv->enable_te)
-                                       dssdrv->enable_te(def_display, 0);
-                               if (dssdrv->set_update_mode)
-                                       dssdrv->set_update_mode(def_display,
-                                                       OMAP_DSS_UPDATE_MANUAL);
-                       } else {
-                               if (dssdrv->set_update_mode)
-                                       dssdrv->set_update_mode(def_display,
-                                                       OMAP_DSS_UPDATE_AUTO);
-                       }
                }
        }
 
index 9d3459d..80796eb 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
+#include <linux/slab.h>
 #include <media/v4l2-event.h>
 
 #include "isp.h"
index d29f9c2..e4100b1 100644 (file)
@@ -1961,7 +1961,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
 
        list_for_each_entry(stream, &dev->streams, list) {
                if (stream->intf == intf)
-                       return uvc_video_resume(stream);
+                       return uvc_video_resume(stream, reset);
        }
 
        uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
index 48fea37..29e2399 100644 (file)
@@ -49,7 +49,7 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain,
                if (remote == NULL)
                        return -EINVAL;
 
-               source = (UVC_ENTITY_TYPE(remote) != UVC_TT_STREAMING)
+               source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
                       ? (remote->vdev ? &remote->vdev->entity : NULL)
                       : &remote->subdev.entity;
                if (source == NULL)
index 8244167..ffd1158 100644 (file)
@@ -1104,10 +1104,18 @@ int uvc_video_suspend(struct uvc_streaming *stream)
  * buffers, making sure userspace applications are notified of the problem
  * instead of waiting forever.
  */
-int uvc_video_resume(struct uvc_streaming *stream)
+int uvc_video_resume(struct uvc_streaming *stream, int reset)
 {
        int ret;
 
+       /* If the bus has been reset on resume, set the alternate setting to 0.
+        * This should be the default value, but some devices crash or otherwise
+        * misbehave if they don't receive a SET_INTERFACE request before any
+        * other video control request.
+        */
+       if (reset)
+               usb_set_interface(stream->dev->udev, stream->intfnum, 0);
+
        stream->frozen = 0;
 
        ret = uvc_commit_video(stream, &stream->ctrl);
index df32a43..cbdd49b 100644 (file)
@@ -638,7 +638,7 @@ extern void uvc_mc_cleanup_entity(struct uvc_entity *entity);
 /* Video */
 extern int uvc_video_init(struct uvc_streaming *stream);
 extern int uvc_video_suspend(struct uvc_streaming *stream);
-extern int uvc_video_resume(struct uvc_streaming *stream);
+extern int uvc_video_resume(struct uvc_streaming *stream, int reset);
 extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
 extern int uvc_probe_video(struct uvc_streaming *stream,
                struct uvc_streaming_control *probe);
index 06f1400..d721565 100644 (file)
@@ -173,6 +173,17 @@ static void v4l2_device_release(struct device *cd)
                media_device_unregister_entity(&vdev->entity);
 #endif
 
+       /* Do not call v4l2_device_put if there is no release callback set.
+        * Drivers that have no v4l2_device release callback might free the
+        * v4l2_dev instance in the video_device release callback below, so we
+        * must perform this check here.
+        *
+        * TODO: In the long run all drivers that use v4l2_device should use the
+        * v4l2_device release callback. This check will then be unnecessary.
+        */
+       if (v4l2_dev->release == NULL)
+               v4l2_dev = NULL;
+
        /* Release video_device and perform other
           cleanups as needed. */
        vdev->release(vdev);
index c72856c..e6a2c3b 100644 (file)
@@ -38,6 +38,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
        mutex_init(&v4l2_dev->ioctl_lock);
        v4l2_prio_init(&v4l2_dev->prio);
        kref_init(&v4l2_dev->ref);
+       get_device(dev);
        v4l2_dev->dev = dev;
        if (dev == NULL) {
                /* If dev == NULL, then name must be filled in by the caller */
@@ -93,6 +94,7 @@ void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
 
        if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev)
                dev_set_drvdata(v4l2_dev->dev, NULL);
+       put_device(v4l2_dev->dev);
        v4l2_dev->dev = NULL;
 }
 EXPORT_SYMBOL_GPL(v4l2_device_disconnect);
index bb7f17f..cbf13d0 100644 (file)
@@ -21,7 +21,7 @@
 #include <media/videobuf-dma-sg.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/via-core.h>
 #include <linux/via-gpio.h>
 #include <linux/via_i2c.h>
@@ -69,7 +69,7 @@ struct via_camera {
        struct mutex lock;
        enum viacam_opstate opstate;
        unsigned long flags;
-       struct pm_qos_request_list qos_request;
+       struct pm_qos_request qos_request;
        /*
         * GPIO info for power/reset management
         */
index 21131c7..563654c 100644 (file)
@@ -273,7 +273,7 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev)
        ct->regs.ack = JZ_REG_ADC_STATUS;
        ct->chip.irq_mask = irq_gc_mask_set_bit;
        ct->chip.irq_unmask = irq_gc_mask_clr_bit;
-       ct->chip.irq_ack = irq_gc_ack;
+       ct->chip.irq_ack = irq_gc_ack_set_bit;
 
        irq_setup_generic_chip(gc, IRQ_MSK(5), 0, 0, IRQ_NOPROBE | IRQ_LEVEL);
 
index b928bc1..8b51cd6 100644 (file)
@@ -375,12 +375,14 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3)
         *      both have been read. So the value read will always be correct.
         * Set BOOT bit to refresh factory tuning values.
         */
-       lis3->read(lis3, CTRL_REG2, &reg);
-       if (lis3->whoami ==  WAI_12B)
-               reg |= CTRL2_BDU | CTRL2_BOOT;
-       else
-               reg |= CTRL2_BOOT_8B;
-       lis3->write(lis3, CTRL_REG2, reg);
+       if (lis3->pdata) {
+               lis3->read(lis3, CTRL_REG2, &reg);
+               if (lis3->whoami ==  WAI_12B)
+                       reg |= CTRL2_BDU | CTRL2_BOOT;
+               else
+                       reg |= CTRL2_BOOT_8B;
+               lis3->write(lis3, CTRL_REG2, reg);
+       }
 
        /* LIS3 power on delay is quite long */
        msleep(lis3->pwron_delay / lis3lv02d_get_odr());
index a1e004a..0b4acf6 100644 (file)
@@ -2120,6 +2120,7 @@ static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)
                        break;
                case DCB_CAP_ATTR_DCBX:
                        *cap = BNX2X_DCBX_CAPS;
+                       break;
                default:
                        rval = -EINVAL;
                        break;
index c027e93..15f8000 100644 (file)
@@ -4943,7 +4943,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp)
        int igu_seg_id;
        int port = BP_PORT(bp);
        int func = BP_FUNC(bp);
-       int reg_offset;
+       int reg_offset, reg_offset_en5;
        u64 section;
        int index;
        struct hc_sp_status_block_data sp_sb_data;
@@ -4966,6 +4966,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp)
 
        reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
                             MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+       reg_offset_en5 = (port ? MISC_REG_AEU_ENABLE5_FUNC_1_OUT_0 :
+                                MISC_REG_AEU_ENABLE5_FUNC_0_OUT_0);
        for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
                int sindex;
                /* take care of sig[0]..sig[4] */
@@ -4980,7 +4982,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp)
                         * and not 16 between the different groups
                         */
                        bp->attn_group[index].sig[4] = REG_RD(bp,
-                                       reg_offset + 0x10 + 0x4*index);
+                                       reg_offset_en5 + 0x4*index);
                else
                        bp->attn_group[index].sig[4] = 0;
        }
@@ -7625,8 +7627,11 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode)
                u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
                u8 *mac_addr = bp->dev->dev_addr;
                u32 val;
+               u16 pmc;
+
                /* The mac address is written to entries 1-4 to
-                  preserve entry 0 which is used by the PMF */
+                * preserve entry 0 which is used by the PMF
+                */
                u8 entry = (BP_VN(bp) + 1)*8;
 
                val = (mac_addr[0] << 8) | mac_addr[1];
@@ -7636,6 +7641,11 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode)
                      (mac_addr[4] << 8) | mac_addr[5];
                EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry + 4, val);
 
+               /* Enable the PME and clear the status */
+               pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmc);
+               pmc |= PCI_PM_CTRL_PME_ENABLE | PCI_PM_CTRL_PME_STATUS;
+               pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, pmc);
+
                reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN;
 
        } else
index 750e844..fc7bd0f 100644 (file)
    Latched ump_tx_parity; [31] MCP Latched scpad_parity; */
 #define MISC_REG_AEU_ENABLE4_PXP_0                              0xa108
 #define MISC_REG_AEU_ENABLE4_PXP_1                              0xa1a8
+/* [RW 32] fifth 32b for enabling the output for function 0 output0. Mapped
+ * as follows: [0] PGLUE config_space; [1] PGLUE misc_flr; [2] PGLUE B RBC
+ * attention [3] PGLUE B RBC parity; [4] ATC attention; [5] ATC parity; [6]
+ * mstat0 attention; [7] mstat0 parity; [8] mstat1 attention; [9] mstat1
+ * parity; [31-10] Reserved; */
+#define MISC_REG_AEU_ENABLE5_FUNC_0_OUT_0                       0xa688
+/* [RW 32] Fifth 32b for enabling the output for function 1 output0. Mapped
+ * as follows: [0] PGLUE config_space; [1] PGLUE misc_flr; [2] PGLUE B RBC
+ * attention [3] PGLUE B RBC parity; [4] ATC attention; [5] ATC parity; [6]
+ * mstat0 attention; [7] mstat0 parity; [8] mstat1 attention; [9] mstat1
+ * parity; [31-10] Reserved; */
+#define MISC_REG_AEU_ENABLE5_FUNC_1_OUT_0                       0xa6b0
 /* [RW 1] set/clr general attention 0; this will set/clr bit 94 in the aeu
    128 bit vector */
 #define MISC_REG_AEU_GENERAL_ATTN_0                             0xa000
index a047eb9..47b928e 100644 (file)
@@ -2168,7 +2168,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        }
 
 re_arm:
-       queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
+       if (!bond->kill_timers)
+               queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
 out:
        read_unlock(&bond->lock);
 }
index 7f8b20a..d4fbd2e 100644 (file)
@@ -1440,7 +1440,8 @@ void bond_alb_monitor(struct work_struct *work)
        }
 
 re_arm:
-       queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
+       if (!bond->kill_timers)
+               queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
 out:
        read_unlock(&bond->lock);
 }
index 43f2ea5..6d79b78 100644 (file)
@@ -777,6 +777,9 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
 
        read_lock(&bond->lock);
 
+       if (bond->kill_timers)
+               goto out;
+
        /* rejoin all groups on bond device */
        __bond_resend_igmp_join_requests(bond->dev);
 
@@ -790,9 +793,9 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
                        __bond_resend_igmp_join_requests(vlan_dev);
        }
 
-       if (--bond->igmp_retrans > 0)
+       if ((--bond->igmp_retrans > 0) && !bond->kill_timers)
                queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
-
+out:
        read_unlock(&bond->lock);
 }
 
@@ -2538,7 +2541,7 @@ void bond_mii_monitor(struct work_struct *work)
        }
 
 re_arm:
-       if (bond->params.miimon)
+       if (bond->params.miimon && !bond->kill_timers)
                queue_delayed_work(bond->wq, &bond->mii_work,
                                   msecs_to_jiffies(bond->params.miimon));
 out:
@@ -2886,7 +2889,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work)
        }
 
 re_arm:
-       if (bond->params.arp_interval)
+       if (bond->params.arp_interval && !bond->kill_timers)
                queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
 out:
        read_unlock(&bond->lock);
@@ -3154,7 +3157,7 @@ void bond_activebackup_arp_mon(struct work_struct *work)
        bond_ab_arp_probe(bond);
 
 re_arm:
-       if (bond->params.arp_interval)
+       if (bond->params.arp_interval && !bond->kill_timers)
                queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
 out:
        read_unlock(&bond->lock);
index 805076c..da5a5d9 100644 (file)
@@ -1146,12 +1146,14 @@ static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
                if (te && te->ctx && te->client && te->client->redirect) {
                        update_tcb = te->client->redirect(te->ctx, old, new, e);
                        if (update_tcb) {
+                               rcu_read_lock();
                                l2t_hold(L2DATA(tdev), e);
+                               rcu_read_unlock();
                                set_l2t_ix(tdev, tid, e);
                        }
                }
        }
-       l2t_release(L2DATA(tdev), e);
+       l2t_release(tdev, e);
 }
 
 /*
@@ -1264,7 +1266,7 @@ int cxgb3_offload_activate(struct adapter *adapter)
                goto out_free;
 
        err = -ENOMEM;
-       L2DATA(dev) = t3_init_l2t(l2t_capacity);
+       RCU_INIT_POINTER(dev->l2opt, t3_init_l2t(l2t_capacity));
        if (!L2DATA(dev))
                goto out_free;
 
@@ -1298,16 +1300,24 @@ int cxgb3_offload_activate(struct adapter *adapter)
 
 out_free_l2t:
        t3_free_l2t(L2DATA(dev));
-       L2DATA(dev) = NULL;
+       rcu_assign_pointer(dev->l2opt, NULL);
 out_free:
        kfree(t);
        return err;
 }
 
+static void clean_l2_data(struct rcu_head *head)
+{
+       struct l2t_data *d = container_of(head, struct l2t_data, rcu_head);
+       t3_free_l2t(d);
+}
+
+
 void cxgb3_offload_deactivate(struct adapter *adapter)
 {
        struct t3cdev *tdev = &adapter->tdev;
        struct t3c_data *t = T3C_DATA(tdev);
+       struct l2t_data *d;
 
        remove_adapter(adapter);
        if (list_empty(&adapter_list))
@@ -1315,8 +1325,11 @@ void cxgb3_offload_deactivate(struct adapter *adapter)
 
        free_tid_maps(&t->tid_maps);
        T3C_DATA(tdev) = NULL;
-       t3_free_l2t(L2DATA(tdev));
-       L2DATA(tdev) = NULL;
+       rcu_read_lock();
+       d = L2DATA(tdev);
+       rcu_read_unlock();
+       rcu_assign_pointer(tdev->l2opt, NULL);
+       call_rcu(&d->rcu_head, clean_l2_data);
        if (t->nofail_skb)
                kfree_skb(t->nofail_skb);
        kfree(t);
index f452c40..4154097 100644 (file)
@@ -300,14 +300,21 @@ static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh)
 struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
                             struct net_device *dev)
 {
-       struct l2t_entry *e;
-       struct l2t_data *d = L2DATA(cdev);
+       struct l2t_entry *e = NULL;
+       struct l2t_data *d;
+       int hash;
        u32 addr = *(u32 *) neigh->primary_key;
        int ifidx = neigh->dev->ifindex;
-       int hash = arp_hash(addr, ifidx, d);
        struct port_info *p = netdev_priv(dev);
        int smt_idx = p->port_id;
 
+       rcu_read_lock();
+       d = L2DATA(cdev);
+       if (!d)
+               goto done_rcu;
+
+       hash = arp_hash(addr, ifidx, d);
+
        write_lock_bh(&d->lock);
        for (e = d->l2tab[hash].first; e; e = e->next)
                if (e->addr == addr && e->ifindex == ifidx &&
@@ -338,6 +345,8 @@ struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
        }
 done:
        write_unlock_bh(&d->lock);
+done_rcu:
+       rcu_read_unlock();
        return e;
 }
 
index 7a12d52..c5f5479 100644 (file)
@@ -76,6 +76,7 @@ struct l2t_data {
        atomic_t nfree;         /* number of free entries */
        rwlock_t lock;
        struct l2t_entry l2tab[0];
+       struct rcu_head rcu_head;       /* to handle rcu cleanup */
 };
 
 typedef void (*arp_failure_handler_func)(struct t3cdev * dev,
@@ -99,7 +100,7 @@ static inline void set_arp_failure_handler(struct sk_buff *skb,
 /*
  * Getting to the L2 data from an offload device.
  */
-#define L2DATA(dev) ((dev)->l2opt)
+#define L2DATA(cdev) (rcu_dereference((cdev)->l2opt))
 
 #define W_TCB_L2T_IX    0
 #define S_TCB_L2T_IX    7
@@ -126,15 +127,22 @@ static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb,
        return t3_l2t_send_slow(dev, skb, e);
 }
 
-static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e)
+static inline void l2t_release(struct t3cdev *t, struct l2t_entry *e)
 {
-       if (atomic_dec_and_test(&e->refcnt))
+       struct l2t_data *d;
+
+       rcu_read_lock();
+       d = L2DATA(t);
+
+       if (atomic_dec_and_test(&e->refcnt) && d)
                t3_l2e_free(d, e);
+
+       rcu_read_unlock();
 }
 
 static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
 {
-       if (atomic_add_return(1, &e->refcnt) == 1)      /* 0 -> 1 transition */
+       if (d && atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */
                atomic_dec(&d->nfree);
 }
 
index c9957b7..b4efa29 100644 (file)
@@ -3712,6 +3712,9 @@ static int __devinit init_one(struct pci_dev *pdev,
                setup_debugfs(adapter);
        }
 
+       /* PCIe EEH recovery on powerpc platforms needs fundamental reset */
+       pdev->needs_freset = 1;
+
        if (is_offload(adapter))
                attach_ulds(adapter);
 
index 2198e61..07031af 100644 (file)
@@ -47,7 +47,7 @@
 #include <linux/if_vlan.h>
 #include <linux/cpu.h>
 #include <linux/smp.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 #include <linux/pm_runtime.h>
 #include <linux/aer.h>
 #include <linux/prefetch.h>
index 8dd5fcc..d393f1e 100644 (file)
@@ -636,8 +636,8 @@ static int ibmveth_open(struct net_device *netdev)
                netdev_err(netdev, "unable to request irq 0x%x, rc %d\n",
                           netdev->irq, rc);
                do {
-                       rc = h_free_logical_lan(adapter->vdev->unit_address);
-               } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY));
+                       lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
+               } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY));
 
                goto err_out;
        }
index 05172c3..376e3e9 100644 (file)
@@ -239,7 +239,7 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
                dest = macvlan_hash_lookup(port, eth->h_dest);
                if (dest && dest->mode == MACVLAN_MODE_BRIDGE) {
                        /* send to lowerdev first for its network taps */
-                       vlan->forward(vlan->lowerdev, skb);
+                       dev_forward_skb(vlan->lowerdev, skb);
 
                        return NET_XMIT_SUCCESS;
                }
index 567ff10..b8b4ba2 100644 (file)
@@ -1199,6 +1199,8 @@ static irqreturn_t pch_gbe_intr(int irq, void *data)
                        iowrite32((int_en & ~PCH_GBE_INT_RX_FIFO_ERR),
                                  &hw->reg->INT_EN);
                        pch_gbe_stop_receive(adapter);
+                       int_st |= ioread32(&hw->reg->INT_ST);
+                       int_st = int_st & ioread32(&hw->reg->INT_EN);
                }
        if (int_st & PCH_GBE_INT_RX_DMA_ERR)
                adapter->stats.intr_rx_dma_err_count++;
@@ -1218,14 +1220,11 @@ static irqreturn_t pch_gbe_intr(int irq, void *data)
                        /* Set Pause packet */
                        pch_gbe_mac_set_pause_packet(hw);
                }
-               if ((int_en & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT))
-                   == 0) {
-                       return IRQ_HANDLED;
-               }
        }
 
        /* When request status is Receive interruption */
-       if ((int_st & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT))) {
+       if ((int_st & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT)) ||
+           (adapter->rx_stop_flag == true)) {
                if (likely(napi_schedule_prep(&adapter->napi))) {
                        /* Enable only Rx Descriptor empty */
                        atomic_inc(&adapter->irq_sem);
@@ -1385,7 +1384,7 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
        struct sk_buff *skb;
        unsigned int i;
        unsigned int cleaned_count = 0;
-       bool cleaned = false;
+       bool cleaned = true;
 
        pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean);
 
@@ -1396,7 +1395,6 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
 
        while ((tx_desc->gbec_status & DSC_INIT16) == 0x0000) {
                pr_debug("gbec_status:0x%04x\n", tx_desc->gbec_status);
-               cleaned = true;
                buffer_info = &tx_ring->buffer_info[i];
                skb = buffer_info->skb;
 
@@ -1439,8 +1437,10 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
                tx_desc = PCH_GBE_TX_DESC(*tx_ring, i);
 
                /* weight of a sort for tx, to avoid endless transmit cleanup */
-               if (cleaned_count++ == PCH_GBE_TX_WEIGHT)
+               if (cleaned_count++ == PCH_GBE_TX_WEIGHT) {
+                       cleaned = false;
                        break;
+               }
        }
        pr_debug("called pch_gbe_unmap_and_free_tx_resource() %d count\n",
                 cleaned_count);
@@ -2168,7 +2168,6 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget)
 {
        struct pch_gbe_adapter *adapter =
            container_of(napi, struct pch_gbe_adapter, napi);
-       struct net_device *netdev = adapter->netdev;
        int work_done = 0;
        bool poll_end_flag = false;
        bool cleaned = false;
@@ -2176,33 +2175,32 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget)
 
        pr_debug("budget : %d\n", budget);
 
-       /* Keep link state information with original netdev */
-       if (!netif_carrier_ok(netdev)) {
+       pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget);
+       cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring);
+
+       if (!cleaned)
+               work_done = budget;
+       /* If no Tx and not enough Rx work done,
+        * exit the polling mode
+        */
+       if (work_done < budget)
                poll_end_flag = true;
-       } else {
-               pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget);
+
+       if (poll_end_flag) {
+               napi_complete(napi);
+               if (adapter->rx_stop_flag) {
+                       adapter->rx_stop_flag = false;
+                       pch_gbe_start_receive(&adapter->hw);
+               }
+               pch_gbe_irq_enable(adapter);
+       } else
                if (adapter->rx_stop_flag) {
                        adapter->rx_stop_flag = false;
                        pch_gbe_start_receive(&adapter->hw);
                        int_en = ioread32(&adapter->hw.reg->INT_EN);
                        iowrite32((int_en | PCH_GBE_INT_RX_FIFO_ERR),
-                                       &adapter->hw.reg->INT_EN);
+                               &adapter->hw.reg->INT_EN);
                }
-               cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring);
-
-               if (cleaned)
-                       work_done = budget;
-               /* If no Tx and not enough Rx work done,
-                * exit the polling mode
-                */
-               if ((work_done < budget) || !netif_running(netdev))
-                       poll_end_flag = true;
-       }
-
-       if (poll_end_flag) {
-               napi_complete(napi);
-               pch_gbe_irq_enable(adapter);
-       }
 
        pr_debug("poll_end_flag : %d  work_done : %d  budget : %d\n",
                 poll_end_flag, work_done, budget);
index cb6e0b4..edd7304 100644 (file)
@@ -589,7 +589,7 @@ static void decode_rxts(struct dp83640_private *dp83640,
        prune_rx_ts(dp83640);
 
        if (list_empty(&dp83640->rxpool)) {
-               pr_warning("dp83640: rx timestamp pool is empty\n");
+               pr_debug("dp83640: rx timestamp pool is empty\n");
                goto out;
        }
        rxts = list_first_entry(&dp83640->rxpool, struct rxts, list);
@@ -612,7 +612,7 @@ static void decode_txts(struct dp83640_private *dp83640,
        skb = skb_dequeue(&dp83640->tx_queue);
 
        if (!skb) {
-               pr_warning("dp83640: have timestamp but tx_queue empty\n");
+               pr_debug("dp83640: have timestamp but tx_queue empty\n");
                return;
        }
        ns = phy2txts(phy_txts);
index ce395fe..f1c435b 100644 (file)
@@ -1470,7 +1470,7 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
        if (!dev->suspend_count++) {
                spin_lock_irq(&dev->txq.lock);
                /* don't autosuspend while transmitting */
-               if (dev->txq.qlen && (message.event & PM_EVENT_AUTO)) {
+               if (dev->txq.qlen && PMSG_IS_AUTO(message)) {
                        spin_unlock_irq(&dev->txq.lock);
                        return -EBUSY;
                } else {
index 298f2b0..9a644d0 100644 (file)
@@ -599,7 +599,7 @@ void i2400mu_disconnect(struct usb_interface *iface)
  *
  *    As well, the device might refuse going to sleep for whichever
  *    reason. In this case we just fail. For system suspend/hibernate,
- *    we *can't* fail. We check PM_EVENT_AUTO to see if the
+ *    we *can't* fail. We check PMSG_IS_AUTO to see if the
  *    suspend call comes from the USB stack or from the system and act
  *    in consequence.
  *
@@ -615,7 +615,7 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
        struct i2400m *i2400m = &i2400mu->i2400m;
 
 #ifdef CONFIG_PM
-       if (pm_msg.event & PM_EVENT_AUTO)
+       if (PMSG_IS_AUTO(pm_msg))
                is_autosuspend = 1;
 #endif
 
index 2339728..3e69c63 100644 (file)
@@ -1514,7 +1514,7 @@ static const u32 ar9300_2p2_mac_core[][2] = {
        {0x00008258, 0x00000000},
        {0x0000825c, 0x40000000},
        {0x00008260, 0x00080922},
-       {0x00008264, 0x9bc00010},
+       {0x00008264, 0x9d400010},
        {0x00008268, 0xffffffff},
        {0x0000826c, 0x0000ffff},
        {0x00008270, 0x00000000},
index 9a48501..4c21f8c 100644 (file)
@@ -205,14 +205,22 @@ static void ath_rx_remove_buffer(struct ath_softc *sc,
 
 static void ath_rx_edma_cleanup(struct ath_softc *sc)
 {
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath_buf *bf;
 
        ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP);
        ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP);
 
        list_for_each_entry(bf, &sc->rx.rxbuf, list) {
-               if (bf->bf_mpdu)
+               if (bf->bf_mpdu) {
+                       dma_unmap_single(sc->dev, bf->bf_buf_addr,
+                                       common->rx_bufsize,
+                                       DMA_BIDIRECTIONAL);
                        dev_kfree_skb_any(bf->bf_mpdu);
+                       bf->bf_buf_addr = 0;
+                       bf->bf_mpdu = NULL;
+               }
        }
 
        INIT_LIST_HEAD(&sc->rx.rxbuf);
index ef9ad79..127e9c6 100644 (file)
@@ -161,7 +161,7 @@ that only one external action is invoked at a time.
 #include <linux/firmware.h>
 #include <linux/acpi.h>
 #include <linux/ctype.h>
-#include <linux/pm_qos_params.h>
+#include <linux/pm_qos.h>
 
 #include <net/lib80211.h>
 
@@ -174,7 +174,7 @@ that only one external action is invoked at a time.
 #define DRV_DESCRIPTION        "Intel(R) PRO/Wireless 2100 Network Driver"
 #define DRV_COPYRIGHT  "Copyright(c) 2003-2006 Intel Corporation"
 
-static struct pm_qos_request_list ipw2100_pm_qos_req;
+static struct pm_qos_request ipw2100_pm_qos_req;
 
 /* Debugging stuff */
 #ifdef CONFIG_IPW2100_DEBUG
index 35cd253..e5971fe 100644 (file)
@@ -937,7 +937,7 @@ void iwl_legacy_irq_handle_error(struct iwl_priv *priv)
                                        &priv->contexts[IWL_RXON_CTX_BSS]);
 #endif
 
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
 
        /* Keep the restart process from trying to send host
         * commands by clearing the INIT status bit */
@@ -1746,7 +1746,7 @@ int iwl_legacy_force_reset(struct iwl_priv *priv, bool external)
 
        /* Set the FW error flag -- cleared on iwl_down */
        set_bit(STATUS_FW_ERROR, &priv->status);
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
        /*
         * Keep the restart process from trying to send host
         * commands by clearing the INIT status bit
index 62b4b09..ce1fc9f 100644 (file)
@@ -167,7 +167,7 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                goto out;
        }
 
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+       ret = wait_event_timeout(priv->wait_command_queue,
                        !test_bit(STATUS_HCMD_ACTIVE, &priv->status),
                        HOST_COMPLETE_TIMEOUT);
        if (!ret) {
index 4fff995..ef9e268 100644 (file)
@@ -625,6 +625,8 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        cmd = txq->cmd[cmd_index];
        meta = &txq->meta[cmd_index];
 
+       txq->time_stamp = jiffies;
+
        pci_unmap_single(priv->pci_dev,
                         dma_unmap_addr(meta, mapping),
                         dma_unmap_len(meta, len),
@@ -645,7 +647,7 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
                clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
                IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
                               iwl_legacy_get_cmd_string(cmd->hdr.cmd));
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
        }
 
        /* Mark as unmapped */
index 795826a..66ee156 100644 (file)
@@ -841,7 +841,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
                wiphy_rfkill_set_hw_state(priv->hw->wiphy,
                                test_bit(STATUS_RF_KILL_HW, &priv->status));
        else
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
 }
 
 /**
@@ -2269,7 +2269,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
        iwl3945_reg_txpower_periodic(priv);
 
        IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
 
        return;
 
@@ -2300,7 +2300,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
        iwl_legacy_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
-       wake_up_interruptible_all(&priv->wait_command_queue);
+       wake_up_all(&priv->wait_command_queue);
 
        /* Wipe out the EXIT_PENDING status bit if we are not actually
         * exiting the module */
@@ -2853,7 +2853,7 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
 
        /* Wait for START_ALIVE from ucode. Otherwise callbacks from
         * mac80211 will not be run successfully. */
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+       ret = wait_event_timeout(priv->wait_command_queue,
                        test_bit(STATUS_READY, &priv->status),
                        UCODE_READY_TIMEOUT);
        if (!ret) {
index 1433466..aa0c253 100644 (file)
@@ -576,7 +576,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
                wiphy_rfkill_set_hw_state(priv->hw->wiphy,
                        test_bit(STATUS_RF_KILL_HW, &priv->status));
        else
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
 }
 
 /**
@@ -926,7 +926,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
                handled |= CSR_INT_BIT_FH_TX;
                /* Wake up uCode load routine, now that load is complete */
                priv->ucode_write_complete = 1;
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
        }
 
        if (inta & ~handled) {
@@ -1795,7 +1795,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
        iwl4965_rf_kill_ct_config(priv);
 
        IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
 
        iwl_legacy_power_update_mode(priv, true);
        IWL_DEBUG_INFO(priv, "Updated power mode\n");
@@ -1828,7 +1828,7 @@ static void __iwl4965_down(struct iwl_priv *priv)
        iwl_legacy_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
-       wake_up_interruptible_all(&priv->wait_command_queue);
+       wake_up_all(&priv->wait_command_queue);
 
        /* Wipe out the EXIT_PENDING status bit if we are not actually
         * exiting the module */
@@ -2266,7 +2266,7 @@ int iwl4965_mac_start(struct ieee80211_hw *hw)
 
        /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
         * mac80211 will not be run successfully. */
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+       ret = wait_event_timeout(priv->wait_command_queue,
                        test_bit(STATUS_READY, &priv->status),
                        UCODE_READY_TIMEOUT);
        if (!ret) {
index dd6937e..77e528f 100644 (file)
@@ -405,31 +405,33 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
-       if (test_bit(STATUS_SCANNING, &priv->status) &&
-           priv->scan_type != IWL_SCAN_NORMAL) {
-               IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
-               ret = -EAGAIN;
-               goto out_unlock;
-       }
-
-       /* mac80211 will only ask for one band at a time */
-       priv->scan_request = req;
-       priv->scan_vif = vif;
-
        /*
         * If an internal scan is in progress, just set
         * up the scan_request as per above.
         */
        if (priv->scan_type != IWL_SCAN_NORMAL) {
-               IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n");
+               IWL_DEBUG_SCAN(priv,
+                              "SCAN request during internal scan - defer\n");
+               priv->scan_request = req;
+               priv->scan_vif = vif;
                ret = 0;
-       } else
+       } else {
+               priv->scan_request = req;
+               priv->scan_vif = vif;
+               /*
+                * mac80211 will only ask for one band at a time
+                * so using channels[0] here is ok
+                */
                ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
                                        req->channels[0]->band);
+               if (ret) {
+                       priv->scan_request = NULL;
+                       priv->scan_vif = NULL;
+               }
+       }
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
-out_unlock:
        mutex_unlock(&priv->mutex);
 
        return ret;
index 8b1cef0..4bf3cf4 100644 (file)
@@ -863,6 +863,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
        u8 tid = 0;
        u16 seq_number = 0;
 
+       memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
        if (ieee80211_is_auth(fc)) {
                RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
                rtl_ips_nic_on(hw);
index 0ca86f9..1825629 100644 (file)
@@ -327,12 +327,12 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
        xenvif_get(vif);
 
        rtnl_lock();
-       if (netif_running(vif->dev))
-               xenvif_up(vif);
        if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN)
                dev_set_mtu(vif->dev, ETH_DATA_LEN);
        netdev_update_features(vif->dev);
        netif_carrier_on(vif->dev);
+       if (netif_running(vif->dev))
+               xenvif_up(vif);
        rtnl_unlock();
 
        return 0;
index 4e84fd4..e9651f0 100644 (file)
@@ -77,7 +77,7 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
 unsigned long pci_hotplug_io_size  = DEFAULT_HOTPLUG_IO_SIZE;
 unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
 
-enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_SAFE;
+enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF;
 
 /*
  * The default CLS is used if arch didn't set CLS explicitly and not
@@ -3568,10 +3568,14 @@ static int __init pci_setup(char *str)
                                pci_hotplug_io_size = memparse(str + 9, &str);
                        } else if (!strncmp(str, "hpmemsize=", 10)) {
                                pci_hotplug_mem_size = memparse(str + 10, &str);
+                       } else if (!strncmp(str, "pcie_bus_tune_off", 17)) {
+                               pcie_bus_config = PCIE_BUS_TUNE_OFF;
                        } else if (!strncmp(str, "pcie_bus_safe", 13)) {
                                pcie_bus_config = PCIE_BUS_SAFE;
                        } else if (!strncmp(str, "pcie_bus_perf", 13)) {
                                pcie_bus_config = PCIE_BUS_PERFORMANCE;
+                       } else if (!strncmp(str, "pcie_bus_peer2peer", 18)) {
+                               pcie_bus_config = PCIE_BUS_PEER2PEER;
                        } else {
                                printk(KERN_ERR "PCI: Unknown option `%s'\n",
                                                str);
index f3f94a5..6ab6bd3 100644 (file)
@@ -1458,12 +1458,24 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data)
  */
 void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss)
 {
-       u8 smpss = mpss;
+       u8 smpss;
 
        if (!pci_is_pcie(bus->self))
                return;
 
+       if (pcie_bus_config == PCIE_BUS_TUNE_OFF)
+               return;
+
+       /* FIXME - Peer to peer DMA is possible, though the endpoint would need
+        * to be aware to the MPS of the destination.  To work around this,
+        * simply force the MPS of the entire system to the smallest possible.
+        */
+       if (pcie_bus_config == PCIE_BUS_PEER2PEER)
+               smpss = 0;
+
        if (pcie_bus_config == PCIE_BUS_SAFE) {
+               smpss = mpss;
+
                pcie_find_smpss(bus->self, &smpss);
                pci_walk_bus(bus, pcie_find_smpss, &smpss);
        }
index cbde448..eb3140e 100644 (file)
@@ -654,8 +654,8 @@ static struct io_subchannel_private console_priv;
 static int console_subchannel_in_use;
 
 /*
- * Use tpi to get a pending interrupt, call the interrupt handler and
- * return a pointer to the subchannel structure.
+ * Use cio_tpi to get a pending interrupt and call the interrupt handler.
+ * Return non-zero if an interrupt was processed, zero otherwise.
  */
 static int cio_tpi(void)
 {
@@ -667,6 +667,10 @@ static int cio_tpi(void)
        tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id;
        if (tpi(NULL) != 1)
                return 0;
+       if (tpi_info->adapter_IO) {
+               do_adapter_IO(tpi_info->isc);
+               return 1;
+       }
        irb = (struct irb *)&S390_lowcore.irb;
        /* Store interrupt response block to lowcore. */
        if (tsch(tpi_info->schid, irb) != 0)
index b7bd5b0..3868ab2 100644 (file)
@@ -1800,10 +1800,12 @@ static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_
        switch (retval) {
        case SCSI_MLQUEUE_HOST_BUSY:
                twa_free_request_id(tw_dev, request_id);
+               twa_unmap_scsi_data(tw_dev, request_id);
                break;
        case 1:
                tw_dev->state[request_id] = TW_S_COMPLETED;
                twa_free_request_id(tw_dev, request_id);
+               twa_unmap_scsi_data(tw_dev, request_id);
                SCpnt->result = (DID_ERROR << 16);
                done(SCpnt);
                retval = 0;
index 3c08f53..6153a66 100644 (file)
@@ -88,7 +88,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o       qlogicfas.o
 obj-$(CONFIG_PCMCIA_QLOGIC)    += qlogicfas408.o
 obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o 
 obj-$(CONFIG_SCSI_QLA_FC)      += qla2xxx/
-obj-$(CONFIG_SCSI_QLA_ISCSI)   += qla4xxx/
+obj-$(CONFIG_SCSI_QLA_ISCSI)   += libiscsi.o qla4xxx/
 obj-$(CONFIG_SCSI_LPFC)                += lpfc/
 obj-$(CONFIG_SCSI_BFA_FC)      += bfa/
 obj-$(CONFIG_SCSI_PAS16)       += pas16.o
index e7d0d47..e5f2d7d 100644 (file)
@@ -1283,6 +1283,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
        kfree(aac->queues);
        aac->queues = NULL;
        free_irq(aac->pdev->irq, aac);
+       if (aac->msi)
+               pci_disable_msi(aac->pdev);
        kfree(aac->fsa_dev);
        aac->fsa_dev = NULL;
        quirks = aac_get_driver_ident(index)->quirks;
index bd22041..f586448 100644 (file)
@@ -913,7 +913,7 @@ static void l2t_put(struct cxgbi_sock *csk)
        struct t3cdev *t3dev = (struct t3cdev *)csk->cdev->lldev;
 
        if (csk->l2t) {
-               l2t_release(L2DATA(t3dev), csk->l2t);
+               l2t_release(t3dev, csk->l2t);
                csk->l2t = NULL;
                cxgbi_sock_put(csk);
        }
index f84084b..16ad97d 100644 (file)
@@ -1721,7 +1721,7 @@ static int sas_find_bcast_dev(struct domain_device *dev,
        list_for_each_entry(ch, &ex->children, siblings) {
                if (ch->dev_type == EDGE_DEV || ch->dev_type == FANOUT_DEV) {
                        res = sas_find_bcast_dev(ch, src_dev);
-                       if (src_dev)
+                       if (*src_dev)
                                return res;
                }
        }
@@ -1769,10 +1769,12 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent,
                sas_disable_routing(parent, phy->attached_sas_addr);
        }
        memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
-       sas_port_delete_phy(phy->port, phy->phy);
-       if (phy->port->num_phys == 0)
-               sas_port_delete(phy->port);
-       phy->port = NULL;
+       if (phy->port) {
+               sas_port_delete_phy(phy->port, phy->phy);
+               if (phy->port->num_phys == 0)
+                       sas_port_delete(phy->port);
+               phy->port = NULL;
+       }
 }
 
 static int sas_discover_bfs_by_root_level(struct domain_device *root,
index 4cace3f..1e69527 100644 (file)
@@ -1328,10 +1328,9 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
                                        qla2x00_sp_compl(ha, sp);
                                } else {
                                        ctx = sp->ctx;
-                                       if (ctx->type == SRB_LOGIN_CMD ||
-                                           ctx->type == SRB_LOGOUT_CMD) {
-                                               ctx->u.iocb_cmd->free(sp);
-                                       } else {
+                                       if (ctx->type == SRB_ELS_CMD_RPT ||
+                                           ctx->type == SRB_ELS_CMD_HST ||
+                                           ctx->type == SRB_CT_CMD) {
                                                struct fc_bsg_job *bsg_job =
                                                    ctx->u.bsg_job;
                                                if (bsg_job->request->msgcode
@@ -1343,6 +1342,8 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
                                                kfree(sp->ctx);
                                                mempool_free(sp,
                                                        ha->srb_mempool);
+                                       } else {
+                                               ctx->u.iocb_cmd->free(sp);
                                        }
                                }
                        }
index 1d23f38..6a80749 100644 (file)
@@ -50,6 +50,8 @@
 #define PCH_RX_THOLD           7
 #define PCH_RX_THOLD_MAX       15
 
+#define PCH_TX_THOLD           2
+
 #define PCH_MAX_BAUDRATE       5000000
 #define PCH_MAX_FIFO_DEPTH     16
 
@@ -58,6 +60,7 @@
 #define PCH_SLEEP_TIME         10
 
 #define SSN_LOW                        0x02U
+#define SSN_HIGH               0x03U
 #define SSN_NO_CONTROL         0x00U
 #define PCH_MAX_CS             0xFF
 #define PCI_DEVICE_ID_GE_SPI   0x8816
@@ -316,16 +319,19 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
 
        /* if transfer complete interrupt */
        if (reg_spsr_val & SPSR_FI_BIT) {
-               if (tx_index < bpw_len)
+               if ((tx_index == bpw_len) && (rx_index == tx_index)) {
+                       /* disable interrupts */
+                       pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
+
+                       /* transfer is completed;
+                          inform pch_spi_process_messages */
+                       data->transfer_complete = true;
+                       data->transfer_active = false;
+                       wake_up(&data->wait);
+               } else {
                        dev_err(&data->master->dev,
                                "%s : Transfer is not completed", __func__);
-               /* disable interrupts */
-               pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
-
-               /* transfer is completed;inform pch_spi_process_messages */
-               data->transfer_complete = true;
-               data->transfer_active = false;
-               wake_up(&data->wait);
+               }
        }
 }
 
@@ -348,16 +354,26 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id)
                        "%s returning due to suspend\n", __func__);
                return IRQ_NONE;
        }
-       if (data->use_dma)
-               return IRQ_NONE;
 
        io_remap_addr = data->io_remap_addr;
        spsr = io_remap_addr + PCH_SPSR;
 
        reg_spsr_val = ioread32(spsr);
 
-       if (reg_spsr_val & SPSR_ORF_BIT)
-               dev_err(&board_dat->pdev->dev, "%s Over run error", __func__);
+       if (reg_spsr_val & SPSR_ORF_BIT) {
+               dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__);
+               if (data->current_msg->complete != 0) {
+                       data->transfer_complete = true;
+                       data->current_msg->status = -EIO;
+                       data->current_msg->complete(data->current_msg->context);
+                       data->bcurrent_msg_processing = false;
+                       data->current_msg = NULL;
+                       data->cur_trans = NULL;
+               }
+       }
+
+       if (data->use_dma)
+               return IRQ_NONE;
 
        /* Check if the interrupt is for SPI device */
        if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) {
@@ -756,10 +772,6 @@ static void pch_spi_set_ir(struct pch_spi_data *data)
 
        wait_event_interruptible(data->wait, data->transfer_complete);
 
-       pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
-       dev_dbg(&data->master->dev,
-               "%s:no more control over SSN-writing 0 to SSNXCR.", __func__);
-
        /* clear all interrupts */
        pch_spi_writereg(data->master, PCH_SPSR,
                         pch_spi_readreg(data->master, PCH_SPSR));
@@ -815,10 +827,11 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw)
        }
 }
 
-static void pch_spi_start_transfer(struct pch_spi_data *data)
+static int pch_spi_start_transfer(struct pch_spi_data *data)
 {
        struct pch_spi_dma_ctrl *dma;
        unsigned long flags;
+       int rtn;
 
        dma = &data->dma;
 
@@ -833,19 +846,23 @@ static void pch_spi_start_transfer(struct pch_spi_data *data)
                                 initiating the transfer. */
        dev_dbg(&data->master->dev,
                "%s:waiting for transfer to get over\n", __func__);
-       wait_event_interruptible(data->wait, data->transfer_complete);
+       rtn = wait_event_interruptible_timeout(data->wait,
+                                              data->transfer_complete,
+                                              msecs_to_jiffies(2 * HZ));
 
        dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent,
                            DMA_FROM_DEVICE);
+
+       dma_sync_sg_for_cpu(&data->master->dev, dma->sg_tx_p, dma->nent,
+                           DMA_FROM_DEVICE);
+       memset(data->dma.tx_buf_virt, 0, PAGE_SIZE);
+
        async_tx_ack(dma->desc_rx);
        async_tx_ack(dma->desc_tx);
        kfree(dma->sg_tx_p);
        kfree(dma->sg_rx_p);
 
        spin_lock_irqsave(&data->lock, flags);
-       pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
-       dev_dbg(&data->master->dev,
-               "%s:no more control over SSN-writing 0 to SSNXCR.", __func__);
 
        /* clear fifo threshold, disable interrupts, disable SPI transfer */
        pch_spi_setclr_reg(data->master, PCH_SPCR, 0,
@@ -858,6 +875,8 @@ static void pch_spi_start_transfer(struct pch_spi_data *data)
        pch_spi_clear_fifo(data->master);
 
        spin_unlock_irqrestore(&data->lock, flags);
+
+       return rtn;
 }
 
 static void pch_dma_rx_complete(void *arg)
@@ -1023,8 +1042,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
        /* set receive fifo threshold and transmit fifo threshold */
        pch_spi_setclr_reg(data->master, PCH_SPCR,
                           ((size - 1) << SPCR_RFIC_FIELD) |
-                          ((PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE) <<
-                           SPCR_TFIC_FIELD),
+                          (PCH_TX_THOLD << SPCR_TFIC_FIELD),
                           MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS);
 
        spin_unlock_irqrestore(&data->lock, flags);
@@ -1035,13 +1053,20 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
        /* offset, length setting */
        sg = dma->sg_rx_p;
        for (i = 0; i < num; i++, sg++) {
-               if (i == 0) {
-                       sg->offset = 0;
+               if (i == (num - 2)) {
+                       sg->offset = size * i;
+                       sg->offset = sg->offset * (*bpw / 8);
                        sg_set_page(sg, virt_to_page(dma->rx_buf_virt), rem,
                                    sg->offset);
                        sg_dma_len(sg) = rem;
+               } else if (i == (num - 1)) {
+                       sg->offset = size * (i - 1) + rem;
+                       sg->offset = sg->offset * (*bpw / 8);
+                       sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size,
+                                   sg->offset);
+                       sg_dma_len(sg) = size;
                } else {
-                       sg->offset = rem + size * (i - 1);
+                       sg->offset = size * i;
                        sg->offset = sg->offset * (*bpw / 8);
                        sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size,
                                    sg->offset);
@@ -1065,6 +1090,16 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
        dma->desc_rx = desc_rx;
 
        /* TX */
+       if (data->bpw_len > PCH_DMA_TRANS_SIZE) {
+               num = data->bpw_len / PCH_DMA_TRANS_SIZE;
+               size = PCH_DMA_TRANS_SIZE;
+               rem = 16;
+       } else {
+               num = 1;
+               size = data->bpw_len;
+               rem = data->bpw_len;
+       }
+
        dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
        sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */
        /* offset, length setting */
@@ -1162,6 +1197,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
        if (data->use_dma)
                pch_spi_request_dma(data,
                                    data->current_msg->spi->bits_per_word);
+       pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
        do {
                /* If we are already processing a message get the next
                transfer structure from the message otherwise retrieve
@@ -1184,7 +1220,8 @@ static void pch_spi_process_messages(struct work_struct *pwork)
 
                if (data->use_dma) {
                        pch_spi_handle_dma(data, &bpw);
-                       pch_spi_start_transfer(data);
+                       if (!pch_spi_start_transfer(data))
+                               goto out;
                        pch_spi_copy_rx_data_for_dma(data, bpw);
                } else {
                        pch_spi_set_tx(data, &bpw);
@@ -1222,6 +1259,8 @@ static void pch_spi_process_messages(struct work_struct *pwork)
 
        } while (data->cur_trans != NULL);
 
+out:
+       pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH);
        if (data->use_dma)
                pch_spi_release_dma(data);
 }
index dac7676..94e6c5c 100644 (file)
@@ -1305,7 +1305,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
        struct acm *acm = usb_get_intfdata(intf);
        int cnt;
 
-       if (message.event & PM_EVENT_AUTO) {
+       if (PMSG_IS_AUTO(message)) {
                int b;
 
                spin_lock_irq(&acm->write_lock);
index 2b9ff51..42f180a 100644 (file)
@@ -798,11 +798,11 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
        dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
 
        /* if this is an autosuspend the caller does the locking */
-       if (!(message.event & PM_EVENT_AUTO))
+       if (!PMSG_IS_AUTO(message))
                mutex_lock(&desc->lock);
        spin_lock_irq(&desc->iuspin);
 
-       if ((message.event & PM_EVENT_AUTO) &&
+       if (PMSG_IS_AUTO(message) &&
                        (test_bit(WDM_IN_USE, &desc->flags)
                        || test_bit(WDM_RESPONDING, &desc->flags))) {
                spin_unlock_irq(&desc->iuspin);
@@ -815,7 +815,7 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
                kill_urbs(desc);
                cancel_work_sync(&desc->rxwork);
        }
-       if (!(message.event & PM_EVENT_AUTO))
+       if (!PMSG_IS_AUTO(message))
                mutex_unlock(&desc->lock);
 
        return rv;
index 34e3da5..e030428 100644 (file)
@@ -1046,8 +1046,7 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
        /* Non-root devices on a full/low-speed bus must wait for their
         * companion high-speed root hub, in case a handoff is needed.
         */
-       if (!(msg.event & PM_EVENT_AUTO) && udev->parent &&
-                       udev->bus->hs_companion)
+       if (!PMSG_IS_AUTO(msg) && udev->parent && udev->bus->hs_companion)
                device_pm_wait_for_dev(&udev->dev,
                                &udev->bus->hs_companion->root_hub->dev);
 
@@ -1075,7 +1074,7 @@ static int usb_suspend_interface(struct usb_device *udev,
 
        if (driver->suspend) {
                status = driver->suspend(intf, msg);
-               if (status && !(msg.event & PM_EVENT_AUTO))
+               if (status && !PMSG_IS_AUTO(msg))
                        dev_err(&intf->dev, "%s error %d\n",
                                        "suspend", status);
        } else {
@@ -1189,7 +1188,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
                        status = usb_suspend_interface(udev, intf, msg);
 
                        /* Ignore errors during system sleep transitions */
-                       if (!(msg.event & PM_EVENT_AUTO))
+                       if (!PMSG_IS_AUTO(msg))
                                status = 0;
                        if (status != 0)
                                break;
@@ -1199,7 +1198,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
                status = usb_suspend_device(udev, msg);
 
                /* Again, ignore errors during system sleep transitions */
-               if (!(msg.event & PM_EVENT_AUTO))
+               if (!PMSG_IS_AUTO(msg))
                        status = 0;
        }
 
index 73cbbd8..3b9d906 100644 (file)
@@ -1961,8 +1961,9 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
        int             status;
        int             old_state = hcd->state;
 
-       dev_dbg(&rhdev->dev, "bus %s%s\n",
-                       (msg.event & PM_EVENT_AUTO ? "auto-" : ""), &quo