Merge branch 'pm-domains' into pm-for-linus
Rafael J. Wysocki [Fri, 21 Oct 2011 22:21:52 +0000 (00:21 +0200)]
* pm-domains:
  ARM: mach-shmobile: sh7372 A4R support (v4)
  ARM: mach-shmobile: sh7372 A3SP support (v4)
  PM / Sleep: Mark devices involved in wakeup signaling during suspend

231 files changed:
Documentation/ABI/testing/sysfs-class-devfreq [new file with mode: 0644]
Documentation/hwmon/coretemp
Documentation/kernel-parameters.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/scaling.txt
Documentation/power/basic-pm-debugging.txt
Documentation/power/devices.txt
Documentation/power/pm_qos_interface.txt
Documentation/power/runtime_pm.txt
Documentation/usb/power-management.txt
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/include/asm/futex.h
arch/arm/include/asm/unistd.h
arch/arm/kernel/smp_scu.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-exynos4/clock.c
arch/arm/mach-msm/clock.c
arch/arm/mach-s3c2443/clock.c
arch/arm/mach-s5pv210/clock.c
arch/arm/mm/cache-v7.S
arch/arm/mm/dma-mapping.c
arch/arm/plat-s5p/irq-gpioint.c
arch/powerpc/platforms/powermac/pci.c
arch/s390/Kconfig
arch/s390/include/asm/elf.h
arch/s390/kernel/suspend.c
arch/s390/kernel/swsusp_asm64.S
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/kvm/emulate.c
arch/x86/kvm/mmu.c
arch/x86/pci/acpi.c
arch/x86/platform/mrst/vrtc.c
block/blk-core.c
block/blk-sysfs.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/processor_idle.c
drivers/acpi/sleep.c
drivers/base/power/Makefile
drivers/base/power/main.c
drivers/base/power/opp.c
drivers/base/power/power.h
drivers/base/power/qos.c [new file with mode: 0644]
drivers/base/power/runtime.c
drivers/base/power/wakeup.c
drivers/bluetooth/btusb.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/governors/ladder.c
drivers/cpuidle/governors/menu.c
drivers/devfreq/Kconfig [new file with mode: 0644]
drivers/devfreq/Makefile [new file with mode: 0644]
drivers/devfreq/devfreq.c [new file with mode: 0644]
drivers/devfreq/governor.h [new file with mode: 0644]
drivers/devfreq/governor_performance.c [new file with mode: 0644]
drivers/devfreq/governor_powersave.c [new file with mode: 0644]
drivers/devfreq/governor_simpleondemand.c [new file with mode: 0644]
drivers/devfreq/governor_userspace.c [new file with mode: 0644]
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/hwmon/ds620.c
drivers/hwmon/w83791d.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/tty/Kconfig
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
fs/namei.c
fs/namespace.c
fs/nfs/super.c
fs/quota/quota.c
fs/stat.c
include/linux/devfreq.h [new file with mode: 0644]
include/linux/device-mapper.h
include/linux/freezer.h
include/linux/irqdomain.h
include/linux/namei.h
include/linux/netdevice.h
include/linux/opp.h
include/linux/pci.h
include/linux/pm.h
include/linux/pm_qos.h [new file with mode: 0644]
include/linux/pm_qos_params.h [deleted file]
include/linux/ptp_classify.h
include/linux/sched.h
include/linux/suspend.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/freezer.c
kernel/irq/irqdomain.c
kernel/posix-cpu-timers.c
kernel/power/Kconfig
kernel/power/Makefile
kernel/power/console.c
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/power.h
kernel/power/process.c
kernel/power/qos.c [moved from kernel/pm_qos_params.c with 71% similarity]
kernel/power/snapshot.c
kernel/power/suspend.c
kernel/power/swap.c
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/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/wm8753.c
sound/soc/omap/mcpdm.c
sound/soc/omap/mcpdm.h
sound/soc/omap/omap-mcbsp.c
sound/soc/pxa/zylonite.c
sound/usb/card.c
tools/perf/util/evsel.c

diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq
new file mode 100644 (file)
index 0000000..23d78b5
--- /dev/null
@@ -0,0 +1,52 @@
+What:          /sys/class/devfreq/.../
+Date:          September 2011
+Contact:       MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+               Provide a place in sysfs for the devfreq objects.
+               This allows accessing various devfreq specific variables.
+               The name of devfreq object denoted as ... is same as the
+               name of device using devfreq.
+
+What:          /sys/class/devfreq/.../governor
+Date:          September 2011
+Contact:       MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+               The /sys/class/devfreq/.../governor shows the name of the
+               governor used by the corresponding devfreq object.
+
+What:          /sys/class/devfreq/.../cur_freq
+Date:          September 2011
+Contact:       MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+               The /sys/class/devfreq/.../cur_freq shows the current
+               frequency of the corresponding devfreq object.
+
+What:          /sys/class/devfreq/.../central_polling
+Date:          September 2011
+Contact:       MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+               The /sys/class/devfreq/.../central_polling shows whether
+               the devfreq ojbect is using devfreq-provided central
+               polling mechanism or not.
+
+What:          /sys/class/devfreq/.../polling_interval
+Date:          September 2011
+Contact:       MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+               The /sys/class/devfreq/.../polling_interval shows and sets
+               the requested polling interval of the corresponding devfreq
+               object. The values are represented in ms. If the value is
+               less than 1 jiffy, it is considered to be 0, which means
+               no polling. This value is meaningless if the governor is
+               not polling; thus. If the governor is not using
+               devfreq-provided central polling
+               (/sys/class/devfreq/.../central_polling is 0), this value
+               may be useless.
+
+What:          /sys/class/devfreq/.../userspace/set_freq
+Date:          September 2011
+Contact:       MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+               The /sys/class/devfreq/.../userspace/set_freq shows and
+               sets the requested frequency for the devfreq object if
+               userspace governor is in effect.
index fa8776a..84d46c0 100644 (file)
@@ -35,13 +35,6 @@ the Out-Of-Spec bit. Following table summarizes the exported sysfs files:
 All Sysfs entries are named with their core_id (represented here by 'X').
 tempX_input     - Core temperature (in millidegrees Celsius).
 tempX_max       - All cooling devices should be turned on (on Core2).
-                  Initialized with IA32_THERM_INTERRUPT. When the CPU
-                  temperature reaches this temperature, an interrupt is
-                  generated and tempX_max_alarm is set.
-tempX_max_hyst   - If the CPU temperature falls below than temperature,
-                  an interrupt is generated and tempX_max_alarm is reset.
-tempX_max_alarm  - Set if the temperature reaches or exceeds tempX_max.
-                  Reset if the temperature drops to or below tempX_max_hyst.
 tempX_crit      - Maximum junction temperature (in millidegrees Celsius).
 tempX_crit_alarm - Set when Out-of-spec bit is set, never clears.
                   Correct CPU operation is no longer guaranteed.
@@ -49,9 +42,10 @@ tempX_label   - Contains string "Core X", where X is processor
                   number. For Package temp, this will be "Physical id Y",
                   where Y is the package number.
 
-The TjMax temperature is set to 85 degrees C if undocumented model specific
-register (UMSR) 0xee has bit 30 set. If not the TjMax is 100 degrees C as
-(sometimes) documented in processor datasheet.
+On CPU models which support it, TjMax is read from a model-specific register.
+On other models, it is set to an arbitrary value based on weak heuristics.
+If these heuristics don't work for you, you can pass the correct TjMax value
+as a module parameter (tjmax).
 
 Appendix A. Known TjMax lists (TBD):
 Some information comes from ark.intel.com
index 854ed5c..831bde2 100644 (file)
@@ -2240,6 +2240,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        in <PAGE_SIZE> units (needed only for swap files).
                        See  Documentation/power/swsusp-and-swap-files.txt
 
+       resumedelay=    [HIBERNATION] Delay (in seconds) to pause before attempting to
+                       read the resume files
+
+       resumewait      [HIBERNATION] Wait (indefinitely) for resume device to show up.
+                       Useful for devices that are detected asynchronously
+                       (e.g. USB and MMC devices).
+
        hibernate=      [HIBERNATION]
                noresume        Don't check if there's a hibernation image
                                present during boot.
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 ddd7817..62eca08 100644 (file)
@@ -201,3 +201,27 @@ case, you may be able to search for failing drivers by following the procedure
 analogous to the one described in section 1.  If you find some failing drivers,
 you will have to unload them every time before an STR transition (ie. before
 you run s2ram), and please report the problems with them.
+
+There is a debugfs entry which shows the suspend to RAM statistics. Here is an
+example of its output.
+       # mount -t debugfs none /sys/kernel/debug
+       # cat /sys/kernel/debug/suspend_stats
+       success: 20
+       fail: 5
+       failed_freeze: 0
+       failed_prepare: 0
+       failed_suspend: 5
+       failed_suspend_noirq: 0
+       failed_resume: 0
+       failed_resume_noirq: 0
+       failures:
+         last_failed_dev:      alarm
+                               adc
+         last_failed_errno:    -16
+                               -16
+         last_failed_step:     suspend
+                               suspend
+Field success means the success number of suspend to RAM, and field fail means
+the failure number. Others are the failure number of different steps of suspend
+to RAM. suspend_stats just lists the last 2 failed devices, error number and
+failed step of suspend.
index 3384d59..646a89e 100644 (file)
@@ -152,7 +152,9 @@ try to use its wakeup mechanism.  device_set_wakeup_enable() affects this flag;
 for the most part drivers should not change its value.  The initial value of
 should_wakeup is supposed to be false for the majority of devices; the major
 exceptions are power buttons, keyboards, and Ethernet adapters whose WoL
-(wake-on-LAN) feature has been set up with ethtool.
+(wake-on-LAN) feature has been set up with ethtool.  It should also default
+to true for devices that don't generate wakeup requests on their own but merely
+forward wakeup requests from one bus to another (like PCI bridges).
 
 Whether or not a device is capable of issuing wakeup events is a hardware
 matter, and the kernel is responsible for keeping track of it.  By contrast,
@@ -279,10 +281,6 @@ When the system goes into the standby or memory sleep state, the phases are:
        time.)  Unlike the other suspend-related phases, during the prepare
        phase the device tree is traversed top-down.
 
-       In addition to that, if device drivers need to allocate additional
-       memory to be able to hadle device suspend correctly, that should be
-       done in the prepare phase.
-
        After the prepare callback method returns, no new children may be
        registered below the device.  The method may also prepare the device or
        driver in some way for the upcoming system power transition (for
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..0e85608 100644 (file)
@@ -43,13 +43,18 @@ struct dev_pm_ops {
        ...
 };
 
-The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are
-executed by the PM core for either the device type, or the class (if the device
-type's struct dev_pm_ops object does not exist), or the bus type (if the
-device type's and class' struct dev_pm_ops objects do not exist) of the given
-device (this allows device types to override callbacks provided by bus types or
-classes if necessary).  The bus type, device type and class callbacks are
-referred to as subsystem-level callbacks in what follows.
+The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks
+are executed by the PM core for either the power domain, or the device type
+(if the device power domain's struct dev_pm_ops does not exist), or the class
+(if the device power domain's and type's struct dev_pm_ops object does not
+exist), or the bus type (if the device power domain's, type's and class'
+struct dev_pm_ops objects do not exist) of the given device, so the priority
+order of callbacks from high to low is that power domain callbacks, device
+type callbacks, class callbacks and bus type callbacks, and the high priority
+one will take precedence over low priority one. The bus type, device type and
+class callbacks are referred to as subsystem-level callbacks in what follows,
+and generally speaking, the power domain callbacks are used for representing
+power domains within a SoC.
 
 By default, the callbacks are always invoked in process context with interrupts
 enabled.  However, subsystems can use the pm_runtime_irq_safe() helper function
@@ -477,12 +482,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..1774b68 100644 (file)
@@ -2733,7 +2733,7 @@ F:        fs/freevxfs/
 FREEZER
 M:     Pavel Machek <pavel@ucw.cz>
 M:     "Rafael J. Wysocki" <rjw@sisk.pl>
-L:     linux-pm@lists.linux-foundation.org
+L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     Documentation/power/freezing-of-tasks.txt
 F:     include/linux/freezer.h
@@ -2995,7 +2995,7 @@ F:        drivers/video/hgafb.c
 HIBERNATION (aka Software Suspend, aka swsusp)
 M:     Pavel Machek <pavel@ucw.cz>
 M:     "Rafael J. Wysocki" <rjw@sisk.pl>
-L:     linux-pm@lists.linux-foundation.org
+L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     arch/x86/power/
 F:     drivers/base/power/
@@ -3189,7 +3189,7 @@ F:        drivers/ide/ide-cd*
 
 IDLE-I7300
 M:     Andy Henroid <andrew.d.henroid@intel.com>
-L:     linux-pm@lists.linux-foundation.org
+L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     drivers/idle/i7300_idle.c
 
@@ -3272,7 +3272,7 @@ F:        firmware/isci/
 
 INTEL IDLE DRIVER
 M:     Len Brown <lenb@kernel.org>
-L:     linux-pm@lists.linux-foundation.org
+L:     linux-pm@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-idle-2.6.git
 S:     Supported
 F:     drivers/idle/intel_idle.c
@@ -3376,7 +3376,7 @@ F:        drivers/net/ixgbevf/
 
 INTEL MRST PMU DRIVER
 M:     Len Brown <len.brown@intel.com>
-L:     linux-pm@lists.linux-foundation.org
+L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     arch/x86/platform/mrst/pmu.*
 
@@ -6306,7 +6306,7 @@ SUSPEND TO RAM
 M:     Len Brown <len.brown@intel.com>
 M:     Pavel Machek <pavel@ucw.cz>
 M:     "Rafael J. Wysocki" <rjw@sisk.pl>
-L:     linux-pm@lists.linux-foundation.org
+L:     linux-pm@vger.kernel.org
 S:     Supported
 F:     Documentation/power/
 F:     arch/x86/kernel/acpi/
@@ -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 733dcba..31f967c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 1
 SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION = -rc9
 NAME = "Divemaster Edition"
 
 # *DOCUMENTATION*
index 3269576..3146ed3 100644 (file)
@@ -1283,6 +1283,20 @@ config ARM_ERRATA_364296
          processor into full low interrupt latency mode. ARM11MPCore
          is not affected.
 
+config ARM_ERRATA_764369
+       bool "ARM errata: Data cache line maintenance operation by MVA may not succeed"
+       depends on CPU_V7 && SMP
+       help
+         This option enables the workaround for erratum 764369
+         affecting Cortex-A9 MPCore with two or more processors (all
+         current revisions). Under certain timing circumstances, a data
+         cache line maintenance operation by MVA targeting an Inner
+         Shareable memory region may fail to proceed up to either the
+         Point of Coherency or to the Point of Unification of the
+         system. This workaround adds a DSB instruction before the
+         relevant cache maintenance functions and sets a specific bit
+         in the diagnostic control register of the SCU.
+
 endmenu
 
 source "arch/arm/common/Kconfig"
index 8c73900..253cc86 100644 (file)
 
 #ifdef CONFIG_SMP
 
-#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)     \
+#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg)        \
        smp_mb();                                               \
        __asm__ __volatile__(                                   \
-       "1:     ldrex   %1, [%2]\n"                             \
+       "1:     ldrex   %1, [%3]\n"                             \
        "       " insn "\n"                                     \
-       "2:     strex   %1, %0, [%2]\n"                         \
-       "       teq     %1, #0\n"                               \
+       "2:     strex   %2, %0, [%3]\n"                         \
+       "       teq     %2, #0\n"                               \
        "       bne     1b\n"                                   \
        "       mov     %0, #0\n"                               \
-       __futex_atomic_ex_table("%4")                           \
-       : "=&r" (ret), "=&r" (oldval)                           \
+       __futex_atomic_ex_table("%5")                           \
+       : "=&r" (ret), "=&r" (oldval), "=&r" (tmp)              \
        : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT)              \
        : "cc", "memory")
 
@@ -73,14 +73,14 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 #include <linux/preempt.h>
 #include <asm/domain.h>
 
-#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)     \
+#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg)        \
        __asm__ __volatile__(                                   \
-       "1:     " T(ldr) "      %1, [%2]\n"                     \
+       "1:     " T(ldr) "      %1, [%3]\n"                     \
        "       " insn "\n"                                     \
-       "2:     " T(str) "      %0, [%2]\n"                     \
+       "2:     " T(str) "      %0, [%3]\n"                     \
        "       mov     %0, #0\n"                               \
-       __futex_atomic_ex_table("%4")                           \
-       : "=&r" (ret), "=&r" (oldval)                           \
+       __futex_atomic_ex_table("%5")                           \
+       : "=&r" (ret), "=&r" (oldval), "=&r" (tmp)              \
        : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT)              \
        : "cc", "memory")
 
@@ -117,7 +117,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
        int cmp = (encoded_op >> 24) & 15;
        int oparg = (encoded_op << 8) >> 20;
        int cmparg = (encoded_op << 20) >> 20;
-       int oldval = 0, ret;
+       int oldval = 0, ret, tmp;
 
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
@@ -129,19 +129,19 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
 
        switch (op) {
        case FUTEX_OP_SET:
-               __futex_atomic_op("mov  %0, %3", ret, oldval, uaddr, oparg);
+               __futex_atomic_op("mov  %0, %4", ret, oldval, tmp, uaddr, oparg);
                break;
        case FUTEX_OP_ADD:
-               __futex_atomic_op("add  %0, %1, %3", ret, oldval, uaddr, oparg);
+               __futex_atomic_op("add  %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
                break;
        case FUTEX_OP_OR:
-               __futex_atomic_op("orr  %0, %1, %3", ret, oldval, uaddr, oparg);
+               __futex_atomic_op("orr  %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
                break;
        case FUTEX_OP_ANDN:
-               __futex_atomic_op("and  %0, %1, %3", ret, oldval, uaddr, ~oparg);
+               __futex_atomic_op("and  %0, %1, %4", ret, oldval, tmp, uaddr, ~oparg);
                break;
        case FUTEX_OP_XOR:
-               __futex_atomic_op("eor  %0, %1, %3", ret, oldval, uaddr, oparg);
+               __futex_atomic_op("eor  %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
                break;
        default:
                ret = -ENOSYS;
index 2c04ed5..c60a294 100644 (file)
 /*
  * Unimplemented (or alternatively implemented) syscalls
  */
-#define __IGNORE_fadvise64_64          1
-#define __IGNORE_migrate_pages         1
+#define __IGNORE_fadvise64_64
+#define __IGNORE_migrate_pages
 
 #endif /* __KERNEL__ */
 #endif /* __ASM_ARM_UNISTD_H */
index 79ed5e7..7fcddb7 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <asm/smp_scu.h>
 #include <asm/cacheflush.h>
+#include <asm/cputype.h>
 
 #define SCU_CTRL               0x00
 #define SCU_CONFIG             0x04
@@ -37,6 +38,15 @@ void __init scu_enable(void __iomem *scu_base)
 {
        u32 scu_ctrl;
 
+#ifdef CONFIG_ARM_ERRATA_764369
+       /* Cortex-A9 only */
+       if ((read_cpuid(CPUID_ID) & 0xff0ffff0) == 0x410fc090) {
+               scu_ctrl = __raw_readl(scu_base + 0x30);
+               if (!(scu_ctrl & 1))
+                       __raw_writel(scu_ctrl | 0x1, scu_base + 0x30);
+       }
+#endif
+
        scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
        /* already enabled? */
        if (scu_ctrl & 1)
index bf977f8..4e66f62 100644 (file)
 
 #if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)
 #define ARM_EXIT_KEEP(x)       x
+#define ARM_EXIT_DISCARD(x)
 #else
 #define ARM_EXIT_KEEP(x)
+#define ARM_EXIT_DISCARD(x)    x
 #endif
 
 OUTPUT_ARCH(arm)
@@ -39,6 +41,11 @@ jiffies = jiffies_64 + 4;
 SECTIONS
 {
        /*
+        * XXX: The linker does not define how output sections are
+        * assigned to input sections when there are multiple statements
+        * matching the same input section name.  There is no documented
+        * order of matching.
+        *
         * unwind exit sections must be discarded before the rest of the
         * unwind sections get included.
         */
@@ -47,6 +54,9 @@ SECTIONS
                *(.ARM.extab.exit.text)
                ARM_CPU_DISCARD(*(.ARM.exidx.cpuexit.text))
                ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text))
+               ARM_EXIT_DISCARD(EXIT_TEXT)
+               ARM_EXIT_DISCARD(EXIT_DATA)
+               EXIT_CALL
 #ifndef CONFIG_HOTPLUG
                *(.ARM.exidx.devexit.text)
                *(.ARM.extab.devexit.text)
@@ -58,6 +68,8 @@ SECTIONS
 #ifndef CONFIG_SMP_ON_UP
                *(.alt.smp.init)
 #endif
+               *(.discard)
+               *(.discard.*)
        }
 
 #ifdef CONFIG_XIP_KERNEL
@@ -279,9 +291,6 @@ SECTIONS
 
        STABS_DEBUG
        .comment 0 : { *(.comment) }
-
-       /* Default discards */
-       DISCARDS
 }
 
 /*
index 79d6cd0..86964d2 100644 (file)
@@ -899,8 +899,7 @@ static struct clksrc_clk clksrcs[] = {
                .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 28, .size = 4 },
        }, {
                .clk            = {
-                       .name           = "sclk_cam",
-                       .devname        = "exynos4-fimc.0",
+                       .name           = "sclk_cam0",
                        .enable         = exynos4_clksrc_mask_cam_ctrl,
                        .ctrlbit        = (1 << 16),
                },
@@ -909,8 +908,7 @@ static struct clksrc_clk clksrcs[] = {
                .reg_div = { .reg = S5P_CLKDIV_CAM, .shift = 16, .size = 4 },
        }, {
                .clk            = {
-                       .name           = "sclk_cam",
-                       .devname        = "exynos4-fimc.1",
+                       .name           = "sclk_cam1",
                        .enable         = exynos4_clksrc_mask_cam_ctrl,
                        .ctrlbit        = (1 << 20),
                },
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 a1a7176..38058af 100644 (file)
@@ -128,7 +128,7 @@ static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
                unsigned long clkcon0;
 
                clkcon0 = __raw_readl(S3C2443_CLKDIV0);
-               clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
+               clkcon0 &= ~S3C2443_CLKDIV0_ARMDIV_MASK;
                clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
                __raw_writel(clkcon0, S3C2443_CLKDIV0);
        }
index 52a8e60..f5f8fa8 100644 (file)
@@ -815,8 +815,7 @@ static struct clksrc_clk clksrcs[] = {
                .reg_div = { .reg = S5P_CLK_DIV3, .shift = 20, .size = 4 },
        }, {
                .clk            = {
-                       .name           = "sclk_cam",
-                       .devname        = "s5pv210-fimc.0",
+                       .name           = "sclk_cam0",
                        .enable         = s5pv210_clk_mask0_ctrl,
                        .ctrlbit        = (1 << 3),
                },
@@ -825,8 +824,7 @@ static struct clksrc_clk clksrcs[] = {
                .reg_div = { .reg = S5P_CLK_DIV1, .shift = 12, .size = 4 },
        }, {
                .clk            = {
-                       .name           = "sclk_cam",
-                       .devname        = "s5pv210-fimc.1",
+                       .name           = "sclk_cam1",
                        .enable         = s5pv210_clk_mask0_ctrl,
                        .ctrlbit        = (1 << 4),
                },
index 3b24bfa..07c4bc8 100644 (file)
@@ -174,6 +174,10 @@ ENTRY(v7_coherent_user_range)
        dcache_line_size r2, r3
        sub     r3, r2, #1
        bic     r12, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+       ALT_SMP(W(dsb))
+       ALT_UP(W(nop))
+#endif
 1:
  USER( mcr     p15, 0, r12, c7, c11, 1 )       @ clean D line to the point of unification
        add     r12, r12, r2
@@ -223,6 +227,10 @@ ENTRY(v7_flush_kern_dcache_area)
        add     r1, r0, r1
        sub     r3, r2, #1
        bic     r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+       ALT_SMP(W(dsb))
+       ALT_UP(W(nop))
+#endif
 1:
        mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line / unified line
        add     r0, r0, r2
@@ -247,6 +255,10 @@ v7_dma_inv_range:
        sub     r3, r2, #1
        tst     r0, r3
        bic     r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+       ALT_SMP(W(dsb))
+       ALT_UP(W(nop))
+#endif
        mcrne   p15, 0, r0, c7, c14, 1          @ clean & invalidate D / U line
 
        tst     r1, r3
@@ -270,6 +282,10 @@ v7_dma_clean_range:
        dcache_line_size r2, r3
        sub     r3, r2, #1
        bic     r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+       ALT_SMP(W(dsb))
+       ALT_UP(W(nop))
+#endif
 1:
        mcr     p15, 0, r0, c7, c10, 1          @ clean D / U line
        add     r0, r0, r2
@@ -288,6 +304,10 @@ ENTRY(v7_dma_flush_range)
        dcache_line_size r2, r3
        sub     r3, r2, #1
        bic     r0, r0, r3
+#ifdef CONFIG_ARM_ERRATA_764369
+       ALT_SMP(W(dsb))
+       ALT_UP(W(nop))
+#endif
 1:
        mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D / U line
        add     r0, r0, r2
index 0a0a1e7..c3ff82f 100644 (file)
@@ -324,6 +324,8 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
 
        if (addr)
                *handle = pfn_to_dma(dev, page_to_pfn(page));
+       else
+               __dma_free_buffer(page, size);
 
        return addr;
 }
index f71078e..f88216d 100644 (file)
@@ -114,17 +114,18 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
 {
        static int used_gpioint_groups = 0;
        int group = chip->group;
-       struct s5p_gpioint_bank *bank = NULL;
+       struct s5p_gpioint_bank *b, *bank = NULL;
        struct irq_chip_generic *gc;
        struct irq_chip_type *ct;
 
        if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
                return -ENOMEM;
 
-       list_for_each_entry(bank, &banks, list) {
-               if (group >= bank->start &&
-                   group < bank->start + bank->nr_groups)
+       list_for_each_entry(b, &banks, list) {
+               if (group >= b->start && group < b->start + b->nr_groups) {
+                       bank = b;
                        break;
+               }
        }
        if (!bank)
                return -EINVAL;
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 ed5cb5a..6b99fc3 100644 (file)
@@ -91,6 +91,7 @@ config S390
        select HAVE_ARCH_MUTEX_CPU_RELAX
        select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
        select HAVE_RCU_TABLE_FREE if SMP
+       select ARCH_SAVE_PAGE_KEYS if HIBERNATION
        select ARCH_INLINE_SPIN_TRYLOCK
        select ARCH_INLINE_SPIN_TRYLOCK_BH
        select ARCH_INLINE_SPIN_LOCK
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 cf9e5c6..b6f9afe 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/pfn.h>
+#include <linux/mm.h>
 #include <asm/system.h>
 
 /*
  */
 extern const void __nosave_begin, __nosave_end;
 
+/*
+ * The restore of the saved pages in an hibernation image will set
+ * the change and referenced bits in the storage key for each page.
+ * Overindication of the referenced bits after an hibernation cycle
+ * does not cause any harm but the overindication of the change bits
+ * would cause trouble.
+ * Use the ARCH_SAVE_PAGE_KEYS hooks to save the storage key of each
+ * page to the most significant byte of the associated page frame
+ * number in the hibernation image.
+ */
+
+/*
+ * Key storage is allocated as a linked list of pages.
+ * The size of the keys array is (PAGE_SIZE - sizeof(long))
+ */
+struct page_key_data {
+       struct page_key_data *next;
+       unsigned char data[];
+};
+
+#define PAGE_KEY_DATA_SIZE     (PAGE_SIZE - sizeof(struct page_key_data *))
+
+static struct page_key_data *page_key_data;
+static struct page_key_data *page_key_rp, *page_key_wp;
+static unsigned long page_key_rx, page_key_wx;
+
+/*
+ * For each page in the hibernation image one additional byte is
+ * stored in the most significant byte of the page frame number.
+ * On suspend no additional memory is required but on resume the
+ * keys need to be memorized until the page data has been restored.
+ * Only then can the storage keys be set to their old state.
+ */
+unsigned long page_key_additional_pages(unsigned long pages)
+{
+       return DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE);
+}
+
+/*
+ * Free page_key_data list of arrays.
+ */
+void page_key_free(void)
+{
+       struct page_key_data *pkd;
+
+       while (page_key_data) {
+               pkd = page_key_data;
+               page_key_data = pkd->next;
+               free_page((unsigned long) pkd);
+       }
+}
+
+/*
+ * Allocate page_key_data list of arrays with enough room to store
+ * one byte for each page in the hibernation image.
+ */
+int page_key_alloc(unsigned long pages)
+{
+       struct page_key_data *pk;
+       unsigned long size;
+
+       size = DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE);
+       while (size--) {
+               pk = (struct page_key_data *) get_zeroed_page(GFP_KERNEL);
+               if (!pk) {
+                       page_key_free();
+                       return -ENOMEM;
+               }
+               pk->next = page_key_data;
+               page_key_data = pk;
+       }
+       page_key_rp = page_key_wp = page_key_data;
+       page_key_rx = page_key_wx = 0;
+       return 0;
+}
+
+/*
+ * Save the storage key into the upper 8 bits of the page frame number.
+ */
+void page_key_read(unsigned long *pfn)
+{
+       unsigned long addr;
+
+       addr = (unsigned long) page_address(pfn_to_page(*pfn));
+       *(unsigned char *) pfn = (unsigned char) page_get_storage_key(addr);
+}
+
+/*
+ * Extract the storage key from the upper 8 bits of the page frame number
+ * and store it in the page_key_data list of arrays.
+ */
+void page_key_memorize(unsigned long *pfn)
+{
+       page_key_wp->data[page_key_wx] = *(unsigned char *) pfn;
+       *(unsigned char *) pfn = 0;
+       if (++page_key_wx < PAGE_KEY_DATA_SIZE)
+               return;
+       page_key_wp = page_key_wp->next;
+       page_key_wx = 0;
+}
+
+/*
+ * Get the next key from the page_key_data list of arrays and set the
+ * storage key of the page referred by @address. If @address refers to
+ * a "safe" page the swsusp_arch_resume code will transfer the storage
+ * key from the buffer page to the original page.
+ */
+void page_key_write(void *address)
+{
+       page_set_storage_key((unsigned long) address,
+                            page_key_rp->data[page_key_rx], 0);
+       if (++page_key_rx >= PAGE_KEY_DATA_SIZE)
+               return;
+       page_key_rp = page_key_rp->next;
+       page_key_rx = 0;
+}
+
 int pfn_is_nosave(unsigned long pfn)
 {
        unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin));
index 51bcdb5..acb78cd 100644 (file)
@@ -136,11 +136,14 @@ ENTRY(swsusp_arch_resume)
 0:
        lg      %r2,8(%r1)
        lg      %r4,0(%r1)
+       iske    %r0,%r4
        lghi    %r3,PAGE_SIZE
        lghi    %r5,PAGE_SIZE
 1:
        mvcle   %r2,%r4,0
        jo      1b
+       lg      %r2,8(%r1)
+       sske    %r0,%r2
        lg      %r1,16(%r1)
        ltgr    %r1,%r1
        jnz     0b
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 6f08bc9..8b4cc5f 100644 (file)
@@ -3603,7 +3603,7 @@ done_prefixes:
                break;
        case Src2CL:
                ctxt->src2.bytes = 1;
-               ctxt->src2.val = ctxt->regs[VCPU_REGS_RCX] & 0x8;
+               ctxt->src2.val = ctxt->regs[VCPU_REGS_RCX] & 0xff;
                break;
        case Src2ImmByte:
                rc = decode_imm(ctxt, &ctxt->src2, 1, true);
index 1c5b693..8e8da79 100644 (file)
@@ -400,7 +400,8 @@ static u64 __update_clear_spte_slow(u64 *sptep, u64 spte)
 
        /* xchg acts as a barrier before the setting of the high bits */
        orig.spte_low = xchg(&ssptep->spte_low, sspte.spte_low);
-       orig.spte_high = ssptep->spte_high = sspte.spte_high;
+       orig.spte_high = ssptep->spte_high;
+       ssptep->spte_high = sspte.spte_high;
        count_spte_clear(sptep, spte);
 
        return orig.spte;
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 95b9e7e..a1efd75 100644 (file)
@@ -130,4 +130,6 @@ source "drivers/iommu/Kconfig"
 
 source "drivers/virt/Kconfig"
 
+source "drivers/devfreq/Kconfig"
+
 endmenu
index 7fa433a..97c957b 100644 (file)
@@ -127,3 +127,5 @@ obj-$(CONFIG_IOMMU_SUPPORT) += iommu/
 
 # Virtualization drivers
 obj-$(CONFIG_VIRT_DRIVERS)     += virt/
+
+obj-$(CONFIG_PM_DEVFREQ)       += devfreq/
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 3ed80b2..28a3e96 100644 (file)
@@ -444,6 +444,22 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
                DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"),
                },
        },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VGN-SR26GN_P",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VGN-FW520F",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"),
+               },
+       },
        {},
 };
 #endif /* CONFIG_SUSPEND */
index 6488ce1..81676dd 100644 (file)
@@ -1,4 +1,4 @@
-obj-$(CONFIG_PM)       += sysfs.o generic_ops.o common.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 1e15732..59f8ab2 100644 (file)
@@ -46,6 +46,7 @@ LIST_HEAD(dpm_prepared_list);
 LIST_HEAD(dpm_suspended_list);
 LIST_HEAD(dpm_noirq_list);
 
+struct suspend_stats suspend_stats;
 static DEFINE_MUTEX(dpm_list_mtx);
 static pm_message_t pm_transition;
 
@@ -65,6 +66,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 +98,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 +112,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);
@@ -464,8 +468,12 @@ void dpm_resume_noirq(pm_message_t state)
                mutex_unlock(&dpm_list_mtx);
 
                error = device_resume_noirq(dev, state);
-               if (error)
+               if (error) {
+                       suspend_stats.failed_resume_noirq++;
+                       dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);
+                       dpm_save_failed_dev(dev_name(dev));
                        pm_dev_err(dev, state, " early", error);
+               }
 
                mutex_lock(&dpm_list_mtx);
                put_device(dev);
@@ -626,8 +634,12 @@ void dpm_resume(pm_message_t state)
                        mutex_unlock(&dpm_list_mtx);
 
                        error = device_resume(dev, state, false);
-                       if (error)
+                       if (error) {
+                               suspend_stats.failed_resume++;
+                               dpm_save_failed_step(SUSPEND_RESUME);
+                               dpm_save_failed_dev(dev_name(dev));
                                pm_dev_err(dev, state, "", error);
+                       }
 
                        mutex_lock(&dpm_list_mtx);
                }
@@ -802,6 +814,9 @@ int dpm_suspend_noirq(pm_message_t state)
                mutex_lock(&dpm_list_mtx);
                if (error) {
                        pm_dev_err(dev, state, " late", error);
+                       suspend_stats.failed_suspend_noirq++;
+                       dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);
+                       dpm_save_failed_dev(dev_name(dev));
                        put_device(dev);
                        break;
                }
@@ -927,8 +942,10 @@ static void async_suspend(void *data, async_cookie_t cookie)
        int error;
 
        error = __device_suspend(dev, pm_transition, true);
-       if (error)
+       if (error) {
+               dpm_save_failed_dev(dev_name(dev));
                pm_dev_err(dev, pm_transition, " async", error);
+       }
 
        put_device(dev);
 }
@@ -971,6 +988,7 @@ int dpm_suspend(pm_message_t state)
                mutex_lock(&dpm_list_mtx);
                if (error) {
                        pm_dev_err(dev, state, "", error);
+                       dpm_save_failed_dev(dev_name(dev));
                        put_device(dev);
                        break;
                }
@@ -984,7 +1002,10 @@ int dpm_suspend(pm_message_t state)
        async_synchronize_full();
        if (!error)
                error = async_error;
-       if (!error)
+       if (error) {
+               suspend_stats.failed_suspend++;
+               dpm_save_failed_step(SUSPEND_SUSPEND);
+       } else
                dpm_show_time(starttime, state, NULL);
        return error;
 }
@@ -1094,7 +1115,10 @@ int dpm_suspend_start(pm_message_t state)
        int error;
 
        error = dpm_prepare(state);
-       if (!error)
+       if (error) {
+               suspend_stats.failed_prepare++;
+               dpm_save_failed_step(SUSPEND_PREPARE);
+       } else
                error = dpm_suspend(state);
        return error;
 }
index b23de18..434a6c0 100644 (file)
@@ -73,6 +73,7 @@ struct opp {
  *             RCU usage: nodes are not modified in the list of device_opp,
  *             however addition is possible and is secured by dev_opp_list_lock
  * @dev:       device pointer
+ * @head:      notifier head to notify the OPP availability changes.
  * @opp_list:  list of opps
  *
  * This is an internal data structure maintaining the link to opps attached to
@@ -83,6 +84,7 @@ struct device_opp {
        struct list_head node;
 
        struct device *dev;
+       struct srcu_notifier_head head;
        struct list_head opp_list;
 };
 
@@ -404,6 +406,7 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
                }
 
                dev_opp->dev = dev;
+               srcu_init_notifier_head(&dev_opp->head);
                INIT_LIST_HEAD(&dev_opp->opp_list);
 
                /* Secure the device list modification */
@@ -428,6 +431,11 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
        list_add_rcu(&new_opp->node, head);
        mutex_unlock(&dev_opp_list_lock);
 
+       /*
+        * Notify the changes in the availability of the operable
+        * frequency/voltage list.
+        */
+       srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ADD, new_opp);
        return 0;
 }
 
@@ -504,6 +512,14 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
        mutex_unlock(&dev_opp_list_lock);
        synchronize_rcu();
 
+       /* Notify the change of the OPP availability */
+       if (availability_req)
+               srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ENABLE,
+                                        new_opp);
+       else
+               srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE,
+                                        new_opp);
+
        /* clean up old opp */
        new_opp = opp;
        goto out;
@@ -643,3 +659,17 @@ void opp_free_cpufreq_table(struct device *dev,
        *table = NULL;
 }
 #endif         /* CONFIG_CPU_FREQ */
+
+/**
+ * opp_get_notifier() - find notifier_head of the device with opp
+ * @dev:       device pointer used to lookup device OPPs.
+ */
+struct srcu_notifier_head *opp_get_notifier(struct device *dev)
+{
+       struct device_opp *dev_opp = find_device_opp(dev);
+
+       if (IS_ERR(dev_opp))
+               return ERR_PTR(PTR_ERR(dev_opp)); /* matching type */
+
+       return &dev_opp->head;
+}
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..6bb3aaf 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;
 }
@@ -277,14 +286,16 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
  * @dev: Device to suspend.
  * @rpmflags: Flag bits.
  *
- * Check if the device's runtime PM status allows it to be suspended.  If
- * another suspend has been started earlier, either return immediately or wait
- * for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC flags.  Cancel a
- * pending idle notification.  If the RPM_ASYNC flag is set then queue a
- * suspend request; otherwise run the ->runtime_suspend() callback directly.
- * If a deferred resume was requested while the callback was running then carry
- * it out; otherwise send an idle notification for the device (if the suspend
- * failed) or for its parent (if the suspend succeeded).
+ * Check if the device's runtime PM status allows it to be suspended.
+ * Cancel a pending idle notification, autosuspend or suspend. If
+ * another suspend has been started earlier, either return immediately
+ * or wait for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC
+ * flags. If the RPM_ASYNC flag is set then queue a suspend request;
+ * otherwise run the ->runtime_suspend() callback directly. When
+ * ->runtime_suspend succeeded, if a deferred resume was requested while
+ * the callback was running then carry it out, otherwise send an idle
+ * notification for its parent (if the suspend succeeded and both
+ * ignore_children of parent->power and irq_safe of dev->power are not set).
  *
  * This function must be called under dev->power.lock with interrupts disabled.
  */
@@ -295,7 +306,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 +358,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,
@@ -400,15 +420,16 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                        dev->power.runtime_error = 0;
                else
                        pm_runtime_cancel_pending(dev);
-       } else {
+               wake_up_all(&dev->power.wait_queue);
+               goto out;
+       }
  no_callback:
-               __update_runtime_status(dev, RPM_SUSPENDED);
-               pm_runtime_deactivate_timer(dev);
+       __update_runtime_status(dev, RPM_SUSPENDED);
+       pm_runtime_deactivate_timer(dev);
 
-               if (dev->parent) {
-                       parent = dev->parent;
-                       atomic_add_unless(&parent->power.child_count, -1, 0);
-               }
+       if (dev->parent) {
+               parent = dev->parent;
+               atomic_add_unless(&parent->power.child_count, -1, 0);
        }
        wake_up_all(&dev->power.wait_queue);
 
@@ -430,7 +451,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 +480,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 +517,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 +645,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 +762,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 +794,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 +825,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 84f7c7d..14ee07e 100644 (file)
@@ -276,7 +276,9 @@ EXPORT_SYMBOL_GPL(device_set_wakeup_capable);
  *
  * By default, most devices should leave wakeup disabled.  The exceptions are
  * devices that everyone expects to be wakeup sources: keyboards, power buttons,
- * possibly network interfaces, etc.
+ * possibly network interfaces, etc.  Also, devices that don't generate their
+ * own wakeup requests but merely forward requests from one bus to another
+ * (like PCI bridges) should have wakeup enabled by default.
  */
 int device_init_wakeup(struct device *dev, bool enable)
 {
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>
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
new file mode 100644 (file)
index 0000000..643b055
--- /dev/null
@@ -0,0 +1,75 @@
+config ARCH_HAS_DEVFREQ
+       bool
+       depends on ARCH_HAS_OPP
+       help
+         Denotes that the architecture supports DEVFREQ. If the architecture
+         supports multiple OPP entries per device and the frequency of the
+         devices with OPPs may be altered dynamically, the architecture
+         supports DEVFREQ.
+
+menuconfig PM_DEVFREQ
+       bool "Generic Dynamic Voltage and Frequency Scaling (DVFS) support"
+       depends on PM_OPP && ARCH_HAS_DEVFREQ
+       help
+         With OPP support, a device may have a list of frequencies and
+         voltages available. DEVFREQ, a generic DVFS framework can be
+         registered for a device with OPP support in order to let the
+         governor provided to DEVFREQ choose an operating frequency
+         based on the OPP's list and the policy given with DEVFREQ.
+
+         Each device may have its own governor and policy. DEVFREQ can
+         reevaluate the device state periodically and/or based on the
+         OPP list changes (each frequency/voltage pair in OPP may be
+         disabled or enabled).
+
+         Like some CPUs with CPUFREQ, a device may have multiple clocks.
+         However, because the clock frequencies of a single device are
+         determined by the single device's state, an instance of DEVFREQ
+         is attached to a single device and returns a "representative"
+         clock frequency from the OPP of the device, which is also attached
+         to a device by 1-to-1. The device registering DEVFREQ takes the
+         responsiblity to "interpret" the frequency listed in OPP and
+         to set its every clock accordingly with the "target" callback
+         given to DEVFREQ.
+
+if PM_DEVFREQ
+
+comment "DEVFREQ Governors"
+
+config DEVFREQ_GOV_SIMPLE_ONDEMAND
+       bool "Simple Ondemand"
+       help
+         Chooses frequency based on the recent load on the device. Works
+         similar as ONDEMAND governor of CPUFREQ does. A device with
+         Simple-Ondemand should be able to provide busy/total counter
+         values that imply the usage rate. A device may provide tuned
+         values to the governor with data field at devfreq_add_device().
+
+config DEVFREQ_GOV_PERFORMANCE
+       bool "Performance"
+       help
+         Sets the frequency at the maximum available frequency.
+         This governor always returns UINT_MAX as frequency so that
+         the DEVFREQ framework returns the highest frequency available
+         at any time.
+
+config DEVFREQ_GOV_POWERSAVE
+       bool "Powersave"
+       help
+         Sets the frequency at the minimum available frequency.
+         This governor always returns 0 as frequency so that
+         the DEVFREQ framework returns the lowest frequency available
+         at any time.
+
+config DEVFREQ_GOV_USERSPACE
+       bool "Userspace"
+       help
+         Sets the frequency at the user specified one.
+         This governor returns the user configured frequency if there
+         has been an input to /sys/devices/.../power/devfreq_set_freq.
+         Otherwise, the governor does not change the frequnecy
+         given at the initialization.
+
+comment "DEVFREQ Drivers"
+
+endif # PM_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
new file mode 100644 (file)
index 0000000..4564a89
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_PM_DEVFREQ)       += devfreq.o
+obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)      += governor_simpleondemand.o
+obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE)  += governor_performance.o
+obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)    += governor_powersave.o
+obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)    += governor_userspace.o
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
new file mode 100644 (file)
index 0000000..5d15b81
--- /dev/null
@@ -0,0 +1,601 @@
+/*
+ * devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework
+ *         for Non-CPU Devices.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ *     MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/opp.h>
+#include <linux/devfreq.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/printk.h>
+#include <linux/hrtimer.h>
+#include "governor.h"
+
+struct class *devfreq_class;
+
+/*
+ * devfreq_work periodically monitors every registered device.
+ * The minimum polling interval is one jiffy. The polling interval is
+ * determined by the minimum polling period among all polling devfreq
+ * devices. The resolution of polling interval is one jiffy.
+ */
+static bool polling;
+static struct workqueue_struct *devfreq_wq;
+static struct delayed_work devfreq_work;
+
+/* wait removing if this is to be removed */
+static struct devfreq *wait_remove_device;
+
+/* The list of all device-devfreq */
+static LIST_HEAD(devfreq_list);
+static DEFINE_MUTEX(devfreq_list_lock);
+
+/**
+ * find_device_devfreq() - find devfreq struct using device pointer
+ * @dev:       device pointer used to lookup device devfreq.
+ *
+ * Search the list of device devfreqs and return the matched device's
+ * devfreq info. devfreq_list_lock should be held by the caller.
+ */
+static struct devfreq *find_device_devfreq(struct device *dev)
+{
+       struct devfreq *tmp_devfreq;
+
+       if (unlikely(IS_ERR_OR_NULL(dev))) {
+               pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
+               return ERR_PTR(-EINVAL);
+       }
+       WARN(!mutex_is_locked(&devfreq_list_lock),
+            "devfreq_list_lock must be locked.");
+
+       list_for_each_entry(tmp_devfreq, &devfreq_list, node) {
+               if (tmp_devfreq->dev.parent == dev)
+                       return tmp_devfreq;
+       }
+
+       return ERR_PTR(-ENODEV);
+}
+
+/**
+ * update_devfreq() - Reevaluate the device and configure frequency.
+ * @devfreq:   the devfreq instance.
+ *
+ * Note: Lock devfreq->lock before calling update_devfreq
+ *      This function is exported for governors.
+ */
+int update_devfreq(struct devfreq *devfreq)
+{
+       unsigned long freq;
+       int err = 0;
+
+       if (!mutex_is_locked(&devfreq->lock)) {
+               WARN(true, "devfreq->lock must be locked by the caller.\n");
+               return -EINVAL;
+       }
+
+       /* Reevaluate the proper frequency */
+       err = devfreq->governor->get_target_freq(devfreq, &freq);
+       if (err)
+               return err;
+
+       err = devfreq->profile->target(devfreq->dev.parent, &freq);
+       if (err)
+               return err;
+
+       devfreq->previous_freq = freq;
+       return err;
+}
+
+/**
+ * devfreq_notifier_call() - Notify that the device frequency requirements
+ *                        has been changed out of devfreq framework.
+ * @nb         the notifier_block (supposed to be devfreq->nb)
+ * @type       not used
+ * @devp       not used
+ *
+ * Called by a notifier that uses devfreq->nb.
+ */
+static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
+                                void *devp)
+{
+       struct devfreq *devfreq = container_of(nb, struct devfreq, nb);
+       int ret;
+
+       mutex_lock(&devfreq->lock);
+       ret = update_devfreq(devfreq);
+       mutex_unlock(&devfreq->lock);
+
+       return ret;
+}
+
+/**
+ * _remove_devfreq() - Remove devfreq from the device.
+ * @devfreq:   the devfreq struct
+ * @skip:      skip calling device_unregister().
+ *
+ * Note that the caller should lock devfreq->lock before calling
+ * this. _remove_devfreq() will unlock it and free devfreq
+ * internally. devfreq_list_lock should be locked by the caller
+ * as well (not relased at return)
+ *
+ * Lock usage:
+ * devfreq->lock: locked before call.
+ *               unlocked at return (and freed)
+ * devfreq_list_lock: locked before call.
+ *                   kept locked at return.
+ *                   if devfreq is centrally polled.
+ *
+ * Freed memory:
+ * devfreq
+ */
+static void _remove_devfreq(struct devfreq *devfreq, bool skip)
+{
+       if (!mutex_is_locked(&devfreq->lock)) {
+               WARN(true, "devfreq->lock must be locked by the caller.\n");
+               return;
+       }
+       if (!devfreq->governor->no_central_polling &&
+           !mutex_is_locked(&devfreq_list_lock)) {
+               WARN(true, "devfreq_list_lock must be locked by the caller.\n");
+               return;
+       }
+
+       if (devfreq->being_removed)
+               return;
+
+       devfreq->being_removed = true;
+
+       if (devfreq->profile->exit)
+               devfreq->profile->exit(devfreq->dev.parent);
+
+       if (devfreq->governor->exit)
+               devfreq->governor->exit(devfreq);
+
+       if (!skip && get_device(&devfreq->dev)) {
+               device_unregister(&devfreq->dev);
+               put_device(&devfreq->dev);
+       }
+
+       if (!devfreq->governor->no_central_polling)
+               list_del(&devfreq->node);
+
+       mutex_unlock(&devfreq->lock);
+       mutex_destroy(&devfreq->lock);
+
+       kfree(devfreq);
+}
+
+/**
+ * devfreq_dev_release() - Callback for struct device to release the device.
+ * @dev:       the devfreq device
+ *
+ * This calls _remove_devfreq() if _remove_devfreq() is not called.
+ * Note that devfreq_dev_release() could be called by _remove_devfreq() as
+ * well as by others unregistering the device.
+ */
+static void devfreq_dev_release(struct device *dev)
+{
+       struct devfreq *devfreq = to_devfreq(dev);
+       bool central_polling = !devfreq->governor->no_central_polling;
+
+       /*
+        * If devfreq_dev_release() was called by device_unregister() of
+        * _remove_devfreq(), we cannot mutex_lock(&devfreq->lock) and
+        * being_removed is already set. This also partially checks the case
+        * where devfreq_dev_release() is called from a thread other than
+        * the one called _remove_devfreq(); however, this case is
+        * dealt completely with another following being_removed check.
+        *
+        * Because being_removed is never being
+        * unset, we do not need to worry about race conditions on
+        * being_removed.
+        */
+       if (devfreq->being_removed)
+               return;
+
+       if (central_polling)
+               mutex_lock(&devfreq_list_lock);
+
+       mutex_lock(&devfreq->lock);
+
+       /*
+        * Check being_removed flag again for the case where
+        * devfreq_dev_release() was called in a thread other than the one
+        * possibly called _remove_devfreq().
+        */
+       if (devfreq->being_removed) {
+               mutex_unlock(&devfreq->lock);
+               goto out;
+       }
+
+       /* devfreq->lock is unlocked and removed in _removed_devfreq() */
+       _remove_devfreq(devfreq, true);
+
+out:
+       if (central_polling)
+               mutex_unlock(&devfreq_list_lock);
+}
+
+/**
+ * devfreq_monitor() - Periodically poll devfreq objects.
+ * @work: the work struct used to run devfreq_monitor periodically.
+ *
+ */
+static void devfreq_monitor(struct work_struct *work)
+{
+       static unsigned long last_polled_at;
+       struct devfreq *devfreq, *tmp;
+       int error;
+       unsigned long jiffies_passed;
+       unsigned long next_jiffies = ULONG_MAX, now = jiffies;
+       struct device *dev;
+
+       /* Initially last_polled_at = 0, polling every device at bootup */
+       jiffies_passed = now - last_polled_at;
+       last_polled_at = now;
+       if (jiffies_passed == 0)
+               jiffies_passed = 1;
+
+       mutex_lock(&devfreq_list_lock);
+       list_for_each_entry_safe(devfreq, tmp, &devfreq_list, node) {
+               mutex_lock(&devfreq->lock);
+               dev = devfreq->dev.parent;
+
+               /* Do not remove tmp for a while */
+               wait_remove_device = tmp;
+
+               if (devfreq->governor->no_central_polling ||
+                   devfreq->next_polling == 0) {
+                       mutex_unlock(&devfreq->lock);
+                       continue;
+               }
+               mutex_unlock(&devfreq_list_lock);
+
+               /*
+                * Reduce more next_polling if devfreq_wq took an extra
+                * delay. (i.e., CPU has been idled.)
+                */
+               if (devfreq->next_polling <= jiffies_passed) {
+                       error = update_devfreq(devfreq);
+
+                       /* Remove a devfreq with an error. */
+                       if (error && error != -EAGAIN) {
+
+                               dev_err(dev, "Due to update_devfreq error(%d), devfreq(%s) is removed from the device\n",
+                                       error, devfreq->governor->name);
+
+                               /*
+                                * Unlock devfreq before locking the list
+                                * in order to avoid deadlock with
+                                * find_device_devfreq or others
+                                */
+                               mutex_unlock(&devfreq->lock);
+                               mutex_lock(&devfreq_list_lock);
+                               /* Check if devfreq is already removed */
+                               if (IS_ERR(find_device_devfreq(dev)))
+                                       continue;
+                               mutex_lock(&devfreq->lock);
+                               /* This unlocks devfreq->lock and free it */
+                               _remove_devfreq(devfreq, false);
+                               continue;
+                       }
+                       devfreq->next_polling = devfreq->polling_jiffies;
+               } else {
+                       devfreq->next_polling -= jiffies_passed;
+               }
+
+               if (devfreq->next_polling)
+                       next_jiffies = (next_jiffies > devfreq->next_polling) ?
+                                       devfreq->next_polling : next_jiffies;
+
+               mutex_unlock(&devfreq->lock);
+               mutex_lock(&devfreq_list_lock);
+       }
+       wait_remove_device = NULL;
+       mutex_unlock(&devfreq_list_lock);
+
+       if (next_jiffies > 0 && next_jiffies < ULONG_MAX) {
+               polling = true;
+               queue_delayed_work(devfreq_wq, &devfreq_work, next_jiffies);
+       } else {
+               polling = false;
+       }
+}
+
+/**
+ * devfreq_add_device() - Add devfreq feature to the device
+ * @dev:       the device to add devfreq feature.
+ * @profile:   device-specific profile to run devfreq.
+ * @governor:  the policy to choose frequency.
+ * @data:      private data for the governor. The devfreq framework does not
+ *             touch this value.
+ */
+struct devfreq *devfreq_add_device(struct device *dev,
+                                  struct devfreq_dev_profile *profile,
+                                  const struct devfreq_governor *governor,
+                                  void *data)
+{
+       struct devfreq *devfreq;
+       int err = 0;
+
+       if (!dev || !profile || !governor) {
+               dev_err(dev, "%s: Invalid parameters.\n", __func__);
+               return ERR_PTR(-EINVAL);
+       }
+
+
+       if (!governor->no_central_polling) {
+               mutex_lock(&devfreq_list_lock);
+               devfreq = find_device_devfreq(dev);
+               mutex_unlock(&devfreq_list_lock);
+               if (!IS_ERR(devfreq)) {
+                       dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__);
+                       err = -EINVAL;
+                       goto out;
+               }
+       }
+
+       devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);
+       if (!devfreq) {
+               dev_err(dev, "%s: Unable to create devfreq for the device\n",
+                       __func__);
+               err = -ENOMEM;
+               goto out;
+       }
+
+       mutex_init(&devfreq->lock);
+       mutex_lock(&devfreq->lock);
+       devfreq->dev.parent = dev;
+       devfreq->dev.class = devfreq_class;
+       devfreq->dev.release = devfreq_dev_release;
+       devfreq->profile = profile;
+       devfreq->governor = governor;
+       devfreq->previous_freq = profile->initial_freq;
+       devfreq->data = data;
+       devfreq->next_polling = devfreq->polling_jiffies
+                             = msecs_to_jiffies(devfreq->profile->polling_ms);
+       devfreq->nb.notifier_call = devfreq_notifier_call;
+
+       dev_set_name(&devfreq->dev, dev_name(dev));
+       err = device_register(&devfreq->dev);
+       if (err) {
+               put_device(&devfreq->dev);
+               goto err_dev;
+       }
+
+       if (governor->init)
+               err = governor->init(devfreq);
+       if (err)
+               goto err_init;
+
+       mutex_unlock(&devfreq->lock);
+
+       if (governor->no_central_polling)
+               goto out;
+
+       mutex_lock(&devfreq_list_lock);
+
+       list_add(&devfreq->node, &devfreq_list);
+
+       if (devfreq_wq && devfreq->next_polling && !polling) {
+               polling = true;
+               queue_delayed_work(devfreq_wq, &devfreq_work,
+                                  devfreq->next_polling);
+       }
+       mutex_unlock(&devfreq_list_lock);
+       goto out;
+err_init:
+       device_unregister(&devfreq->dev);
+err_dev:
+       mutex_unlock(&devfreq->lock);
+       kfree(devfreq);
+out:
+       if (err)
+               return ERR_PTR(err);
+       else
+               return devfreq;
+}
+
+/**
+ * devfreq_remove_device() - Remove devfreq feature from a device.
+ * @devfreq    the devfreq instance to be removed
+ */
+int devfreq_remove_device(struct devfreq *devfreq)
+{
+       if (!devfreq)
+               return -EINVAL;
+
+       if (!devfreq->governor->no_central_polling) {
+               mutex_lock(&devfreq_list_lock);
+               while (wait_remove_device == devfreq) {
+                       mutex_unlock(&devfreq_list_lock);
+                       schedule();
+                       mutex_lock(&devfreq_list_lock);
+               }
+       }
+
+       mutex_lock(&devfreq->lock);
+       _remove_devfreq(devfreq, false); /* it unlocks devfreq->lock */
+
+       if (!devfreq->governor->no_central_polling)
+               mutex_unlock(&devfreq_list_lock);
+
+       return 0;
+}
+
+static ssize_t show_governor(struct device *dev,
+                            struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name);
+}
+
+static ssize_t show_freq(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%lu\n", to_devfreq(dev)->previous_freq);
+}
+
+static ssize_t show_polling_interval(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", to_devfreq(dev)->profile->polling_ms);
+}
+
+static ssize_t store_polling_interval(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct devfreq *df = to_devfreq(dev);
+       unsigned int value;
+       int ret;
+
+       ret = sscanf(buf, "%u", &value);
+       if (ret != 1)
+               goto out;
+
+       mutex_lock(&df->lock);
+       df->profile->polling_ms = value;
+       df->next_polling = df->polling_jiffies
+                        = msecs_to_jiffies(value);
+       mutex_unlock(&df->lock);
+
+       ret = count;
+
+       if (df->governor->no_central_polling)
+               goto out;
+
+       mutex_lock(&devfreq_list_lock);
+       if (df->next_polling > 0 && !polling) {
+               polling = true;
+               queue_delayed_work(devfreq_wq, &devfreq_work,
+                                  df->next_polling);
+       }
+       mutex_unlock(&devfreq_list_lock);
+out:
+       return ret;
+}
+
+static ssize_t show_central_polling(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n",
+                      !to_devfreq(dev)->governor->no_central_polling);
+}
+
+static struct device_attribute devfreq_attrs[] = {
+       __ATTR(governor, S_IRUGO, show_governor, NULL),
+       __ATTR(cur_freq, S_IRUGO, show_freq, NULL),
+       __ATTR(central_polling, S_IRUGO, show_central_polling, NULL),
+       __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval,
+              store_polling_interval),
+       { },
+};
+
+/**
+ * devfreq_start_polling() - Initialize data structure for devfreq framework and
+ *                        start polling registered devfreq devices.
+ */
+static int __init devfreq_start_polling(void)
+{
+       mutex_lock(&devfreq_list_lock);
+       polling = false;
+       devfreq_wq = create_freezable_workqueue("devfreq_wq");
+       INIT_DELAYED_WORK_DEFERRABLE(&devfreq_work, devfreq_monitor);
+       mutex_unlock(&devfreq_list_lock);
+
+       devfreq_monitor(&devfreq_work.work);
+       return 0;
+}
+late_initcall(devfreq_start_polling);
+
+static int __init devfreq_init(void)
+{
+       devfreq_class = class_create(THIS_MODULE, "devfreq");
+       if (IS_ERR(devfreq_class)) {
+               pr_err("%s: couldn't create class\n", __FILE__);
+               return PTR_ERR(devfreq_class);
+       }
+       devfreq_class->dev_attrs = devfreq_attrs;
+       return 0;
+}
+subsys_initcall(devfreq_init);
+
+static void __exit devfreq_exit(void)
+{
+       class_destroy(devfreq_class);
+}
+module_exit(devfreq_exit);
+
+/*
+ * The followings are helper functions for devfreq user device drivers with
+ * OPP framework.
+ */
+
+/**
+ * devfreq_recommended_opp() - Helper function to get proper OPP for the
+ *                          freq value given to target callback.
+ * @dev                The devfreq user device. (parent of devfreq)
+ * @freq       The frequency given to target function
+ *
+ */
+struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq)
+{
+       struct opp *opp = opp_find_freq_ceil(dev, freq);
+
+       if (opp == ERR_PTR(-ENODEV))
+               opp = opp_find_freq_floor(dev, freq);
+       return opp;
+}
+
+/**
+ * devfreq_register_opp_notifier() - Helper function to get devfreq notified
+ *                                for any changes in the OPP availability
+ *                                changes
+ * @dev                The devfreq user device. (parent of devfreq)
+ * @devfreq    The devfreq object.
+ */
+int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
+{
+       struct srcu_notifier_head *nh = opp_get_notifier(dev);
+
+       if (IS_ERR(nh))
+               return PTR_ERR(nh);
+       return srcu_notifier_chain_register(nh, &devfreq->nb);
+}
+
+/**
+ * devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq
+ *                                  notified for any changes in the OPP
+ *                                  availability changes anymore.
+ * @dev                The devfreq user device. (parent of devfreq)
+ * @devfreq    The devfreq object.
+ *
+ * At exit() callback of devfreq_dev_profile, this must be included if
+ * devfreq_recommended_opp is used.
+ */
+int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
+{
+       struct srcu_notifier_head *nh = opp_get_notifier(dev);
+
+       if (IS_ERR(nh))
+               return PTR_ERR(nh);
+       return srcu_notifier_chain_unregister(nh, &devfreq->nb);
+}
+
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("devfreq class support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h
new file mode 100644 (file)
index 0000000..ea7f13c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * governor.h - internal header for devfreq governors.
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ *     MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This header is for devfreq governors in drivers/devfreq/
+ */
+
+#ifndef _GOVERNOR_H
+#define _GOVERNOR_H
+
+#include <linux/devfreq.h>
+
+#define to_devfreq(DEV)        container_of((DEV), struct devfreq, dev)
+
+/* Caution: devfreq->lock must be locked before calling update_devfreq */
+extern int update_devfreq(struct devfreq *devfreq);
+
+#endif /* _GOVERNOR_H */
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
new file mode 100644 (file)
index 0000000..c0596b2
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *  linux/drivers/devfreq/governor_performance.c
+ *
+ *  Copyright (C) 2011 Samsung Electronics
+ *     MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/devfreq.h>
+
+static int devfreq_performance_func(struct devfreq *df,
+                                   unsigned long *freq)
+{
+       /*
+        * target callback should be able to get floor value as
+        * said in devfreq.h
+        */
+       *freq = UINT_MAX;
+       return 0;
+}
+
+const struct devfreq_governor devfreq_performance = {
+       .name = "performance",
+       .get_target_freq = devfreq_performance_func,
+       .no_central_polling = true,
+};
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
new file mode 100644 (file)
index 0000000..2483a85
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *  linux/drivers/devfreq/governor_powersave.c
+ *
+ *  Copyright (C) 2011 Samsung Electronics
+ *     MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/devfreq.h>
+
+static int devfreq_powersave_func(struct devfreq *df,
+                                 unsigned long *freq)
+{
+       /*
+        * target callback should be able to get ceiling value as
+        * said in devfreq.h
+        */
+       *freq = 0;
+       return 0;
+}
+
+const struct devfreq_governor devfreq_powersave = {
+       .name = "powersave",
+       .get_target_freq = devfreq_powersave_func,
+       .no_central_polling = true,
+};
diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c
new file mode 100644 (file)
index 0000000..efad8dc
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *  linux/drivers/devfreq/governor_simpleondemand.c
+ *
+ *  Copyright (C) 2011 Samsung Electronics
+ *     MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/devfreq.h>
+#include <linux/math64.h>
+
+/* Default constants for DevFreq-Simple-Ondemand (DFSO) */
+#define DFSO_UPTHRESHOLD       (90)
+#define DFSO_DOWNDIFFERENCTIAL (5)
+static int devfreq_simple_ondemand_func(struct devfreq *df,
+                                       unsigned long *freq)
+{
+       struct devfreq_dev_status stat;
+       int err = df->profile->get_dev_status(df->dev.parent, &stat);
+       unsigned long long a, b;
+       unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;
+       unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
+       struct devfreq_simple_ondemand_data *data = df->data;
+
+       if (err)
+               return err;
+
+       if (data) {
+               if (data->upthreshold)
+                       dfso_upthreshold = data->upthreshold;
+               if (data->downdifferential)
+                       dfso_downdifferential = data->downdifferential;
+       }
+       if (dfso_upthreshold > 100 ||
+           dfso_upthreshold < dfso_downdifferential)
+               return -EINVAL;
+
+       /* Assume MAX if it is going to be divided by zero */
+       if (stat.total_time == 0) {
+               *freq = UINT_MAX;
+               return 0;
+       }
+
+       /* Prevent overflow */
+       if (stat.busy_time >= (1 << 24) || stat.total_time >= (1 << 24)) {
+               stat.busy_time >>= 7;
+               stat.total_time >>= 7;
+       }
+
+       /* Set MAX if it's busy enough */
+       if (stat.busy_time * 100 >
+           stat.total_time * dfso_upthreshold) {
+               *freq = UINT_MAX;
+               return 0;
+       }
+
+       /* Set MAX if we do not know the initial frequency */
+       if (stat.current_frequency == 0) {
+               *freq = UINT_MAX;
+               return 0;
+       }
+
+       /* Keep the current frequency */
+       if (stat.busy_time * 100 >
+           stat.total_time * (dfso_upthreshold - dfso_downdifferential)) {
+               *freq = stat.current_frequency;
+               return 0;
+       }
+
+       /* Set the desired frequency based on the load */
+       a = stat.busy_time;
+       a *= stat.current_frequency;
+       b = div_u64(a, stat.total_time);
+       b *= 100;
+       b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));
+       *freq = (unsigned long) b;
+
+       return 0;
+}
+
+const struct devfreq_governor devfreq_simple_ondemand = {
+       .name = "simple_ondemand",
+       .get_target_freq = devfreq_simple_ondemand_func,
+};
diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c
new file mode 100644 (file)
index 0000000..4f8b563
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ *  linux/drivers/devfreq/governor_simpleondemand.c
+ *
+ *  Copyright (C) 2011 Samsung Electronics
+ *     MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/devfreq.h>
+#include <linux/pm.h>
+#include <linux/mutex.h>
+#include "governor.h"
+
+struct userspace_data {
+       unsigned long user_frequency;
+       bool valid;
+};
+
+static int devfreq_userspace_func(struct devfreq *df, unsigned long *freq)
+{
+       struct userspace_data *data = df->data;
+
+       if (!data->valid)
+               *freq = df->previous_freq; /* No user freq specified yet */
+       else
+               *freq = data->user_frequency;
+       return 0;
+}
+
+static ssize_t store_freq(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct devfreq *devfreq = to_devfreq(dev);
+       struct userspace_data *data;
+       unsigned long wanted;
+       int err = 0;
+
+
+       mutex_lock(&devfreq->lock);
+       data = devfreq->data;
+
+       sscanf(buf, "%lu", &wanted);
+       data->user_frequency = wanted;
+       data->valid = true;
+       err = update_devfreq(devfreq);
+       if (err == 0)
+               err = count;
+       mutex_unlock(&devfreq->lock);
+       return err;
+}
+
+static ssize_t show_freq(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct devfreq *devfreq = to_devfreq(dev);
+       struct userspace_data *data;
+       int err = 0;
+
+       mutex_lock(&devfreq->lock);
+       data = devfreq->data;
+
+       if (data->valid)
+               err = sprintf(buf, "%lu\n", data->user_frequency);
+       else
+               err = sprintf(buf, "undefined\n");
+       mutex_unlock(&devfreq->lock);
+       return err;
+}
+
+static DEVICE_ATTR(set_freq, 0644, show_freq, store_freq);
+static struct attribute *dev_entries[] = {
+       &dev_attr_set_freq.attr,
+       NULL,
+};
+static struct attribute_group dev_attr_group = {
+       .name   = "userspace",
+       .attrs  = dev_entries,
+};
+
+static int userspace_init(struct devfreq *devfreq)
+{
+       int err = 0;
+       struct userspace_data *data = kzalloc(sizeof(struct userspace_data),
+                                             GFP_KERNEL);
+
+       if (!data) {
+               err = -ENOMEM;
+               goto out;
+       }
+       data->valid = false;
+       devfreq->data = data;
+
+       err = sysfs_create_group(&devfreq->dev.kobj, &dev_attr_group);
+out:
+       return err;
+}
+
+static void userspace_exit(struct devfreq *devfreq)
+{
+       sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group);
+       kfree(devfreq->data);
+       devfreq->data = NULL;
+}
+
+const struct devfreq_governor devfreq_userspace = {
+       .name = "userspace",
+       .get_target_freq = devfreq_userspace_func,
+       .init = userspace_init,
+       .exit = userspace_exit,
+       .no_central_polling = true,
+};
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 4112576..9323837 100644 (file)
 #include <linux/cpu.h>
 #include <linux/pci.h>
 #include <linux/smp.h>
+#include <linux/moduleparam.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
 
 #define DRVNAME        "coretemp"
 
+/*
+ * force_tjmax only matters when TjMax can't be read from the CPU itself.
+ * When set, it replaces the driver's suboptimal heuristic.
+ */
+static int force_tjmax;
+module_param_named(tjmax, force_tjmax, int, 0444);
+MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
+
 #define BASE_SYSFS_ATTR_NO     2       /* Sysfs Base attr no for coretemp */
 #define NUM_REAL_CORES         16      /* Number of Real cores per cpu */
 #define CORETEMP_NAME_LENGTH   17      /* String Length of attrs */
 #define MAX_CORE_ATTRS         4       /* Maximum no of basic attrs */
-#define MAX_THRESH_ATTRS       3       /* Maximum no of Threshold attrs */
-#define TOTAL_ATTRS            (MAX_CORE_ATTRS + MAX_THRESH_ATTRS)
+#define TOTAL_ATTRS            (MAX_CORE_ATTRS + 1)
 #define MAX_CORE_DATA          (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
 
 #ifdef CONFIG_SMP
@@ -69,8 +77,6 @@
  *             This value is passed as "id" field to rdmsr/wrmsr functions.
  * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS,
  *             from where the temperature values should be read.
- * @intrpt_reg: One of IA32_THERM_INTERRUPT or IA32_PACKAGE_THERM_INTERRUPT,
- *             from where the thresholds are read.
  * @attr_size:  Total number of pre-core attrs displayed in the sysfs.
  * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
  *             Otherwise, temp_data holds coretemp data.
 struct temp_data {
        int temp;
        int ttarget;
-       int tmin;
        int tjmax;
        unsigned long last_updated;
        unsigned int cpu;
        u32 cpu_core_id;
        u32 status_reg;
-       u32 intrpt_reg;
        int attr_size;
        bool is_pkg_data;
        bool valid;
@@ -143,19 +147,6 @@ static ssize_t show_crit_alarm(struct device *dev,
        return sprintf(buf, "%d\n", (eax >> 5) & 1);
 }
 
-static ssize_t show_max_alarm(struct device *dev,
-                               struct device_attribute *devattr, char *buf)
-{
-       u32 eax, edx;
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct platform_data *pdata = dev_get_drvdata(dev);
-       struct temp_data *tdata = pdata->core_data[attr->index];
-
-       rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
-
-       return sprintf(buf, "%d\n", !!(eax & THERM_STATUS_THRESHOLD1));
-}
-
 static ssize_t show_tjmax(struct device *dev,
                        struct device_attribute *devattr, char *buf)
 {
@@ -174,83 +165,6 @@ static ssize_t show_ttarget(struct device *dev,
        return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
 }
 
-static ssize_t store_ttarget(struct device *dev,
-                               struct device_attribute *devattr,
-                               const char *buf, size_t count)
-{
-       struct platform_data *pdata = dev_get_drvdata(dev);
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct temp_data *tdata = pdata->core_data[attr->index];
-       u32 eax, edx;
-       unsigned long val;
-       int diff;
-
-       if (strict_strtoul(buf, 10, &val))
-               return -EINVAL;
-
-       /*
-        * THERM_MASK_THRESHOLD1 is 7 bits wide. Values are entered in terms
-        * of milli degree celsius. Hence don't accept val > (127 * 1000)
-        */
-       if (val > tdata->tjmax || val > 127000)
-               return -EINVAL;
-
-       diff = (tdata->tjmax - val) / 1000;
-
-       mutex_lock(&tdata->update_lock);
-       rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
-       eax = (eax & ~THERM_MASK_THRESHOLD1) |
-                               (diff << THERM_SHIFT_THRESHOLD1);
-       wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
-       tdata->ttarget = val;
-       mutex_unlock(&tdata->update_lock);
-
-       return count;
-}
-
-static ssize_t show_tmin(struct device *dev,
-                       struct device_attribute *devattr, char *buf)
-{
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct platform_data *pdata = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tmin);
-}
-
-static ssize_t store_tmin(struct device *dev,
-                               struct device_attribute *devattr,
-                               const char *buf, size_t count)
-{
-       struct platform_data *pdata = dev_get_drvdata(dev);
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct temp_data *tdata = pdata->core_data[attr->index];
-       u32 eax, edx;
-       unsigned long val;
-       int diff;
-
-       if (strict_strtoul(buf, 10, &val))
-               return -EINVAL;
-
-       /*
-        * THERM_MASK_THRESHOLD0 is 7 bits wide. Values are entered in terms
-        * of milli degree celsius. Hence don't accept val > (127 * 1000)
-        */
-       if (val > tdata->tjmax || val > 127000)
-               return -EINVAL;
-
-       diff = (tdata->tjmax - val) / 1000;
-
-       mutex_lock(&tdata->update_lock);
-       rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx);
-       eax = (eax & ~THERM_MASK_THRESHOLD0) |
-                               (diff << THERM_SHIFT_THRESHOLD0);
-       wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx);
-       tdata->tmin = val;
-       mutex_unlock(&tdata->update_lock);
-
-       return count;
-}
-
 static ssize_t show_temp(struct device *dev,
                        struct device_attribute *devattr, char *buf)
 {
@@ -374,7 +288,6 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
 
 static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
 {
-       /* The 100C is default for both mobile and non mobile CPUs */
        int err;
        u32 eax, edx;
        u32 val;
@@ -385,7 +298,8 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
         */
        err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
        if (err) {
-               dev_warn(dev, "Unable to read TjMax from CPU.\n");
+               if (c->x86_model > 0xe && c->x86_model != 0x1c)
+                       dev_warn(dev, "Unable to read TjMax from CPU %u\n", id);
        } else {
                val = (eax >> 16) & 0xff;
                /*
@@ -393,11 +307,17 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
                 * will be used
                 */
                if (val) {
-                       dev_info(dev, "TjMax is %d C.\n", val);
+                       dev_dbg(dev, "TjMax is %d degrees C\n", val);
                        return val * 1000;
                }
        }
 
+       if (force_tjmax) {
+               dev_notice(dev, "TjMax forced to %d degrees C by user\n",
+                          force_tjmax);
+               return force_tjmax * 1000;
+       }
+
        /*
         * An assumption is made for early CPUs and unreadable MSR.
         * NOTE: the calculated value may not be correct.
@@ -414,21 +334,6 @@ static void __devinit get_ucode_rev_on_cpu(void *edx)
        rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
 }
 
-static int get_pkg_tjmax(unsigned int cpu, struct device *dev)
-{
-       int err;
-       u32 eax, edx, val;
-
-       err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
-       if (!err) {
-               val = (eax >> 16) & 0xff;
-               if (val)
-                       return val * 1000;
-       }
-       dev_warn(dev, "Unable to read Pkg-TjMax from CPU:%u\n", cpu);
-       return 100000; /* Default TjMax: 100 degree celsius */
-}
-
 static int create_name_attr(struct platform_data *pdata, struct device *dev)
 {
        sysfs_attr_init(&pdata->name_attr.attr);
@@ -442,19 +347,14 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
                                int attr_no)
 {
        int err, i;
-       static ssize_t (*rd_ptr[TOTAL_ATTRS]) (struct device *dev,
+       static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
                        struct device_attribute *devattr, char *buf) = {
                        show_label, show_crit_alarm, show_temp, show_tjmax,
-                       show_max_alarm, show_ttarget, show_tmin };
-       static ssize_t (*rw_ptr[TOTAL_ATTRS]) (struct device *dev,
-                       struct device_attribute *devattr, const char *buf,
-                       size_t count) = { NULL, NULL, NULL, NULL, NULL,
-                                       store_ttarget, store_tmin };
-       static const char *names[TOTAL_ATTRS] = {
+                       show_ttarget };
+       static const char *const names[TOTAL_ATTRS] = {
                                        "temp%d_label", "temp%d_crit_alarm",
                                        "temp%d_input", "temp%d_crit",
-                                       "temp%d_max_alarm", "temp%d_max",
-                                       "temp%d_max_hyst" };
+                                       "temp%d_max" };
 
        for (i = 0; i < tdata->attr_size; i++) {
                snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i],
@@ -462,10 +362,6 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
                sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
                tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
                tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
-               if (rw_ptr[i]) {
-                       tdata->sd_attrs[i].dev_attr.attr.mode |= S_IWUSR;
-                       tdata->sd_attrs[i].dev_attr.store = rw_ptr[i];
-               }
                tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
                tdata->sd_attrs[i].index = attr_no;
                err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
@@ -481,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;
 
@@ -494,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;
                }
        }
@@ -538,8 +432,6 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
 
        tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS :
                                                        MSR_IA32_THERM_STATUS;
-       tdata->intrpt_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_INTERRUPT :
-                                               MSR_IA32_THERM_INTERRUPT;
        tdata->is_pkg_data = pkg_flag;
        tdata->cpu = cpu;
        tdata->cpu_core_id = TO_CORE_ID(cpu);
@@ -548,11 +440,11 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
        return tdata;
 }
 
-static int create_core_data(struct platform_data *pdata,
-                               struct platform_device *pdev,
+static int create_core_data(struct platform_device *pdev,
                                unsigned int cpu, int pkg_flag)
 {
        struct temp_data *tdata;
+       struct platform_data *pdata = platform_get_drvdata(pdev);
        struct cpuinfo_x86 *c = &cpu_data(cpu);
        u32 eax, edx;
        int err, attr_no;
@@ -588,25 +480,21 @@ static int create_core_data(struct platform_data *pdata,
                goto exit_free;
 
        /* We can access status register. Get Critical Temperature */
-       if (pkg_flag)
-               tdata->tjmax = get_pkg_tjmax(pdev->id, &pdev->dev);
-       else
-               tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
+       tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
 
        /*
-        * Test if we can access the intrpt register. If so, increase the
-        * 'size' enough to have ttarget/tmin/max_alarm interfaces.
-        * Initialize ttarget with bits 16:22 of MSR_IA32_THERM_INTERRUPT
+        * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET.
+        * The target temperature is available on older CPUs but not in this
+        * register. Atoms don't have the register at all.
         */
-       err = rdmsr_safe_on_cpu(cpu, tdata->intrpt_reg, &eax, &edx);
-       if (!err) {
-               tdata->attr_size += MAX_THRESH_ATTRS;
-               tdata->tmin = tdata->tjmax -
-                             ((eax & THERM_MASK_THRESHOLD0) >>
-                              THERM_SHIFT_THRESHOLD0) * 1000;
-               tdata->ttarget = tdata->tjmax -
-                                ((eax & THERM_MASK_THRESHOLD1) >>
-                                 THERM_SHIFT_THRESHOLD1) * 1000;
+       if (c->x86_model > 0xe && c->x86_model != 0x1c) {
+               err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET,
+                                       &eax, &edx);
+               if (!err) {
+                       tdata->ttarget
+                         = tdata->tjmax - ((eax >> 8) & 0xff) * 1000;
+                       tdata->attr_size++;
+               }
        }
 
        pdata->core_data[attr_no] = tdata;
@@ -618,22 +506,20 @@ static int create_core_data(struct platform_data *pdata,
 
        return 0;
 exit_free:
+       pdata->core_data[attr_no] = NULL;
        kfree(tdata);
        return err;
 }
 
 static void coretemp_add_core(unsigned int cpu, int pkg_flag)
 {
-       struct platform_data *pdata;
        struct platform_device *pdev = coretemp_get_pdev(cpu);
        int err;
 
        if (!pdev)
                return;
 
-       pdata = platform_get_drvdata(pdev);
-
-       err = create_core_data(pdata, pdev, cpu, pkg_flag);
+       err = create_core_data(pdev, cpu, pkg_flag);
        if (err)
                dev_err(&pdev->dev, "Adding Core %u failed\n", cpu);
 }
@@ -657,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)
@@ -671,7 +552,7 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
        if (err)
                goto exit_free;
 
-       pdata->phys_proc_id = TO_PHYS_ID(pdev->id);
+       pdata->phys_proc_id = pdev->id;
        platform_set_drvdata(pdev, pdata);
 
        pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
@@ -723,7 +604,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
 
        mutex_lock(&pdev_list_mutex);
 
-       pdev = platform_device_alloc(DRVNAME, cpu);
+       pdev = platform_device_alloc(DRVNAME, TO_PHYS_ID(cpu));
        if (!pdev) {
                err = -ENOMEM;
                pr_err("Device allocation failed\n");
@@ -743,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);
@@ -804,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 257957c..4f7c3fc 100644 (file)
@@ -72,7 +72,7 @@ struct ds620_data {
        char valid;             /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
 
-       u16 temp[3];            /* Register values, word */
+       s16 temp[3];            /* Register values, word */
 };
 
 /*
index 17cf1ab..8c2844e 100644 (file)
@@ -329,8 +329,8 @@ static int w83791d_detect(struct i2c_client *client,
                          struct i2c_board_info *info);
 static int w83791d_remove(struct i2c_client *client);
 
-static int w83791d_read(struct i2c_client *client, u8 register);
-static int w83791d_write(struct i2c_client *client, u8 register, u8 value);
+static int w83791d_read(struct i2c_client *client, u8 reg);
+static int w83791d_write(struct i2c_client *client, u8 reg, u8 value);
 static struct w83791d_data *w83791d_update_device(struct device *dev);
 
 #ifdef DEBUG
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)
+