Merge branch 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 Dec 2009 17:12:57 +0000 (09:12 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 Dec 2009 17:12:57 +0000 (09:12 -0800)
* 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  sched: Revert 738d2be, simplify set_task_cpu()

191 files changed:
Documentation/power/runtime_pm.txt
Documentation/powerpc/dts-bindings/fsl/mpic.txt [new file with mode: 0644]
Documentation/trace/events-kmem.txt
MAINTAINERS
arch/powerpc/boot/dts/katmai.dts
arch/powerpc/boot/dts/mpc8315erdb.dts
arch/powerpc/boot/dts/mpc8349emitx.dts
arch/powerpc/boot/dts/warp.dts
arch/powerpc/boot/ugecon.c
arch/powerpc/configs/g5_defconfig
arch/powerpc/configs/iseries_defconfig
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/configs/ppc64e_defconfig
arch/powerpc/configs/pseries_defconfig
arch/powerpc/include/asm/bug.h
arch/powerpc/include/asm/gpio.h
arch/powerpc/kernel/align.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/mmu_context_nohash.c
arch/powerpc/mm/pgtable_32.c
arch/powerpc/platforms/83xx/suspend.c
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/platforms/embedded6xx/flipper-pic.c
arch/powerpc/platforms/embedded6xx/hlwd-pic.c
arch/powerpc/platforms/embedded6xx/usbgecko_udbg.c
arch/powerpc/platforms/iseries/mf.c
arch/powerpc/platforms/iseries/viopath.c
arch/powerpc/platforms/pseries/Kconfig
arch/powerpc/platforms/pseries/cmm.c
arch/powerpc/platforms/pseries/dlpar.c
arch/powerpc/platforms/pseries/smp.c
arch/powerpc/sysdev/cpm2_pic.c
arch/powerpc/sysdev/fsl_pci.c
arch/powerpc/sysdev/mpc8xxx_gpio.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/mpic_msi.c
arch/powerpc/sysdev/mpic_u3msi.c
drivers/ata/pata_bf54x.c
drivers/base/memory.c
drivers/base/power/main.c
drivers/base/power/runtime.c
drivers/char/nozomi.c
drivers/char/sonypi.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_ioc32.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/i2c/ch7006_drv.c
drivers/gpu/drm/i2c/ch7006_mode.c
drivers/gpu/drm/i810/i810_dma.c
drivers/gpu/drm/i810/i810_drv.c
drivers/gpu/drm/i830/i830_dma.c
drivers/gpu/drm/i830/i830_drv.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_ioc32.c
drivers/gpu/drm/mga/mga_drv.c
drivers/gpu/drm/mga/mga_ioc32.c
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_dp.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_grctx.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_grctx.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_ioc32.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv04_crtc.c
drivers/gpu/drm/nouveau/nv04_dac.c
drivers/gpu/drm/nouveau/nv04_dfp.c
drivers/gpu/drm/nouveau/nv04_display.c
drivers/gpu/drm/nouveau/nv04_graph.c
drivers/gpu/drm/nouveau/nv10_graph.c
drivers/gpu/drm/nouveau/nv17_tv.c
drivers/gpu/drm/nouveau/nv40_graph.c
drivers/gpu/drm/nouveau/nv40_grctx.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_cursor.c
drivers/gpu/drm/nouveau/nv50_dac.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_fifo.c
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_sor.c
drivers/gpu/drm/r128/r128_drv.c
drivers/gpu/drm/r128/r128_ioc32.c
drivers/gpu/drm/radeon/atom.c
drivers/gpu/drm/radeon/atom.h
drivers/gpu/drm/radeon/atombios.h
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r100_track.h
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r300_cmdbuf.c
drivers/gpu/drm/radeon/r300_reg.h
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_clocks.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_ioc32.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_test.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/savage/savage_drv.c
drivers/gpu/drm/sis/sis_drv.c
drivers/gpu/drm/tdfx/tdfx_drv.c
drivers/gpu/drm/via/via_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/infiniband/hw/cxgb3/cxio_hal.h
drivers/infiniband/hw/cxgb3/cxio_resource.c
drivers/media/video/cx23885/cx23888-ir.c
drivers/media/video/meye.c
drivers/media/video/meye.h
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/main.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/scsi/libiscsi.c
drivers/scsi/libiscsi_tcp.c
drivers/scsi/libsrp.c
drivers/staging/pohmelfs/dir.c
drivers/usb/host/fhci-sched.c
drivers/usb/host/fhci-tds.c
drivers/usb/host/fhci.h
drivers/usb/serial/generic.c
drivers/usb/serial/usb-serial.c
fs/anon_inodes.c
fs/compat_ioctl.c
fs/eventfd.c
fs/eventpoll.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext3/resize.c
fs/ext3/super.c
fs/ext4/ext4.h
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/super.c
fs/file_table.c
fs/internal.h
fs/jbd/journal.c
fs/jbd2/journal.c
fs/jfs/super.c
fs/namei.c
fs/open.c
fs/quota/dquot.c
fs/quota/quota_v2.c
fs/signalfd.c
fs/stat.c
fs/timerfd.c
include/drm/drmP.h
include/linux/ext3_fs_sb.h
include/linux/ext3_jbd.h
include/linux/fs.h
include/linux/kfifo.h
include/linux/memory.h
include/linux/namei.h
include/linux/quota.h
include/linux/usb/serial.h
include/scsi/libiscsi.h
include/scsi/libiscsi_tcp.h
include/scsi/libsrp.h
kernel/auditsc.c
kernel/kfifo.c
kernel/perf_event.c
kernel/resource.c
kernel/time.c
kernel/time/timekeeping.c
lib/string.c
mm/page_alloc.c
net/dccp/probe.c
security/tomoyo/file.c
virt/kvm/kvm_main.c

index 4a3109b..356fd86 100644 (file)
@@ -42,80 +42,81 @@ struct dev_pm_ops {
        ...
 };
 
-The ->runtime_suspend() callback is executed by the PM core for the bus type of
-the device being suspended.  The bus type's callback is then _entirely_
-_responsible_ for handling the device as appropriate, which may, but need not
-include executing the device driver's own ->runtime_suspend() callback (from the
+The ->runtime_suspend(), ->runtime_resume() and ->runtime_idle() callbacks are
+executed by the PM core for either the bus type, or device type (if the bus
+type's callback is not defined), or device class (if the bus type's and device
+type's callbacks are not defined) of given device.  The bus type, device type
+and device class callbacks are referred to as subsystem-level callbacks in what
+follows.
+
+The subsystem-level suspend callback is _entirely_ _responsible_ for handling
+the suspend of the device as appropriate, which may, but need not include
+executing the device driver's own ->runtime_suspend() callback (from the
 PM core's point of view it is not necessary to implement a ->runtime_suspend()
-callback in a device driver as long as the bus type's ->runtime_suspend() knows
-what to do to handle the device).
+callback in a device driver as long as the subsystem-level suspend callback
+knows what to do to handle the device).
 
-  * Once the bus type's ->runtime_suspend() callback has completed successfully
+  * Once the subsystem-level suspend callback has completed successfully
     for given device, the PM core regards the device as suspended, which need
     not mean that the device has been put into a low power state.  It is
     supposed to mean, however, that the device will not process data and will
-    not communicate with the CPU(s) and RAM until its bus type's
-    ->runtime_resume() callback is executed for it.  The run-time PM status of
-    a device after successful execution of its bus type's ->runtime_suspend()
-    callback is 'suspended'.
-
-  * If the bus type's ->runtime_suspend() callback returns -EBUSY or -EAGAIN,
-    the device's run-time PM status is supposed to be 'active', which means that
-    the device _must_ be fully operational afterwards.
-
-  * If the bus type's ->runtime_suspend() callback returns an error code
-    different from -EBUSY or -EAGAIN, the PM core regards this as a fatal
-    error and will refuse to run the helper functions described in Section 4
-    for the device, until the status of it is directly set either to 'active'
-    or to 'suspended' (the PM core provides special helper functions for this
-    purpose).
-
-In particular, if the driver requires remote wakeup capability for proper
-functioning and device_run_wake() returns 'false' for the device, then
-->runtime_suspend() should return -EBUSY.  On the other hand, if
-device_run_wake() returns 'true' for the device and the device is put
-into a low power state during the execution of its bus type's
-->runtime_suspend(), it is expected that remote wake-up (i.e. hardware mechanism
-allowing the device to request a change of its power state, such as PCI PME)
-will be enabled for the device.  Generally, remote wake-up should be enabled
-for all input devices put into a low power state at run time.
-
-The ->runtime_resume() callback is executed by the PM core for the bus type of
-the device being woken up.  The bus type's callback is then _entirely_
-_responsible_ for handling the device as appropriate, which may, but need not
-include executing the device driver's own ->runtime_resume() callback (from the
-PM core's point of view it is not necessary to implement a ->runtime_resume()
-callback in a device driver as long as the bus type's ->runtime_resume() knows
-what to do to handle the device).
-
-  * Once the bus type's ->runtime_resume() callback has completed successfully,
-    the PM core regards the device as fully operational, which means that the
-    device _must_ be able to complete I/O operations as needed.  The run-time
-    PM status of the device is then 'active'.
-
-  * If the bus type's ->runtime_resume() callback returns an error code, the PM
-    core regards this as a fatal error and will refuse to run the helper
-    functions described in Section 4 for the device, until its status is
-    directly set either to 'active' or to 'suspended' (the PM core provides
-    special helper functions for this purpose).
-
-The ->runtime_idle() callback is executed by the PM core for the bus type of
-given device whenever the device appears to be idle, which is indicated to the
-PM core by two counters, the device's usage counter and the counter of 'active'
-children of the device.
+    not communicate with the CPU(s) and RAM until the subsystem-level resume
+    callback is executed for it.  The run-time PM status of a device after
+    successful execution of the subsystem-level suspend callback is 'suspended'.
+
+  * If the subsystem-level suspend callback returns -EBUSY or -EAGAIN,
+    the device's run-time PM status is 'active', which means that the device
+    _must_ be fully operational afterwards.
+
+  * If the subsystem-level suspend callback returns an error code different
+    from -EBUSY or -EAGAIN, the PM core regards this as a fatal error and will
+    refuse to run the helper functions described in Section 4 for the device,
+    until the status of it is directly set either to 'active', or to 'suspended'
+    (the PM core provides special helper functions for this purpose).
+
+In particular, if the driver requires remote wake-up capability (i.e. hardware
+mechanism allowing the device to request a change of its power state, such as
+PCI PME) for proper functioning and device_run_wake() returns 'false' for the
+device, then ->runtime_suspend() should return -EBUSY.  On the other hand, if
+device_run_wake() returns 'true' for the device and the device is put into a low
+power state during the execution of the subsystem-level suspend callback, it is
+expected that remote wake-up will be enabled for the device.  Generally, remote
+wake-up should be enabled for all input devices put into a low power state at
+run time.
+
+The subsystem-level resume callback is _entirely_ _responsible_ for handling the
+resume of the device as appropriate, which may, but need not include executing
+the device driver's own ->runtime_resume() callback (from the PM core's point of
+view it is not necessary to implement a ->runtime_resume() callback in a device
+driver as long as the subsystem-level resume callback knows what to do to handle
+the device).
+
+  * Once the subsystem-level resume callback has completed successfully, the PM
+    core regards the device as fully operational, which means that the device
+    _must_ be able to complete I/O operations as needed.  The run-time PM status
+    of the device is then 'active'.
+
+  * If the subsystem-level resume callback returns an error code, the PM core
+    regards this as a fatal error and will refuse to run the helper functions
+    described in Section 4 for the device, until its status is directly set
+    either to 'active' or to 'suspended' (the PM core provides special helper
+    functions for this purpose).
+
+The subsystem-level idle callback is executed by the PM core whenever the device
+appears to be idle, which is indicated to the PM core by two counters, the
+device's usage counter and the counter of 'active' children of the device.
 
   * If any of these counters is decreased using a helper function provided by
     the PM core and it turns out to be equal to zero, the other counter is
     checked.  If that counter also is equal to zero, the PM core executes the
-    device bus type's ->runtime_idle() callback (with the device as an
-    argument).
+    subsystem-level idle callback with the device as an argument.
 
-The action performed by a bus type's ->runtime_idle() callback is totally
-dependent on the bus type in question, but the expected and recommended action
-is to check if the device can be suspended (i.e. if all of the conditions
-necessary for suspending the device are satisfied) and to queue up a suspend
-request for the device in that case.  The value returned by this callback is
-ignored by the PM core.
+The action performed by a subsystem-level idle callback is totally dependent on
+the subsystem in question, but the expected and recommended action is to check
+if the device can be suspended (i.e. if all of the conditions necessary for
+suspending the device are satisfied) and to queue up a suspend request for the
+device in that case.  The value returned by this callback is ignored by the PM
+core.
 
 The helper functions provided by the PM core, described in Section 4, guarantee
 that the following constraints are met with respect to the bus type's run-time
@@ -238,41 +239,41 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
       removing the device from device hierarchy
 
   int pm_runtime_idle(struct device *dev);
-    - execute ->runtime_idle() for the device's bus type; returns 0 on success
-      or error code on failure, where -EINPROGRESS means that ->runtime_idle()
-      is already being executed
+    - execute the subsystem-level idle callback for the device; returns 0 on
+      success or error code on failure, where -EINPROGRESS means that
+      ->runtime_idle() is already being executed
 
   int pm_runtime_suspend(struct device *dev);
-    - execute ->runtime_suspend() for the device's bus type; returns 0 on
+    - execute the subsystem-level suspend callback for the device; returns 0 on
       success, 1 if the device's run-time PM status was already 'suspended', or
       error code on failure, where -EAGAIN or -EBUSY means it is safe to attempt
       to suspend the device again in future
 
   int pm_runtime_resume(struct device *dev);
-    - execute ->runtime_resume() for the device's bus type; returns 0 on
+    - execute the subsystem-leve resume callback for the device; returns 0 on
       success, 1 if the device's run-time PM status was already 'active' or
       error code on failure, where -EAGAIN means it may be safe to attempt to
       resume the device again in future, but 'power.runtime_error' should be
       checked additionally
 
   int pm_request_idle(struct device *dev);
-    - submit a request to execute ->runtime_idle() for the device's bus type
-      (the request is represented by a work item in pm_wq); returns 0 on success
-      or error code if the request has not been queued up
+    - submit a request to execute the subsystem-level idle callback for the
+      device (the request is represented by a work item in pm_wq); returns 0 on
+      success or error code if the request has not been queued up
 
   int pm_schedule_suspend(struct device *dev, unsigned int delay);
-    - schedule the execution of ->runtime_suspend() for the device's bus type
-      in future, where 'delay' is the time to wait before queuing up a suspend
-      work item in pm_wq, in milliseconds (if 'delay' is zero, the work item is
-      queued up immediately); returns 0 on success, 1 if the device's PM
+    - schedule the execution of the subsystem-level suspend callback for the
+      device in future, where 'delay' is the time to wait before queuing up a
+      suspend work item in pm_wq, in milliseconds (if 'delay' is zero, the work
+      item is queued up immediately); returns 0 on success, 1 if the device's PM
       run-time status was already 'suspended', or error code if the request
       hasn't been scheduled (or queued up if 'delay' is 0); if the execution of
       ->runtime_suspend() is already scheduled and not yet expired, the new
       value of 'delay' will be used as the time to wait
 
   int pm_request_resume(struct device *dev);
-    - submit a request to execute ->runtime_resume() for the device's bus type
-      (the request is represented by a work item in pm_wq); returns 0 on
+    - submit a request to execute the subsystem-level resume callback for the
+      device (the request is represented by a work item in pm_wq); returns 0 on
       success, 1 if the device's run-time PM status was already 'active', or
       error code if the request hasn't been queued up
 
@@ -303,12 +304,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
       run-time PM callbacks described in Section 2
 
   int pm_runtime_disable(struct device *dev);
-    - prevent the run-time PM helper functions from running the device bus
-      type's run-time PM callbacks, make sure that all of the pending run-time
-      PM operations on the device are either completed or canceled; returns
-      1 if there was a resume request pending and it was necessary to execute
-      ->runtime_resume() for the device's bus type to satisfy that request,
-      otherwise 0 is returned
+    - prevent the run-time PM helper functions from running subsystem-level
+      run-time PM callbacks for the device, make sure that all of the pending
+      run-time PM operations on the device are either completed or canceled;
+      returns 1 if there was a resume request pending and it was necessary to
+      execute the subsystem-level resume callback for the device to satisfy that
+      request, otherwise 0 is returned
 
   void pm_suspend_ignore_children(struct device *dev, bool enable);
     - set/unset the power.ignore_children flag of the device
@@ -378,5 +379,55 @@ pm_runtime_suspend() or pm_runtime_idle() or their asynchronous counterparts,
 they will fail returning -EAGAIN, because the device's usage counter is
 incremented by the core before executing ->probe() and ->remove().  Still, it
 may be desirable to suspend the device as soon as ->probe() or ->remove() has
-finished, so the PM core uses pm_runtime_idle_sync() to invoke the device bus
-type's ->runtime_idle() callback at that time.
+finished, so the PM core uses pm_runtime_idle_sync() to invoke the
+subsystem-level idle callback for the device at that time.
+
+6. Run-time PM and System Sleep
+
+Run-time PM and system sleep (i.e., system suspend and hibernation, also known
+as suspend-to-RAM and suspend-to-disk) interact with each other in a couple of
+ways.  If a device is active when a system sleep starts, everything is
+straightforward.  But what should happen if the device is already suspended?
+
+The device may have different wake-up settings for run-time PM and system sleep.
+For example, remote wake-up may be enabled for run-time suspend but disallowed
+for system sleep (device_may_wakeup(dev) returns 'false').  When this happens,
+the subsystem-level system suspend callback is responsible for changing the
+device's wake-up setting (it may leave that to the device driver's system
+suspend routine).  It may be necessary to resume the device and suspend it again
+in order to do so.  The same is true if the driver uses different power levels
+or other settings for run-time suspend and system sleep.
+
+During system resume, devices generally should be brought back to full power,
+even if they were suspended before the system sleep began.  There are several
+reasons for this, including:
+
+  * The device might need to switch power levels, wake-up settings, etc.
+
+  * Remote wake-up events might have been lost by the firmware.
+
+  * The device's children may need the device to be at full power in order
+    to resume themselves.
+
+  * The driver's idea of the device state may not agree with the device's
+    physical state.  This can happen during resume from hibernation.
+
+  * The device might need to be reset.
+
+  * Even though the device was suspended, if its usage counter was > 0 then most
+    likely it would need a run-time resume in the near future anyway.
+
+  * Always going back to full power is simplest.
+
+If the device was suspended before the sleep began, then its run-time PM status
+will have to be updated to reflect the actual post-system sleep status.  The way
+to do this is:
+
+       pm_runtime_disable(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+The PM core always increments the run-time usage counter before calling the
+->prepare() callback and decrements it after calling the ->complete() callback.
+Hence disabling run-time PM temporarily like this will not cause any run-time
+suspend callbacks to be lost.
diff --git a/Documentation/powerpc/dts-bindings/fsl/mpic.txt b/Documentation/powerpc/dts-bindings/fsl/mpic.txt
new file mode 100644 (file)
index 0000000..71e39cf
--- /dev/null
@@ -0,0 +1,42 @@
+* OpenPIC and its interrupt numbers on Freescale's e500/e600 cores
+
+The OpenPIC specification does not specify which interrupt source has to
+become which interrupt number. This is up to the software implementation
+of the interrupt controller. The only requirement is that every
+interrupt source has to have an unique interrupt number / vector number.
+To accomplish this the current implementation assigns the number zero to
+the first source, the number one to the second source and so on until
+all interrupt sources have their unique number.
+Usually the assigned vector number equals the interrupt number mentioned
+in the documentation for a given core / CPU. This is however not true
+for the e500 cores (MPC85XX CPUs) where the documentation distinguishes
+between internal and external interrupt sources and starts counting at
+zero for both of them.
+
+So what to write for external interrupt source X or internal interrupt
+source Y into the device tree? Here is an example:
+
+The memory map for the interrupt controller in the MPC8544[0] shows,
+that the first interrupt source starts at 0x5_0000 (PIC Register Address
+Map-Interrupt Source Configuration Registers). This source becomes the
+number zero therefore:
+ External interrupt 0 = interrupt number 0
+ External interrupt 1 = interrupt number 1
+ External interrupt 2 = interrupt number 2
+ ...
+Every interrupt number allocates 0x20 bytes register space. So to get
+its number it is sufficient to shift the lower 16bits to right by five.
+So for the external interrupt 10 we have:
+  0x0140 >> 5 = 10
+
+After the external sources, the internal sources follow. The in core I2C
+controller on the MPC8544 for instance has the internal source number
+27. Oo obtain its interrupt number we take the lower 16bits of its memory
+address (0x5_0560) and shift it right:
+ 0x0560 >> 5 = 43
+
+Therefore the I2C device node for the MPC8544 CPU has to have the
+interrupt number 43 specified in the device tree.
+
+[0] MPC8544E PowerQUICCTM III, Integrated Host Processor Family Reference Manual
+    MPC8544ERM Rev. 1 10/2007
index 6ef2a86..aa82ee4 100644 (file)
@@ -1,7 +1,7 @@
                        Subsystem Trace Points: kmem
 
-The tracing system kmem captures events related to object and page allocation
-within the kernel. Broadly speaking there are four major subheadings.
+The kmem tracing system captures events related to object and page allocation
+within the kernel. Broadly speaking there are five major subheadings.
 
   o Slab allocation of small objects of unknown type (kmalloc)
   o Slab allocation of small objects of known type
@@ -9,7 +9,7 @@ within the kernel. Broadly speaking there are four major subheadings.
   o Per-CPU Allocator Activity
   o External Fragmentation
 
-This document will describe what each of the tracepoints are and why they
+This document describes what each of the tracepoints is and why they
 might be useful.
 
 1. Slab allocation of small objects of unknown type
@@ -34,7 +34,7 @@ kmem_cache_free               call_site=%lx ptr=%p
 These events are similar in usage to the kmalloc-related events except that
 it is likely easier to pin the event down to a specific cache. At the time
 of writing, no information is available on what slab is being allocated from,
-but the call_site can usually be used to extrapolate that information
+but the call_site can usually be used to extrapolate that information.
 
 3. Page allocation
 ==================
@@ -80,9 +80,9 @@ event indicating whether it is for a percpu_refill or not.
 When the per-CPU list is too full, a number of pages are freed, each one
 which triggers a mm_page_pcpu_drain event.
 
-The individual nature of the events are so that pages can be tracked
+The individual nature of the events is so that pages can be tracked
 between allocation and freeing. A number of drain or refill pages that occur
-consecutively imply the zone->lock being taken once. Large amounts of PCP
+consecutively imply the zone->lock being taken once. Large amounts of per-CPU
 refills and drains could imply an imbalance between CPUs where too much work
 is being concentrated in one place. It could also indicate that the per-CPU
 lists should be a larger size. Finally, large amounts of refills on one CPU
@@ -102,6 +102,6 @@ is important.
 
 Large numbers of this event implies that memory is fragmenting and
 high-order allocations will start failing at some time in the future. One
-means of reducing the occurange of this event is to increase the size of
+means of reducing the occurrence of this event is to increase the size of
 min_free_kbytes in increments of 3*pageblock_size*nr_online_nodes where
 pageblock_size is usually the size of the default hugepage size.
index efd2ef2..d5244f1 100644 (file)
@@ -1402,6 +1402,8 @@ L:        linux-usb@vger.kernel.org
 S:     Supported
 F:     Documentation/usb/WUSB-Design-overview.txt
 F:     Documentation/usb/wusb-cbaf
+F:     drivers/usb/host/hwa-hc.c
+F:     drivers/usb/host/whci/
 F:     drivers/usb/wusbcore/
 F:     include/linux/usb/wusb*
 
@@ -5430,7 +5432,10 @@ ULTRA-WIDEBAND (UWB) SUBSYSTEM:
 M:     David Vrabel <david.vrabel@csr.com>
 L:     linux-usb@vger.kernel.org
 S:     Supported
-F:     drivers/uwb/*
+F:     drivers/uwb/
+X:     drivers/uwb/wlp/
+X:     drivers/uwb/i1480/i1480u-wlp/
+X:     drivers/uwb/i1480/i1480-wlp.h
 F:     include/linux/uwb.h
 F:     include/linux/uwb/
 
@@ -5943,9 +5948,12 @@ W:       http://linuxwimax.org
 
 WIMEDIA LLC PROTOCOL (WLP) SUBSYSTEM
 M:     David Vrabel <david.vrabel@csr.com>
+L:     netdev@vger.kernel.org
 S:     Maintained
 F:     include/linux/wlp.h
 F:     drivers/uwb/wlp/
+F:     drivers/uwb/i1480/i1480u-wlp/
+F:     drivers/uwb/i1480/i1480-wlp.h
 
 WISTRON LAPTOP BUTTON DRIVER
 M:     Miloslav Trmac <mitr@volny.cz>
index 51eb6ed..8f345de 100644 (file)
                dcr-reg = <0x00c 0x002>;
        };
 
+       MQ0: mq {
+               compatible = "ibm,mq-440spe";
+               dcr-reg = <0x040 0x020>;
+       };
+
        plb {
                compatible = "ibm,plb-440spe", "ibm,plb-440gp", "ibm,plb4";
                #address-cells = <2>;
                #size-cells = <1>;
                /*        addr-child     addr-parent    size */
-               ranges = <0x4 0xe0000000 0x4 0xe0000000 0x20000000
+               ranges = <0x4 0x00100000 0x4 0x00100000 0x00001000
+                         0x4 0x00200000 0x4 0x00200000 0x00000400
+                         0x4 0xe0000000 0x4 0xe0000000 0x20000000
                          0xc 0x00000000 0xc 0x00000000 0x20000000
                          0xd 0x00000000 0xd 0x00000000 0x80000000
                          0xd 0x80000000 0xd 0x80000000 0x80000000
                                0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /* swizzled int C */
                                0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
                };
+
+               I2O: i2o@400100000 {
+                       compatible = "ibm,i2o-440spe";
+                       reg = <0x00000004 0x00100000 0x100>;
+                       dcr-reg = <0x060 0x020>;
+               };
+
+               DMA0: dma0@400100100 {
+                       compatible = "ibm,dma-440spe";
+                       cell-index = <0>;
+                       reg = <0x00000004 0x00100100 0x100>;
+                       dcr-reg = <0x060 0x020>;
+                       interrupt-parent = <&DMA0>;
+                       interrupts = <0 1>;
+                       #interrupt-cells = <1>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
+                       interrupt-map = <
+                               0 &UIC0 0x14 4
+                               1 &UIC1 0x16 4>;
+               };
+
+               DMA1: dma1@400100200 {
+                       compatible = "ibm,dma-440spe";
+                       cell-index = <1>;
+                       reg = <0x00000004 0x00100200 0x100>;
+                       dcr-reg = <0x060 0x020>;
+                       interrupt-parent = <&DMA1>;
+                       interrupts = <0 1>;
+                       #interrupt-cells = <1>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
+                       interrupt-map = <
+                               0 &UIC0 0x16 4
+                               1 &UIC1 0x16 4>;
+               };
+
+               xor-accel@400200000 {
+                       compatible = "amcc,xor-accelerator";
+                       reg = <0x00000004 0x00200000 0x400>;
+                       interrupt-parent = <&UIC1>;
+                       interrupts = <0x1f 4>;
+               };
        };
 
        chosen {
index 32e10f5..8a3a4f3 100644 (file)
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi0>;
                        phy-handle = < &phy0 >;
+                       fsl,magic-packet;
 
                        mdio@520 {
                                #address-cells = <1>;
                        interrupt-parent = <&ipic>;
                        tbi-handle = <&tbi1>;
                        phy-handle = < &phy1 >;
+                       fsl,magic-packet;
 
                        mdio@520 {
                                #address-cells = <1>;
                        interrupt-parent = <&ipic>;
                };
 
+               gtm1: timer@500 {
+                       compatible = "fsl,mpc8315-gtm", "fsl,gtm";
+                       reg = <0x500 0x100>;
+                       interrupts = <90 8 78 8 84 8 72 8>;
+                       interrupt-parent = <&ipic>;
+                       clock-frequency = <133333333>;
+               };
+
+               timer@600 {
+                       compatible = "fsl,mpc8315-gtm", "fsl,gtm";
+                       reg = <0x600 0x100>;
+                       interrupts = <91 8 79 8 85 8 73 8>;
+                       interrupt-parent = <&ipic>;
+                       clock-frequency = <133333333>;
+               };
+
                /* IPIC
                 * interrupts cell = <intr #, sense>
                 * sense values match linux IORESOURCE_IRQ_* defines:
                                      0x59 0x8>;
                        interrupt-parent = < &ipic >;
                };
+
+               pmc: power@b00 {
+                       compatible = "fsl,mpc8315-pmc", "fsl,mpc8313-pmc",
+                                    "fsl,mpc8349-pmc";
+                       reg = <0xb00 0x100 0xa00 0x100>;
+                       interrupts = <80 8>;
+                       interrupt-parent = <&ipic>;
+                       fsl,mpc8313-wakeup-timer = <&gtm1>;
+               };
        };
 
        pci0: pci@e0008500 {
index feeeb7f..b53d1df 100644 (file)
                        reg = <0x200 0x100>;
                };
 
+               gpio1: gpio-controller@c00 {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8349-gpio";
+                       reg = <0xc00 0x100>;
+                       interrupts = <74 0x8>;
+                       interrupt-parent = <&ipic>;
+                       gpio-controller;
+               };
+
+               gpio2: gpio-controller@d00 {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8349-gpio";
+                       reg = <0xd00 0x100>;
+                       interrupts = <75 0x8>;
+                       interrupt-parent = <&ipic>;
+                       gpio-controller;
+               };
+
                i2c@3000 {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        interrupts = <14 0x8>;
                        interrupt-parent = <&ipic>;
                        dfsrr;
+
+                       eeprom: at24@50 {
+                               compatible = "st-micro,24c256";
+                               reg = <0x50>;
+                       };
+
                };
 
                i2c@3100 {
                                interrupt-parent = <&ipic>;
                        };
 
+                       pcf1: iexp@38 {
+                               #gpio-cells = <2>;
+                               compatible = "ti,pcf8574a";
+                               reg = <0x38>;
+                               gpio-controller;
+                       };
+
+                       pcf2: iexp@39 {
+                               #gpio-cells = <2>;
+                               compatible = "ti,pcf8574a";
+                               reg = <0x39>;
+                               gpio-controller;
+                       };
+
+                       spd: at24@51 {
+                               compatible = "at24,spd";
+                               reg = <0x51>;
+                       };
+
                        mcu_pio: mcu@a {
                                #gpio-cells = <2>;
                                compatible = "fsl,mc9s08qg8-mpc8349emitx",
                        reg = <0x700 0x100>;
                        device_type = "ipic";
                };
+
+               gpio-leds {
+                       compatible = "gpio-leds";
+
+                       green {
+                               label = "Green";
+                               gpios = <&pcf1 0 1>;
+                               linux,default-trigger = "heartbeat";
+                       };
+
+                       yellow {
+                               label = "Yellow";
+                               gpios = <&pcf1 1 1>;
+                               /* linux,default-trigger = "heartbeat"; */
+                               default-state = "on";
+                       };
+               };
+
        };
 
        pci0: pci@e0008500 {
                compatible = "fsl,mpc8349e-localbus",
                             "fsl,pq2pro-localbus";
                reg = <0xe0005000 0xd8>;
-               ranges = <0x3 0x0 0xf0000000 0x210>;
+               ranges = <0x0 0x0 0xfe000000 0x1000000  /* flash */
+                         0x1 0x0 0xf8000000 0x20000    /* VSC 7385 */
+                         0x2 0x0 0xf9000000 0x200000   /* exp slot */
+                         0x3 0x0 0xf0000000 0x210>;    /* CF slot */
+
+               flash@0,0 {
+                       compatible = "cfi-flash";
+                       reg = <0x0      0x0 0x800000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+               };
+
+               flash@0,800000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "cfi-flash";
+                       reg = <0x0 0x800000 0x800000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+               };
 
                pata@3,0 {
                        compatible = "fsl,mpc8349emitx-pata", "ata-generic";
index 31605ee..e576ee8 100644 (file)
 
                                fpga@2,4000 {
                                        compatible = "pika,fpga-sd";
-                                       reg = <0x00000002 0x00004000 0x00000A00>;
+                                       reg = <0x00000002 0x00004000 0x00004000>;
                                };
 
                                nor@0,0 {
index 50609ea..8f2a6b3 100644 (file)
@@ -86,7 +86,7 @@ static void ug_putc(char ch)
 
        while (!ug_is_txfifo_ready() && count--)
                barrier();
-       if (count)
+       if (count >= 0)
                ug_raw_putc(ch);
 }
 
index fc90592..826a65d 100644 (file)
@@ -757,7 +757,7 @@ CONFIG_SUNGEM=y
 # CONFIG_B44 is not set
 # CONFIG_ATL2 is not set
 CONFIG_NETDEV_1000=y
-CONFIG_ACENIC=y
+CONFIG_ACENIC=m
 CONFIG_ACENIC_OMIT_TIGON_I=y
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
@@ -794,8 +794,8 @@ CONFIG_NETDEV_10000=y
 # CONFIG_BNX2X is not set
 # CONFIG_QLGE is not set
 # CONFIG_SFC is not set
-CONFIG_TR=y
-CONFIG_IBMOL=y
+# CONFIG_TR is not set
+# CONFIG_IBMOL is not set
 # CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 
index f925c55..76982c5 100644 (file)
@@ -714,8 +714,8 @@ CONFIG_NETDEV_10000=y
 # CONFIG_BNX2X is not set
 # CONFIG_QLGE is not set
 # CONFIG_SFC is not set
-CONFIG_TR=y
-CONFIG_IBMOL=y
+# CONFIG_TR is not set
+# CONFIG_IBMOL is not set
 # CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 
index 2524018..7b3804a 100644 (file)
@@ -304,11 +304,11 @@ CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
 # CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
+CONFIG_HZ=100
 CONFIG_SCHED_HRTICK=y
 CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
@@ -980,7 +980,7 @@ CONFIG_E100=y
 # CONFIG_SC92031 is not set
 # CONFIG_ATL2 is not set
 CONFIG_NETDEV_1000=y
-CONFIG_ACENIC=y
+CONFIG_ACENIC=m
 CONFIG_ACENIC_OMIT_TIGON_I=y
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
@@ -1023,8 +1023,8 @@ CONFIG_PASEMI_MAC=y
 # CONFIG_BNX2X is not set
 # CONFIG_QLGE is not set
 # CONFIG_SFC is not set
-CONFIG_TR=y
-CONFIG_IBMOL=y
+# CONFIG_TR is not set
+# CONFIG_IBMOL is not set
 # CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 
@@ -1863,7 +1863,7 @@ CONFIG_HFSPLUS_FS=m
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_CRAMFS=y
+CONFIG_CRAMFS=m
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_OMFS_FS is not set
index 18af460..8195f16 100644 (file)
@@ -1008,8 +1008,8 @@ CONFIG_IXGB=m
 # CONFIG_QLGE is not set
 # CONFIG_SFC is not set
 # CONFIG_BE2NET is not set
-CONFIG_TR=y
-CONFIG_IBMOL=y
+# CONFIG_TR is not set
+# CONFIG_IBMOL is not set
 # CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 CONFIG_WLAN=y
index c568329..ca9ff9a 100644 (file)
@@ -230,11 +230,11 @@ CONFIG_TICK_ONESHOT=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
 # CONFIG_HZ_300 is not set
 # CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
+CONFIG_HZ=100
 CONFIG_SCHED_HRTICK=y
 CONFIG_PREEMPT_NONE=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
@@ -796,7 +796,7 @@ CONFIG_E100=y
 # CONFIG_NET_POCKET is not set
 # CONFIG_ATL2 is not set
 CONFIG_NETDEV_1000=y
-CONFIG_ACENIC=y
+CONFIG_ACENIC=m
 CONFIG_ACENIC_OMIT_TIGON_I=y
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
@@ -834,8 +834,8 @@ CONFIG_S2IO=m
 # CONFIG_BNX2X is not set
 # CONFIG_QLGE is not set
 # CONFIG_SFC is not set
-CONFIG_TR=y
-CONFIG_IBMOL=y
+# CONFIG_TR is not set
+# CONFIG_IBMOL is not set
 # CONFIG_3C359 is not set
 # CONFIG_TMS380TR is not set
 
@@ -1494,7 +1494,7 @@ CONFIG_CONFIGFS_FS=m
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_CRAMFS=y
+CONFIG_CRAMFS=m
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_OMFS_FS is not set
index 64e1fdc..2c15212 100644 (file)
@@ -68,7 +68,7 @@
                _EMIT_BUG_ENTRY                                 \
                : : "i" (__FILE__), "i" (__LINE__),             \
                    "i" (0), "i"  (sizeof(struct bug_entry)));  \
-       for(;;) ;                                               \
+       unreachable();                                          \
 } while (0)
 
 #define BUG_ON(x) do {                                         \
index ea04632..38762ed 100644 (file)
@@ -38,12 +38,9 @@ static inline int gpio_cansleep(unsigned int gpio)
        return __gpio_cansleep(gpio);
 }
 
-/*
- * Not implemented, yet.
- */
 static inline int gpio_to_irq(unsigned int gpio)
 {
-       return -ENOSYS;
+       return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned int irq)
index 3839839..b876e98 100644 (file)
@@ -642,10 +642,14 @@ static int emulate_spe(struct pt_regs *regs, unsigned int reg,
  */
 static int emulate_vsx(unsigned char __user *addr, unsigned int reg,
                       unsigned int areg, struct pt_regs *regs,
-                      unsigned int flags, unsigned int length)
+                      unsigned int flags, unsigned int length,
+                      unsigned int elsize)
 {
        char *ptr;
+       unsigned long *lptr;
        int ret = 0;
+       int sw = 0;
+       int i, j;
 
        flush_vsx_to_thread(current);
 
@@ -654,19 +658,35 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg,
        else
                ptr = (char *) &current->thread.vr[reg - 32];
 
-       if (flags & ST)
-               ret = __copy_to_user(addr, ptr, length);
-        else {
-               if (flags & SPLT){
-                       ret = __copy_from_user(ptr, addr, length);
-                       ptr += length;
+       lptr = (unsigned long *) ptr;
+
+       if (flags & SW)
+               sw = elsize-1;
+
+       for (j = 0; j < length; j += elsize) {
+               for (i = 0; i < elsize; ++i) {
+                       if (flags & ST)
+                               ret |= __put_user(ptr[i^sw], addr + i);
+                       else
+                               ret |= __get_user(ptr[i^sw], addr + i);
                }
-               ret |= __copy_from_user(ptr, addr, length);
+               ptr  += elsize;
+               addr += elsize;
        }
-       if (flags & U)
-               regs->gpr[areg] = regs->dar;
-       if (ret)
+
+       if (!ret) {
+               if (flags & U)
+                       regs->gpr[areg] = regs->dar;
+
+               /* Splat load copies the same data to top and bottom 8 bytes */
+               if (flags & SPLT)
+                       lptr[1] = lptr[0];
+               /* For 8 byte loads, zero the top 8 bytes */
+               else if (!(flags & ST) && (8 == length))
+                       lptr[1] = 0;
+       } else
                return -EFAULT;
+
        return 1;
 }
 #endif
@@ -767,16 +787,25 @@ int fix_alignment(struct pt_regs *regs)
 
 #ifdef CONFIG_VSX
        if ((instruction & 0xfc00003e) == 0x7c000018) {
-               /* Additional register addressing bit (64 VSX vs 32 FPR/GPR */
+               unsigned int elsize;
+
+               /* Additional register addressing bit (64 VSX vs 32 FPR/GPR) */
                reg |= (instruction & 0x1) << 5;
                /* Simple inline decoder instead of a table */
+               /* VSX has only 8 and 16 byte memory accesses */
+               nb = 8;
                if (instruction & 0x200)
                        nb = 16;
-               else if (instruction & 0x080)
-                       nb = 8;
-               else
-                       nb = 4;
+
+               /* Vector stores in little-endian mode swap individual
+                  elements, so process them separately */
+               elsize = 4;
+               if (instruction & 0x80)
+                       elsize = 8;
+
                flags = 0;
+               if (regs->msr & MSR_LE)
+                       flags |= SW;
                if (instruction & 0x100)
                        flags |= ST;
                if (instruction & 0x040)
@@ -787,7 +816,7 @@ int fix_alignment(struct pt_regs *regs)
                        nb = 8;
                }
                PPC_WARN_ALIGNMENT(vsx, regs);
-               return emulate_vsx(addr, reg, areg, regs, flags, nb);
+               return emulate_vsx(addr, reg, areg, regs, flags, nb, elsize);
        }
 #endif
        /* A size of 0 indicates an instruction we don't support, with
index 50f867d..3ecdcec 100644 (file)
@@ -340,7 +340,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
                        else
                                def->tlbiel = 0;
 
-                       DBG(" %d: shift=%02x, sllp=%04x, avpnm=%08x, "
+                       DBG(" %d: shift=%02x, sllp=%04lx, avpnm=%08lx, "
                            "tlbiel=%d, penc=%d\n",
                            idx, shift, def->sllp, def->avpnm, def->tlbiel,
                            def->penc);
@@ -663,7 +663,7 @@ static void __init htab_initialize(void)
                base = (unsigned long)__va(lmb.memory.region[i].base);
                size = lmb.memory.region[i].size;
 
-               DBG("creating mapping for region: %lx..%lx (prot: %x)\n",
+               DBG("creating mapping for region: %lx..%lx (prot: %lx)\n",
                    base, size, prot);
 
 #ifdef CONFIG_U3_DART
@@ -879,7 +879,7 @@ static inline int subpage_protection(struct mm_struct *mm, unsigned long ea)
  */
 int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
 {
-       void *pgdir;
+       pgd_t *pgdir;
        unsigned long vsid;
        struct mm_struct *mm;
        pte_t *ptep;
@@ -1025,7 +1025,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
        else
 #endif /* CONFIG_PPC_HAS_HASH_64K */
        {
-               int spp = subpage_protection(pgdir, ea);
+               int spp = subpage_protection(mm, ea);
                if (access & spp)
                        rc = -2;
                else
@@ -1115,7 +1115,7 @@ void flush_hash_page(unsigned long va, real_pte_t pte, int psize, int ssize,
 {
        unsigned long hash, index, shift, hidx, slot;
 
-       DBG_LOW("flush_hash_page(va=%016x)\n", va);
+       DBG_LOW("flush_hash_page(va=%016lx)\n", va);
        pte_iterate_hashed_subpages(pte, psize, va, index, shift) {
                hash = hpt_hash(va, shift, ssize);
                hidx = __rpte_to_hidx(pte, index);
@@ -1123,7 +1123,7 @@ void flush_hash_page(unsigned long va, real_pte_t pte, int psize, int ssize,
                        hash = ~hash;
                slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
                slot += hidx & _PTEIDX_GROUP_IX;
-               DBG_LOW(" sub %d: hash=%x, hidx=%x\n", index, slot, hidx);
+               DBG_LOW(" sub %ld: hash=%lx, hidx=%lx\n", index, slot, hidx);
                ppc_md.hpte_invalidate(slot, va, psize, ssize, local);
        } pte_iterate_hashed_end();
 }
index be4f34c..1044a63 100644 (file)
@@ -353,7 +353,7 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
                read_lock(&tasklist_lock);
                for_each_process(p) {
                        if (p->mm)
-                               cpu_mask_clear_cpu(cpu, mm_cpumask(p->mm));
+                               cpumask_clear_cpu(cpu, mm_cpumask(p->mm));
                }
                read_unlock(&tasklist_lock);
        break;
index 177e403..573b3bd 100644 (file)
@@ -382,7 +382,7 @@ static int __change_page_attr(struct page *page, pgprot_t prot)
                return 0;
        if (!get_pteptr(&init_mm, address, &kpte, &kpmd))
                return -EINVAL;
-       set_pte_at(&init_mm, address, kpte, mk_pte(page, prot));
+       __set_pte_at(&init_mm, address, kpte, mk_pte(page, prot), 0);
        wmb();
 #ifdef CONFIG_PPC_STD_MMU
        flush_hash_pages(0, address, pmd_val(*kpmd), 1);
index d306f07..4380534 100644 (file)
@@ -32,6 +32,7 @@
 #define PMCCR1_NEXT_STATE       0x0C /* Next state for power management */
 #define PMCCR1_NEXT_STATE_SHIFT 2
 #define PMCCR1_CURR_STATE       0x03 /* Current state for power management*/
+#define IMMR_SYSCR_OFFSET       0x100
 #define IMMR_RCW_OFFSET         0x900
 #define RCW_PCI_HOST            0x80000000
 
@@ -78,6 +79,22 @@ struct mpc83xx_clock {
        u32 sccr;
 };
 
+struct mpc83xx_syscr {
+       __be32 sgprl;
+       __be32 sgprh;
+       __be32 spridr;
+       __be32 :32;
+       __be32 spcr;
+       __be32 sicrl;
+       __be32 sicrh;
+};
+
+struct mpc83xx_saved {
+       u32 sicrl;
+       u32 sicrh;
+       u32 sccr;
+};
+
 struct pmc_type {
        int has_deep_sleep;
 };
@@ -87,6 +104,8 @@ static int has_deep_sleep, deep_sleeping;
 static int pmc_irq;
 static struct mpc83xx_pmc __iomem *pmc_regs;
 static struct mpc83xx_clock __iomem *clock_regs;
+static struct mpc83xx_syscr __iomem *syscr_regs;
+static struct mpc83xx_saved saved_regs;
 static int is_pci_agent, wake_from_pci;
 static phys_addr_t immrbase;
 static int pci_pm_state;
@@ -137,6 +156,20 @@ static irqreturn_t pmc_irq_handler(int irq, void *dev_id)
        return ret;
 }
 
+static void mpc83xx_suspend_restore_regs(void)
+{
+       out_be32(&syscr_regs->sicrl, saved_regs.sicrl);
+       out_be32(&syscr_regs->sicrh, saved_regs.sicrh);
+       out_be32(&clock_regs->sccr, saved_regs.sccr);
+}
+
+static void mpc83xx_suspend_save_regs(void)
+{
+       saved_regs.sicrl = in_be32(&syscr_regs->sicrl);
+       saved_regs.sicrh = in_be32(&syscr_regs->sicrh);
+       saved_regs.sccr = in_be32(&clock_regs->sccr);
+}
+
 static int mpc83xx_suspend_enter(suspend_state_t state)
 {
        int ret = -EAGAIN;
@@ -166,6 +199,8 @@ static int mpc83xx_suspend_enter(suspend_state_t state)
         */
 
        if (deep_sleeping) {
+               mpc83xx_suspend_save_regs();
+
                out_be32(&pmc_regs->mask, PMCER_ALL);
 
                out_be32(&pmc_regs->config1,
@@ -179,6 +214,8 @@ static int mpc83xx_suspend_enter(suspend_state_t state)
                         in_be32(&pmc_regs->config1) & ~PMCCR1_POWER_OFF);
 
                out_be32(&pmc_regs->mask, PMCER_PMCI);
+
+               mpc83xx_suspend_restore_regs();
        } else {
                out_be32(&pmc_regs->mask, PMCER_PMCI);
 
@@ -194,7 +231,7 @@ out:
        return ret;
 }
 
-static void mpc83xx_suspend_finish(void)
+static void mpc83xx_suspend_end(void)
 {
        deep_sleeping = 0;
 }
@@ -278,7 +315,7 @@ static struct platform_suspend_ops mpc83xx_suspend_ops = {
        .valid = mpc83xx_suspend_valid,
        .begin = mpc83xx_suspend_begin,
        .enter = mpc83xx_suspend_enter,
-       .finish = mpc83xx_suspend_finish,
+       .end = mpc83xx_suspend_end,
 };
 
 static int pmc_probe(struct of_device *ofdev,
@@ -333,12 +370,23 @@ static int pmc_probe(struct of_device *ofdev,
                goto out_pmc;
        }
 
+       if (has_deep_sleep) {
+               syscr_regs = ioremap(immrbase + IMMR_SYSCR_OFFSET,
+                                    sizeof(*syscr_regs));
+               if (!syscr_regs) {
+                       ret = -ENOMEM;
+                       goto out_syscr;
+               }
+       }
+
        if (is_pci_agent)
                mpc83xx_set_agent();
 
        suspend_set_ops(&mpc83xx_suspend_ops);
        return 0;
 
+out_syscr:
+       iounmap(clock_regs);
 out_pmc:
        iounmap(pmc_regs);
 out:
index c5028a2..21f61b8 100644 (file)
@@ -86,7 +86,7 @@ static int mpc8568_fixup_125_clock(struct phy_device *phydev)
        scr = phy_read(phydev, MV88E1111_SCR);
 
        if (scr < 0)
-               return err;
+               return scr;
 
        err = phy_write(phydev, MV88E1111_SCR, scr | 0x0008);
 
index d596328..c278bd3 100644 (file)
@@ -102,7 +102,7 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq,
                           irq_hw_number_t hwirq)
 {
        set_irq_chip_data(virq, h->host_data);
-       get_irq_desc(virq)->status |= IRQ_LEVEL;
+       irq_to_desc(virq)->status |= IRQ_LEVEL;
        set_irq_chip_and_handler(virq, &flipper_pic, handle_level_irq);
        return 0;
 }
index dd20bff..a771f91 100644 (file)
@@ -95,7 +95,7 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq,
                           irq_hw_number_t hwirq)
 {
        set_irq_chip_data(virq, h->host_data);
-       get_irq_desc(virq)->status |= IRQ_LEVEL;
+       irq_to_desc(virq)->status |= IRQ_LEVEL;
        set_irq_chip_and_handler(virq, &hlwd_pic, handle_level_irq);
        return 0;
 }
@@ -132,9 +132,9 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq,
        struct irq_host *irq_host = get_irq_data(cascade_virq);
        unsigned int virq;
 
-       spin_lock(&desc->lock);
+       raw_spin_lock(&desc->lock);
        desc->chip->mask(cascade_virq); /* IRQ_LEVEL */
-       spin_unlock(&desc->lock);
+       raw_spin_unlock(&desc->lock);
 
        virq = __hlwd_pic_get_irq(irq_host);
        if (virq != NO_IRQ)
@@ -142,11 +142,11 @@ static void hlwd_pic_irq_cascade(unsigned int cascade_virq,
        else
                pr_err("spurious interrupt!\n");
 
-       spin_lock(&desc->lock);
+       raw_spin_lock(&desc->lock);
        desc->chip->ack(cascade_virq); /* IRQ_LEVEL */
        if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
                desc->chip->unmask(cascade_virq);
-       spin_unlock(&desc->lock);
+       raw_spin_unlock(&desc->lock);
 }
 
 /*
index edc956c..20a8ed9 100644 (file)
@@ -120,7 +120,7 @@ static void ug_putc(char ch)
 
        while (!ug_is_txfifo_ready() && count--)
                barrier();
-       if (count)
+       if (count >= 0)
                ug_raw_putc(ch);
 }
 
index 0d9343d..6617915 100644 (file)
@@ -855,59 +855,58 @@ static int mf_get_boot_rtc(struct rtc_time *tm)
 }
 
 #ifdef CONFIG_PROC_FS
-
-static int proc_mf_dump_cmdline(char *page, char **start, off_t off,
-               int count, int *eof, void *data)
+static int mf_cmdline_proc_show(struct seq_file *m, void *v)
 {
-       int len;
-       char *p;
+       char *page, *p;
        struct vsp_cmd_data vsp_cmd;
        int rc;
        dma_addr_t dma_addr;
 
        /* The HV appears to return no more than 256 bytes of command line */
-       if (off >= 256)
-               return 0;
-       if ((off + count) > 256)
-               count = 256 - off;
+       page = kmalloc(256, GFP_KERNEL);
+       if (!page)
+               return -ENOMEM;
 
-       dma_addr = iseries_hv_map(page, off + count, DMA_FROM_DEVICE);
-       if (dma_addr == DMA_ERROR_CODE)
+       dma_addr = iseries_hv_map(page, 256, DMA_FROM_DEVICE);
+       if (dma_addr == DMA_ERROR_CODE) {
+               kfree(page);
                return -ENOMEM;
-       memset(page, 0, off + count);
+       }
+       memset(page, 0, 256);
        memset(&vsp_cmd, 0, sizeof(vsp_cmd));
        vsp_cmd.cmd = 33;
        vsp_cmd.sub_data.kern.token = dma_addr;
        vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
-       vsp_cmd.sub_data.kern.side = (u64)data;
-       vsp_cmd.sub_data.kern.length = off + count;
+       vsp_cmd.sub_data.kern.side = (u64)m->private;
+       vsp_cmd.sub_data.kern.length = 256;
        mb();
        rc = signal_vsp_instruction(&vsp_cmd);
-       iseries_hv_unmap(dma_addr, off + count, DMA_FROM_DEVICE);
-       if (rc)
+       iseries_hv_unmap(dma_addr, 256, DMA_FROM_DEVICE);
+       if (rc) {
+               kfree(page);
                return rc;
-       if (vsp_cmd.result_code != 0)
+       }
+       if (vsp_cmd.result_code != 0) {
+               kfree(page);
                return -ENOMEM;
+       }
        p = page;
-       len = 0;
-       while (len < (off + count)) {
-               if ((*p == '\0') || (*p == '\n')) {
-                       if (*p == '\0')
-                               *p = '\n';
-                       p++;
-                       len++;
-                       *eof = 1;
+       while (p - page < 256) {
+               if (*p == '\0' || *p == '\n') {
+                       *p = '\n';
                        break;
                }
                p++;
-               len++;
-       }
 
-       if (len < off) {
-               *eof = 1;
-               len = 0;
        }
-       return len;
+       seq_write(m, page, p - page);
+       kfree(page);
+       return 0;
+}
+
+static int mf_cmdline_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mf_cmdline_proc_show, PDE(inode)->data);
 }
 
 #if 0
@@ -962,10 +961,8 @@ static int proc_mf_dump_vmlinux(char *page, char **start, off_t off,
 }
 #endif
 
-static int proc_mf_dump_side(char *page, char **start, off_t off,
-               int count, int *eof, void *data)
+static int mf_side_proc_show(struct seq_file *m, void *v)
 {
-       int len;
        char mf_current_side = ' ';
        struct vsp_cmd_data vsp_cmd;
 
@@ -989,21 +986,17 @@ static int proc_mf_dump_side(char *page, char **start, off_t off,
                }
        }
 
-       len = sprintf(page, "%c\n", mf_current_side);
+       seq_printf(m, "%c\n", mf_current_side);
+       return 0;
+}
 
-       if (len <= (off + count))
-               *eof = 1;
-       *start = page + off;
-       len -= off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
-       return len;
+static int mf_side_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mf_side_proc_show, NULL);
 }
 
-static int proc_mf_change_side(struct file *file, const char __user *buffer,
-               unsigned long count, void *data)
+static ssize_t mf_side_proc_write(struct file *file, const char __user *buffer,
+                                 size_t count, loff_t *pos)
 {
        char side;
        u64 newSide;
@@ -1041,6 +1034,15 @@ static int proc_mf_change_side(struct file *file, const char __user *buffer,
        return count;
 }
 
+static const struct file_operations mf_side_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = mf_side_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = mf_side_proc_write,
+};
+
 #if 0
 static void mf_getSrcHistory(char *buffer, int size)
 {
@@ -1087,8 +1089,7 @@ static void mf_getSrcHistory(char *buffer, int size)
 }
 #endif
 
-static int proc_mf_dump_src(char *page, char **start, off_t off,
-               int count, int *eof, void *data)
+static int mf_src_proc_show(struct seq_file *m, void *v)
 {
 #if 0
        int len;
@@ -1109,8 +1110,13 @@ static int proc_mf_dump_src(char *page, char **start, off_t off,
 #endif
 }
 
-static int proc_mf_change_src(struct file *file, const char __user *buffer,
-               unsigned long count, void *data)
+static int mf_src_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mf_src_proc_show, NULL);
+}
+
+static ssize_t mf_src_proc_write(struct file *file, const char __user *buffer,
+                                size_t count, loff_t *pos)
 {
        char stkbuf[10];
 
@@ -1135,9 +1141,19 @@ static int proc_mf_change_src(struct file *file, const char __user *buffer,
        return count;
 }
 
-static int proc_mf_change_cmdline(struct file *file, const char __user *buffer,
-               unsigned long count, void *data)
+static const struct file_operations mf_src_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = mf_src_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = mf_src_proc_write,
+};
+
+static ssize_t mf_cmdline_proc_write(struct file *file, const char __user *buffer,
+                                    size_t count, loff_t *pos)
 {
+       void *data = PDE(file->f_path.dentry->d_inode)->data;
        struct vsp_cmd_data vsp_cmd;
        dma_addr_t dma_addr;
        char *page;
@@ -1172,6 +1188,15 @@ out:
        return ret;
 }
 
+static const struct file_operations mf_cmdline_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = mf_cmdline_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = mf_cmdline_proc_write,
+};
+
 static ssize_t proc_mf_change_vmlinux(struct file *file,
                                      const char __user *buf,
                                      size_t count, loff_t *ppos)
@@ -1246,12 +1271,10 @@ static int __init mf_proc_init(void)
                if (!mf)
                        return 1;
 
-               ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf);
+               ent = proc_create_data("cmdline", S_IRUSR|S_IWUSR, mf,
+                                      &mf_cmdline_proc_fops, (void *)(long)i);
                if (!ent)
                        return 1;
-               ent->data = (void *)(long)i;
-               ent->read_proc = proc_mf_dump_cmdline;
-               ent->write_proc = proc_mf_change_cmdline;
 
                if (i == 3)     /* no vmlinux entry for 'D' */
                        continue;
@@ -1263,19 +1286,15 @@ static int __init mf_proc_init(void)
                        return 1;
        }
 
-       ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
+       ent = proc_create("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,
+                         &mf_side_proc_fops);
        if (!ent)
                return 1;
-       ent->data = (void *)0;
-       ent->read_proc = proc_mf_dump_side;
-       ent->write_proc = proc_mf_change_side;
 
-       ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
+       ent = proc_create("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,
+                         &mf_src_proc_fops);
        if (!ent)
                return 1;
-       ent->data = (void *)0;
-       ent->read_proc = proc_mf_dump_src;
-       ent->write_proc = proc_mf_change_src;
 
        return 0;
 }
index 49ff4dc..5aea94f 100644 (file)
@@ -116,7 +116,7 @@ static int proc_viopath_show(struct seq_file *m, void *v)
        u16 vlanMap;
        dma_addr_t handle;
        HvLpEvent_Rc hvrc;
-       DECLARE_COMPLETION(done);
+       DECLARE_COMPLETION_ONSTACK(done);
        struct device_node *node;
        const char *sysid;
 
index 27554c8..c667f0f 100644 (file)
@@ -2,6 +2,8 @@ config PPC_PSERIES
        depends on PPC64 && PPC_BOOK3S
        bool "IBM pSeries & new (POWER5-based) iSeries"
        select MPIC
+       select PCI_MSI
+       select XICS
        select PPC_I8259
        select PPC_RTAS
        select PPC_RTAS_DAEMON
index bcdcf0c..a277f2e 100644 (file)
 #include <asm/mmu.h>
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
+#include <linux/memory.h>
 
 #include "plpar_wrappers.h"
 
 #define CMM_DRIVER_VERSION     "1.0.0"
 #define CMM_DEFAULT_DELAY      1
+#define CMM_HOTPLUG_DELAY      5
 #define CMM_DEBUG                      0
 #define CMM_DISABLE            0
 #define CMM_OOM_KB             1024
 #define CMM_MIN_MEM_MB         256
 #define KB2PAGES(_p)           ((_p)>>(PAGE_SHIFT-10))
 #define PAGES2KB(_p)           ((_p)<<(PAGE_SHIFT-10))
+/*
+ * The priority level tries to ensure that this notifier is called as
+ * late as possible to reduce thrashing in the shared memory pool.
+ */
+#define CMM_MEM_HOTPLUG_PRI    1
+#define CMM_MEM_ISOLATE_PRI    15
 
 static unsigned int delay = CMM_DEFAULT_DELAY;
+static unsigned int hotplug_delay = CMM_HOTPLUG_DELAY;
 static unsigned int oom_kb = CMM_OOM_KB;
 static unsigned int cmm_debug = CMM_DEBUG;
 static unsigned int cmm_disabled = CMM_DISABLE;
@@ -65,6 +74,10 @@ MODULE_VERSION(CMM_DRIVER_VERSION);
 module_param_named(delay, delay, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(delay, "Delay (in seconds) between polls to query hypervisor paging requests. "
                 "[Default=" __stringify(CMM_DEFAULT_DELAY) "]");
+module_param_named(hotplug_delay, hotplug_delay, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(delay, "Delay (in seconds) after memory hotplug remove "
+                "before loaning resumes. "
+                "[Default=" __stringify(CMM_HOTPLUG_DELAY) "]");
 module_param_named(oom_kb, oom_kb, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(oom_kb, "Amount of memory in kb to free on OOM. "
                 "[Default=" __stringify(CMM_OOM_KB) "]");
@@ -92,6 +105,9 @@ static unsigned long oom_freed_pages;
 static struct cmm_page_array *cmm_page_list;
 static DEFINE_SPINLOCK(cmm_lock);
 
+static DEFINE_MUTEX(hotplug_mutex);
+static int hotplug_occurred; /* protected by the hotplug mutex */
+
 static struct task_struct *cmm_thread_ptr;
 
 /**
@@ -110,6 +126,17 @@ static long cmm_alloc_pages(long nr)
        cmm_dbg("Begin request for %ld pages\n", nr);
 
        while (nr) {
+               /* Exit if a hotplug operation is in progress or occurred */
+               if (mutex_trylock(&hotplug_mutex)) {
+                       if (hotplug_occurred) {
+                               mutex_unlock(&hotplug_mutex);
+                               break;
+                       }
+                       mutex_unlock(&hotplug_mutex);
+               } else {
+                       break;
+               }
+
                addr = __get_free_page(GFP_NOIO | __GFP_NOWARN |
                                       __GFP_NORETRY | __GFP_NOMEMALLOC);
                if (!addr)
@@ -119,8 +146,9 @@ static long cmm_alloc_pages(long nr)
                if (!pa || pa->index >= CMM_NR_PAGES) {
                        /* Need a new page for the page list. */
                        spin_unlock(&cmm_lock);
-                       npa = (struct cmm_page_array *)__get_free_page(GFP_NOIO | __GFP_NOWARN |
-                                                                      __GFP_NORETRY | __GFP_NOMEMALLOC);
+                       npa = (struct cmm_page_array *)__get_free_page(
+                                       GFP_NOIO | __GFP_NOWARN |
+                                       __GFP_NORETRY | __GFP_NOMEMALLOC);
                        if (!npa) {
                                pr_info("%s: Can not allocate new page list\n", __func__);
                                free_page(addr);
@@ -282,9 +310,28 @@ static int cmm_thread(void *dummy)
        while (1) {
                timeleft = msleep_interruptible(delay * 1000);
 
-               if (kthread_should_stop() || timeleft) {
-                       loaned_pages_target = loaned_pages;
+               if (kthread_should_stop() || timeleft)
                        break;
+
+               if (mutex_trylock(&hotplug_mutex)) {
+                       if (hotplug_occurred) {
+                               hotplug_occurred = 0;
+                               mutex_unlock(&hotplug_mutex);
+                               cmm_dbg("Hotplug operation has occurred, "
+                                               "loaning activity suspended "
+                                               "for %d seconds.\n",
+                                               hotplug_delay);
+                               timeleft = msleep_interruptible(hotplug_delay *
+                                               1000);
+                               if (kthread_should_stop() || timeleft)
+                                       break;
+                               continue;
+                       }
+                       mutex_unlock(&hotplug_mutex);
+               } else {
+                       cmm_dbg("Hotplug operation in progress, activity "
+                                       "suspended\n");
+                       continue;
                }
 
                cmm_get_mpp();
@@ -414,6 +461,193 @@ static struct notifier_block cmm_reboot_nb = {
 };
 
 /**
+ * cmm_count_pages - Count the number of pages loaned in a particular range.
+ *
+ * @arg: memory_isolate_notify structure with address range and count
+ *
+ * Return value:
+ *      0 on success
+ **/
+static unsigned long cmm_count_pages(void *arg)
+{
+       struct memory_isolate_notify *marg = arg;
+       struct cmm_page_array *pa;
+       unsigned long start = (unsigned long)pfn_to_kaddr(marg->start_pfn);
+       unsigned long end = start + (marg->nr_pages << PAGE_SHIFT);
+       unsigned long idx;
+
+       spin_lock(&cmm_lock);
+       pa = cmm_page_list;
+       while (pa) {
+               if ((unsigned long)pa >= start && (unsigned long)pa < end)
+                       marg->pages_found++;
+               for (idx = 0; idx < pa->index; idx++)
+                       if (pa->page[idx] >= start && pa->page[idx] < end)
+                               marg->pages_found++;
+               pa = pa->next;
+       }
+       spin_unlock(&cmm_lock);
+       return 0;
+}
+
+/**
+ * cmm_memory_isolate_cb - Handle memory isolation notifier calls
+ * @self:      notifier block struct
+ * @action:    action to take
+ * @arg:       struct memory_isolate_notify data for handler
+ *
+ * Return value:
+ *     NOTIFY_OK or notifier error based on subfunction return value
+ **/
+static int cmm_memory_isolate_cb(struct notifier_block *self,
+                                unsigned long action, void *arg)
+{
+       int ret = 0;
+
+       if (action == MEM_ISOLATE_COUNT)
+               ret = cmm_count_pages(arg);
+
+       if (ret)
+               ret = notifier_from_errno(ret);
+       else
+               ret = NOTIFY_OK;
+
+       return ret;
+}
+
+static struct notifier_block cmm_mem_isolate_nb = {
+       .notifier_call = cmm_memory_isolate_cb,
+       .priority = CMM_MEM_ISOLATE_PRI
+};
+
+/**
+ * cmm_mem_going_offline - Unloan pages where memory is to be removed
+ * @arg: memory_notify structure with page range to be offlined
+ *
+ * Return value:
+ *     0 on success
+ **/
+static int cmm_mem_going_offline(void *arg)
+{
+       struct memory_notify *marg = arg;
+       unsigned long start_page = (unsigned long)pfn_to_kaddr(marg->start_pfn);
+       unsigned long end_page = start_page + (marg->nr_pages << PAGE_SHIFT);
+       struct cmm_page_array *pa_curr, *pa_last, *npa;
+       unsigned long idx;
+       unsigned long freed = 0;
+
+       cmm_dbg("Memory going offline, searching 0x%lx (%ld pages).\n",
+                       start_page, marg->nr_pages);
+       spin_lock(&cmm_lock);
+
+       /* Search the page list for pages in the range to be offlined */
+       pa_last = pa_curr = cmm_page_list;
+       while (pa_curr) {
+               for (idx = (pa_curr->index - 1); (idx + 1) > 0; idx--) {
+                       if ((pa_curr->page[idx] < start_page) ||
+                           (pa_curr->page[idx] >= end_page))
+                               continue;
+
+                       plpar_page_set_active(__pa(pa_curr->page[idx]));
+                       free_page(pa_curr->page[idx]);
+                       freed++;
+                       loaned_pages--;
+                       totalram_pages++;
+                       pa_curr->page[idx] = pa_last->page[--pa_last->index];
+                       if (pa_last->index == 0) {
+                               if (pa_curr == pa_last)
+                                       pa_curr = pa_last->next;
+                               pa_last = pa_last->next;
+                               free_page((unsigned long)cmm_page_list);
+                               cmm_page_list = pa_last;
+                               continue;
+                       }
+               }
+               pa_curr = pa_curr->next;
+       }
+
+       /* Search for page list structures in the range to be offlined */
+       pa_last = NULL;
+       pa_curr = cmm_page_list;
+       while (pa_curr) {
+               if (((unsigned long)pa_curr >= start_page) &&
+                               ((unsigned long)pa_curr < end_page)) {
+                       npa = (struct cmm_page_array *)__get_free_page(
+                                       GFP_NOIO | __GFP_NOWARN |
+                                       __GFP_NORETRY | __GFP_NOMEMALLOC);
+                       if (!npa) {
+                               spin_unlock(&cmm_lock);
+                               cmm_dbg("Failed to allocate memory for list "
+                                               "management. Memory hotplug "
+                                               "failed.\n");
+                               return ENOMEM;
+                       }
+                       memcpy(npa, pa_curr, PAGE_SIZE);
+                       if (pa_curr == cmm_page_list)
+                               cmm_page_list = npa;
+                       if (pa_last)
+                               pa_last->next = npa;
+                       free_page((unsigned long) pa_curr);
+                       freed++;
+                       pa_curr = npa;
+               }
+
+               pa_last = pa_curr;
+               pa_curr = pa_curr->next;
+       }
+
+       spin_unlock(&cmm_lock);
+       cmm_dbg("Released %ld pages in the search range.\n", freed);
+
+       return 0;
+}
+
+/**
+ * cmm_memory_cb - Handle memory hotplug notifier calls
+ * @self:      notifier block struct
+ * @action:    action to take
+ * @arg:       struct memory_notify data for handler
+ *
+ * Return value:
+ *     NOTIFY_OK or notifier error based on subfunction return value
+ *
+ **/
+static int cmm_memory_cb(struct notifier_block *self,
+                       unsigned long action, void *arg)
+{
+       int ret = 0;
+
+       switch (action) {
+       case MEM_GOING_OFFLINE:
+               mutex_lock(&hotplug_mutex);
+               hotplug_occurred = 1;
+               ret = cmm_mem_going_offline(arg);
+               break;
+       case MEM_OFFLINE:
+       case MEM_CANCEL_OFFLINE:
+               mutex_unlock(&hotplug_mutex);
+               cmm_dbg("Memory offline operation complete.\n");
+               break;
+       case MEM_GOING_ONLINE:
+       case MEM_ONLINE:
+       case MEM_CANCEL_ONLINE:
+               break;
+       }
+
+       if (ret)
+               ret = notifier_from_errno(ret);
+       else
+               ret = NOTIFY_OK;
+
+       return ret;
+}
+
+static struct notifier_block cmm_mem_nb = {
+       .notifier_call = cmm_memory_cb,
+       .priority = CMM_MEM_HOTPLUG_PRI
+};
+
+/**
  * cmm_init - Module initialization
  *
  * Return value:
@@ -435,18 +669,24 @@ static int cmm_init(void)
        if ((rc = cmm_sysfs_register(&cmm_sysdev)))
                goto out_reboot_notifier;
 
+       if (register_memory_notifier(&cmm_mem_nb) ||
+           register_memory_isolate_notifier(&cmm_mem_isolate_nb))
+               goto out_unregister_notifier;
+
        if (cmm_disabled)
                return rc;
 
        cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
        if (IS_ERR(cmm_thread_ptr)) {
                rc = PTR_ERR(cmm_thread_ptr);
-               goto out_unregister_sysfs;
+               goto out_unregister_notifier;
        }
 
        return rc;
 
-out_unregister_sysfs:
+out_unregister_notifier:
+       unregister_memory_notifier(&cmm_mem_nb);
+       unregister_memory_isolate_notifier(&cmm_mem_isolate_nb);
        cmm_unregister_sysfs(&cmm_sysdev);
 out_reboot_notifier:
        unregister_reboot_notifier(&cmm_reboot_nb);
@@ -467,6 +707,8 @@ static void cmm_exit(void)
                kthread_stop(cmm_thread_ptr);
        unregister_oom_notifier(&cmm_oom_nb);
        unregister_reboot_notifier(&cmm_reboot_nb);
+       unregister_memory_notifier(&cmm_mem_nb);
+       unregister_memory_isolate_notifier(&cmm_mem_isolate_nb);
        cmm_free_pages(loaned_pages);
        cmm_unregister_sysfs(&cmm_sysdev);
 }
index 12df9e8..67b7a10 100644 (file)
@@ -346,12 +346,14 @@ int dlpar_release_drc(u32 drc_index)
 
 static DEFINE_MUTEX(pseries_cpu_hotplug_mutex);
 
-void cpu_hotplug_driver_lock()
+void cpu_hotplug_driver_lock(void)
+__acquires(pseries_cpu_hotplug_mutex)
 {
        mutex_lock(&pseries_cpu_hotplug_mutex);
 }
 
-void cpu_hotplug_driver_unlock()
+void cpu_hotplug_driver_unlock(void)
+__releases(pseries_cpu_hotplug_mutex)
 {
        mutex_unlock(&pseries_cpu_hotplug_mutex);
 }
index 8868c01..b488663 100644 (file)
@@ -144,8 +144,8 @@ static void __devinit smp_pSeries_kick_cpu(int nr)
                hcpuid = get_hard_smp_processor_id(nr);
                rc = plpar_hcall_norets(H_PROD, hcpuid);
                if (rc != H_SUCCESS)
-                       panic("Error: Prod to wake up processor %d Ret= %ld\n",
-                               nr, rc);
+                       printk(KERN_ERR "Error: Prod to wake up processor %d\
+                                               Ret= %ld\n", nr, rc);
        }
 }
 
index 971483f..1709ac5 100644 (file)
@@ -143,13 +143,23 @@ static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type)
        struct irq_desc *desc = irq_to_desc(virq);
        unsigned int vold, vnew, edibit;
 
-       if (flow_type == IRQ_TYPE_NONE)
-               flow_type = IRQ_TYPE_LEVEL_LOW;
-
-       if (flow_type & IRQ_TYPE_EDGE_RISING) {
-               printk(KERN_ERR "CPM2 PIC: sense type 0x%x not supported\n",
-                       flow_type);
-               return -EINVAL;
+       /* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or
+        * IRQ_TYPE_EDGE_BOTH (default).  All others are IRQ_TYPE_EDGE_FALLING
+        * or IRQ_TYPE_LEVEL_LOW (default)
+        */
+       if (src >= CPM2_IRQ_PORTC15 && src <= CPM2_IRQ_PORTC0) {
+               if (flow_type == IRQ_TYPE_NONE)
+                       flow_type = IRQ_TYPE_EDGE_BOTH;
+
+               if (flow_type != IRQ_TYPE_EDGE_BOTH &&
+                   flow_type != IRQ_TYPE_EDGE_FALLING)
+                       goto err_sense;
+       } else {
+               if (flow_type == IRQ_TYPE_NONE)
+                       flow_type = IRQ_TYPE_LEVEL_LOW;
+
+               if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
+                       goto err_sense;
        }
 
        desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
@@ -181,6 +191,10 @@ static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type)
        if (vold != vnew)
                out_be32(&cpm2_intctl->ic_siexr, vnew);
        return 0;
+
+err_sense:
+       pr_err("CPM2 PIC: sense type 0x%x not supported\n", flow_type);
+       return -EINVAL;
 }
 
 static struct irq_chip cpm2_pic = {
index 4e3a3e3..e1a028c 100644 (file)
@@ -464,8 +464,7 @@ static void __iomem *mpc83xx_pcie_remap_cfg(struct pci_bus *bus,
 {
        struct pci_controller *hose = pci_bus_to_host(bus);
        struct mpc83xx_pcie_priv *pcie = hose->dn->data;
-       u8 bus_no = bus->number - hose->first_busno;
-       u32 dev_base = bus_no << 24 | devfn << 16;
+       u32 dev_base = bus->number << 24 | devfn << 16;
        int ret;
 
        ret = mpc83xx_pcie_exclude_device(bus, devfn);
@@ -515,12 +514,17 @@ static int mpc83xx_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
 static int mpc83xx_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
                                     int offset, int len, u32 val)
 {
+       struct pci_controller *hose = pci_bus_to_host(bus);
        void __iomem *cfg_addr;
 
        cfg_addr = mpc83xx_pcie_remap_cfg(bus, devfn, offset);
        if (!cfg_addr)
                return PCIBIOS_DEVICE_NOT_FOUND;
 
+       /* PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS */
+       if (offset == PCI_PRIMARY_BUS && bus->number == hose->first_busno)
+               val &= 0xffffff00;
+
        switch (len) {
        case 1:
                out_8(cfg_addr, val);
index 103eace..ee1c0e1 100644 (file)
@@ -54,6 +54,22 @@ static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm)
        mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT);
 }
 
+/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs
+ * defined as output cannot be determined by reading GPDAT register,
+ * so we use shadow data register instead. The status of input pins
+ * is determined by reading GPDAT register.
+ */
+static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+       u32 val;
+       struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+
+       val = in_be32(mm->regs + GPIO_DAT) & ~in_be32(mm->regs + GPIO_DIR);
+
+       return (val | mpc8xxx_gc->data) & mpc8xxx_gpio2mask(gpio);
+}
+
 static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
 {
        struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
@@ -136,7 +152,10 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
        gc->ngpio = MPC8XXX_GPIO_PINS;
        gc->direction_input = mpc8xxx_gpio_dir_in;
        gc->direction_output = mpc8xxx_gpio_dir_out;
-       gc->get = mpc8xxx_gpio_get;
+       if (of_device_is_compatible(np, "fsl,mpc8572-gpio"))
+               gc->get = mpc8572_gpio_get;
+       else
+               gc->get = mpc8xxx_gpio_get;
        gc->set = mpc8xxx_gpio_set;
 
        ret = of_mm_gpiochip_add(np, mm_gc);
index aa9d06e..470dc6c 100644 (file)
@@ -567,13 +567,11 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
 #endif /* CONFIG_MPIC_U3_HT_IRQS */
 
 #ifdef CONFIG_SMP
-static int irq_choose_cpu(unsigned int virt_irq)
+static int irq_choose_cpu(const cpumask_t *mask)
 {
-       cpumask_t mask;
        int cpuid;
 
-       cpumask_copy(&mask, irq_to_desc(virt_irq)->affinity);
-       if (cpus_equal(mask, CPU_MASK_ALL)) {
+       if (cpumask_equal(mask, cpu_all_mask)) {
                static int irq_rover;
                static DEFINE_SPINLOCK(irq_rover_lock);
                unsigned long flags;
@@ -594,20 +592,15 @@ static int irq_choose_cpu(unsigned int virt_irq)
 
                spin_unlock_irqrestore(&irq_rover_lock, flags);
        } else {
-               cpumask_t tmp;
-
-               cpus_and(tmp, cpu_online_map, mask);
-
-               if (cpus_empty(tmp))
+               cpuid = cpumask_first_and(mask, cpu_online_mask);
+               if (cpuid >= nr_cpu_ids)
                        goto do_round_robin;
-
-               cpuid = first_cpu(tmp);
        }
 
        return get_hard_smp_processor_id(cpuid);
 }
 #else
-static int irq_choose_cpu(unsigned int virt_irq)
+static int irq_choose_cpu(const cpumask_t *mask)
 {
        return hard_smp_processor_id();
 }
@@ -816,7 +809,7 @@ int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
        unsigned int src = mpic_irq_to_hw(irq);
 
        if (mpic->flags & MPIC_SINGLE_DEST_CPU) {
-               int cpuid = irq_choose_cpu(irq);
+               int cpuid = irq_choose_cpu(cpumask);
 
                mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
        } else {
index 1d44eee..0f67cd7 100644 (file)
@@ -39,7 +39,12 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
 
        pr_debug("mpic: found U3, guessing msi allocator setup\n");
 
-       /* Reserve source numbers we know are reserved in the HW */
+       /* Reserve source numbers we know are reserved in the HW.
+        *
+        * This is a bit of a mix of U3 and U4 reserves but that's going
+        * to work fine, we have plenty enugh numbers left so let's just
+        * mark anything we don't like reserved.
+        */
        for (i = 0;   i < 8;   i++)
                msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
 
@@ -49,6 +54,10 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
        for (i = 100; i < 105; i++)
                msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
 
+       for (i = 124; i < mpic->irq_count; i++)
+               msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
+
+
        np = NULL;
        while ((np = of_find_all_nodes(np))) {
                pr_debug("mpic: mapping hwirqs for %s\n", np->full_name);
index d3caf23..bcbfe79 100644 (file)
@@ -64,12 +64,12 @@ static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos)
        return addr;
 }
 
-static u64 find_ht_magic_addr(struct pci_dev *pdev)
+static u64 find_ht_magic_addr(struct pci_dev *pdev, unsigned int hwirq)
 {
        struct pci_bus *bus;
        unsigned int pos;
 
-       for (bus = pdev->bus; bus; bus = bus->parent) {
+       for (bus = pdev->bus; bus && bus->self; bus = bus->parent) {
                pos = pci_find_ht_capability(bus->self, HT_CAPTYPE_MSI_MAPPING);
                if (pos)
                        return read_ht_magic_addr(bus->self, pos);
@@ -78,13 +78,41 @@ static u64 find_ht_magic_addr(struct pci_dev *pdev)
        return 0;
 }
 
+static u64 find_u4_magic_addr(struct pci_dev *pdev, unsigned int hwirq)
+{
+       struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+
+       /* U4 PCIe MSIs need to write to the special register in
+        * the bridge that generates interrupts. There should be
+        * theorically a register at 0xf8005000 where you just write
+        * the MSI number and that triggers the right interrupt, but
+        * unfortunately, this is busted in HW, the bridge endian swaps
+        * the value and hits the wrong nibble in the register.
+        *
+        * So instead we use another register set which is used normally
+        * for converting HT interrupts to MPIC interrupts, which decodes
+        * the interrupt number as part of the low address bits
+        *
+        * This will not work if we ever use more than one legacy MSI in
+        * a block but we never do. For one MSI or multiple MSI-X where
+        * each interrupt address can be specified separately, it works
+        * just fine.
+        */
+       if (of_device_is_compatible(hose->dn, "u4-pcie") ||
+           of_device_is_compatible(hose->dn, "U4-pcie"))
+               return 0xf8004000 | (hwirq << 4);
+
+       return 0;
+}
+
 static int u3msi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
 {
        if (type == PCI_CAP_ID_MSIX)
                pr_debug("u3msi: MSI-X untested, trying anyway.\n");
 
        /* If we can't find a magic address then MSI ain't gonna work */
-       if (find_ht_magic_addr(pdev) == 0) {
+       if (find_ht_magic_addr(pdev, 0) == 0 &&
+           find_u4_magic_addr(pdev, 0) == 0) {
                pr_debug("u3msi: no magic address found for %s\n",
                         pci_name(pdev));
                return -ENXIO;
@@ -118,10 +146,6 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
        u64 addr;
        int hwirq;
 
-       addr = find_ht_magic_addr(pdev);
-       msg.address_lo = addr & 0xFFFFFFFF;
-       msg.address_hi = addr >> 32;
-
        list_for_each_entry(entry, &pdev->msi_list, list) {
                hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1);
                if (hwirq < 0) {
@@ -129,6 +153,12 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
                        return hwirq;
                }
 
+               addr = find_ht_magic_addr(pdev, hwirq);
+               if (addr == 0)
+                       addr = find_u4_magic_addr(pdev, hwirq);
+               msg.address_lo = addr & 0xFFFFFFFF;
+               msg.address_hi = addr >> 32;
+
                virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
                if (virq == NO_IRQ) {
                        pr_debug("u3msi: failed mapping hwirq 0x%x\n", hwirq);
@@ -143,6 +173,8 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
                pr_debug("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n",
                          virq, hwirq, (unsigned long)addr);
 
+               printk("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n",
+                         virq, hwirq, (unsigned long)addr);
                msg.data = hwirq;
                write_msi_msg(virq, &msg);
 
index c4b47a3..02c81f1 100644 (file)
@@ -1557,6 +1557,25 @@ static unsigned short atapi_io_port[] = {
        P_ATAPI_DMARQ,
        P_ATAPI_INTRQ,
        P_ATAPI_IORDY,
+       P_ATAPI_D0A,
+       P_ATAPI_D1A,
+       P_ATAPI_D2A,
+       P_ATAPI_D3A,
+       P_ATAPI_D4A,
+       P_ATAPI_D5A,
+       P_ATAPI_D6A,
+       P_ATAPI_D7A,
+       P_ATAPI_D8A,
+       P_ATAPI_D9A,
+       P_ATAPI_D10A,
+       P_ATAPI_D11A,
+       P_ATAPI_D12A,
+       P_ATAPI_D13A,
+       P_ATAPI_D14A,
+       P_ATAPI_D15A,
+       P_ATAPI_A0A,
+       P_ATAPI_A1A,
+       P_ATAPI_A2A,
        0
 };
 
index c4c8f2e..d7d77d4 100644 (file)
@@ -63,6 +63,20 @@ void unregister_memory_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL(unregister_memory_notifier);
 
+static ATOMIC_NOTIFIER_HEAD(memory_isolate_chain);
+
+int register_memory_isolate_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&memory_isolate_chain, nb);
+}
+EXPORT_SYMBOL(register_memory_isolate_notifier);
+
+void unregister_memory_isolate_notifier(struct notifier_block *nb)
+{
+       atomic_notifier_chain_unregister(&memory_isolate_chain, nb);
+}
+EXPORT_SYMBOL(unregister_memory_isolate_notifier);
+
 /*
  * register_memory - Setup a sysfs device for a memory block
  */
@@ -157,6 +171,11 @@ int memory_notify(unsigned long val, void *v)
        return blocking_notifier_call_chain(&memory_chain, val, v);
 }
 
+int memory_isolate_notify(unsigned long val, void *v)
+{
+       return atomic_notifier_call_chain(&memory_isolate_chain, val, v);
+}
+
 /*
  * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
  * OK to have direct references to sparsemem variables in here.
index 1a216c1..48adf80 100644 (file)
@@ -161,6 +161,32 @@ void device_pm_move_last(struct device *dev)
        list_move_tail(&dev->power.entry, &dpm_list);
 }
 
+static ktime_t initcall_debug_start(struct device *dev)
+{
+       ktime_t calltime = ktime_set(0, 0);
+
+       if (initcall_debug) {
+               pr_info("calling  %s+ @ %i\n",
+                               dev_name(dev), task_pid_nr(current));
+               calltime = ktime_get();
+       }
+
+       return calltime;
+}
+
+static void initcall_debug_report(struct device *dev, ktime_t calltime,
+                                 int error)
+{
+       ktime_t delta, rettime;
+
+       if (initcall_debug) {
+               rettime = ktime_get();
+               delta = ktime_sub(rettime, calltime);
+               pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
+                       error, (unsigned long long)ktime_to_ns(delta) >> 10);
+       }
+}
+
 /**
  * pm_op - Execute the PM operation appropriate for given PM event.
  * @dev: Device to handle.
@@ -172,13 +198,9 @@ static int pm_op(struct device *dev,
                 pm_message_t state)
 {
        int error = 0;
-       ktime_t calltime, delta, rettime;
+       ktime_t calltime;
 
-       if (initcall_debug) {
-               pr_info("calling  %s+ @ %i\n",
-                               dev_name(dev), task_pid_nr(current));
-               calltime = ktime_get();
-       }
+       calltime = initcall_debug_start(dev);
 
        switch (state.event) {
 #ifdef CONFIG_SUSPEND
@@ -227,12 +249,7 @@ static int pm_op(struct device *dev,
                error = -EINVAL;
        }
 
-       if (initcall_debug) {
-               rettime = ktime_get();
-               delta = ktime_sub(rettime, calltime);
-               pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev),
-                       error, (unsigned long long)ktime_to_ns(delta) >> 10);
-       }
+       initcall_debug_report(dev, calltime, error);
 
        return error;
 }
@@ -309,8 +326,9 @@ static int pm_noirq_op(struct device *dev,
        if (initcall_debug) {
                rettime = ktime_get();
                delta = ktime_sub(rettime, calltime);
-               printk("initcall %s_i+ returned %d after %Ld usecs\n", dev_name(dev),
-                       error, (unsigned long long)ktime_to_ns(delta) >> 10);
+               printk("initcall %s_i+ returned %d after %Ld usecs\n",
+                       dev_name(dev), error,
+                       (unsigned long long)ktime_to_ns(delta) >> 10);
        }
 
        return error;
@@ -354,6 +372,23 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
                kobject_name(&dev->kobj), pm_verb(state.event), info, error);
 }
 
+static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
+{
+       ktime_t calltime;
+       s64 usecs64;
+       int usecs;
+
+       calltime = ktime_get();
+       usecs64 = ktime_to_ns(ktime_sub(calltime, starttime));
+       do_div(usecs64, NSEC_PER_USEC);
+       usecs = usecs64;
+       if (usecs == 0)
+               usecs = 1;
+       pr_info("PM: %s%s%s of devices complete after %ld.%03ld msecs\n",
+               info ?: "", info ? " " : "", pm_verb(state.event),
+               usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);
+}
+
 /*------------------------- Resume routines -------------------------*/
 
 /**
@@ -390,6 +425,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
 void dpm_resume_noirq(pm_message_t state)
 {
        struct device *dev;
+       ktime_t starttime = ktime_get();
 
        mutex_lock(&dpm_list_mtx);
        transition_started = false;
@@ -403,11 +439,32 @@ void dpm_resume_noirq(pm_message_t state)
                                pm_dev_err(dev, state, " early", error);
                }
        mutex_unlock(&dpm_list_mtx);
+       dpm_show_time(starttime, state, "early");
        resume_device_irqs();
 }
 EXPORT_SYMBOL_GPL(dpm_resume_noirq);
 
 /**
+ * legacy_resume - Execute a legacy (bus or class) resume callback for device.
+ * dev: Device to resume.
+ * cb: Resume callback to execute.
+ */
+static int legacy_resume(struct device *dev, int (*cb)(struct device *dev))
+{
+       int error;
+       ktime_t calltime;
+
+       calltime = initcall_debug_start(dev);
+
+       error = cb(dev);
+       suspend_report_result(cb, error);
+
+       initcall_debug_report(dev, calltime, error);
+
+       return error;
+}
+
+/**
  * device_resume - Execute "resume" callbacks for given device.
  * @dev: Device to handle.
  * @state: PM transition of the system being carried out.
@@ -427,7 +484,7 @@ static int device_resume(struct device *dev, pm_message_t state)
                        error = pm_op(dev, dev->bus->pm, state);
                } else if (dev->bus->resume) {
                        pm_dev_dbg(dev, state, "legacy ");
-                       error = dev->bus->resume(dev);
+                       error = legacy_resume(dev, dev->bus->resume);
                }
                if (error)
                        goto End;
@@ -448,7 +505,7 @@ static int device_resume(struct device *dev, pm_message_t state)
                        error = pm_op(dev, dev->class->pm, state);
                } else if (dev->class->resume) {
                        pm_dev_dbg(dev, state, "legacy class ");
-                       error = dev->class->resume(dev);
+                       error = legacy_resume(dev, dev->class->resume);
                }
        }
  End:
@@ -468,6 +525,7 @@ static int device_resume(struct device *dev, pm_message_t state)
 static void dpm_resume(pm_message_t state)
 {
        struct list_head list;
+       ktime_t starttime = ktime_get();
 
        INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
@@ -496,6 +554,7 @@ static void dpm_resume(pm_message_t state)
        }
        list_splice(&list, &dpm_list);
        mutex_unlock(&dpm_list_mtx);
+       dpm_show_time(starttime, state, NULL);
 }
 
 /**
@@ -548,7 +607,7 @@ static void dpm_complete(pm_message_t state)
                        mutex_unlock(&dpm_list_mtx);
 
                        device_complete(dev, state);
-                       pm_runtime_put_noidle(dev);
+                       pm_runtime_put_sync(dev);
 
                        mutex_lock(&dpm_list_mtx);
                }
@@ -628,6 +687,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
 int dpm_suspend_noirq(pm_message_t state)
 {
        struct device *dev;
+       ktime_t starttime = ktime_get();
        int error = 0;
 
        suspend_device_irqs();
@@ -643,11 +703,34 @@ int dpm_suspend_noirq(pm_message_t state)
        mutex_unlock(&dpm_list_mtx);
        if (error)
                dpm_resume_noirq(resume_event(state));
+       else
+               dpm_show_time(starttime, state, "late");
        return error;
 }
 EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
 
 /**
+ * legacy_suspend - Execute a legacy (bus or class) suspend callback for device.
+ * dev: Device to suspend.
+ * cb: Suspend callback to execute.
+ */
+static int legacy_suspend(struct device *dev, pm_message_t state,
+                         int (*cb)(struct device *dev, pm_message_t state))
+{
+       int error;
+       ktime_t calltime;
+
+       calltime = initcall_debug_start(dev);
+
+       error = cb(dev, state);
+       suspend_report_result(cb, error);
+
+       initcall_debug_report(dev, calltime, error);
+
+       return error;
+}
+
+/**
  * device_suspend - Execute "suspend" callbacks for given device.
  * @dev: Device to handle.
  * @state: PM transition of the system being carried out.
@@ -664,8 +747,7 @@ static int device_suspend(struct device *dev, pm_message_t state)
                        error = pm_op(dev, dev->class->pm, state);
                } else if (dev->class->suspend) {
                        pm_dev_dbg(dev, state, "legacy class ");
-                       error = dev->class->suspend(dev, state);
-                       suspend_report_result(dev->class->suspend, error);
+                       error = legacy_suspend(dev, state, dev->class->suspend);
                }
                if (error)
                        goto End;
@@ -686,8 +768,7 @@ static int device_suspend(struct device *dev, pm_message_t state)
                        error = pm_op(dev, dev->bus->pm, state);
                } else if (dev->bus->suspend) {
                        pm_dev_dbg(dev, state, "legacy ");
-                       error = dev->bus->suspend(dev, state);
-                       suspend_report_result(dev->bus->suspend, error);
+                       error = legacy_suspend(dev, state, dev->bus->suspend);
                }
        }
  End:
@@ -703,6 +784,7 @@ static int device_suspend(struct device *dev, pm_message_t state)
 static int dpm_suspend(pm_message_t state)
 {
        struct list_head list;
+       ktime_t starttime = ktime_get();
        int error = 0;
 
        INIT_LIST_HEAD(&list);
@@ -728,6 +810,8 @@ static int dpm_suspend(pm_message_t state)
        }
        list_splice(&list, dpm_list.prev);
        mutex_unlock(&dpm_list_mtx);
+       if (!error)
+               dpm_show_time(starttime, state, NULL);
        return error;
 }
 
@@ -796,7 +880,7 @@ static int dpm_prepare(pm_message_t state)
                pm_runtime_get_noresume(dev);
                if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) {
                        /* Wake-up requested during system sleep transition. */
-                       pm_runtime_put_noidle(dev);
+                       pm_runtime_put_sync(dev);
                        error = -EBUSY;
                } else {
                        error = device_prepare(dev, state);
index 40d7720..f8b044e 100644 (file)
@@ -85,6 +85,19 @@ static int __pm_runtime_idle(struct device *dev)
                dev->bus->pm->runtime_idle(dev);
 
                spin_lock_irq(&dev->power.lock);
+       } else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
+               spin_unlock_irq(&dev->power.lock);
+
+               dev->type->pm->runtime_idle(dev);
+
+               spin_lock_irq(&dev->power.lock);
+       } else if (dev->class && dev->class->pm
+           && dev->class->pm->runtime_idle) {
+               spin_unlock_irq(&dev->power.lock);
+
+               dev->class->pm->runtime_idle(dev);
+
+               spin_lock_irq(&dev->power.lock);
        }
 
        dev->power.idle_notification = false;
@@ -194,6 +207,22 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
 
                spin_lock_irq(&dev->power.lock);
                dev->power.runtime_error = retval;
+       } else if (dev->type && dev->type->pm
+           && dev->type->pm->runtime_suspend) {
+               spin_unlock_irq(&dev->power.lock);
+
+               retval = dev->type->pm->runtime_suspend(dev);
+
+               spin_lock_irq(&dev->power.lock);
+               dev->power.runtime_error = retval;
+       } else if (dev->class && dev->class->pm
+           && dev->class->pm->runtime_suspend) {
+               spin_unlock_irq(&dev->power.lock);
+
+               retval = dev->class->pm->runtime_suspend(dev);
+
+               spin_lock_irq(&dev->power.lock);
+               dev->power.runtime_error = retval;
        } else {
                retval = -ENOSYS;
        }
@@ -359,6 +388,22 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
 
                spin_lock_irq(&dev->power.lock);
                dev->power.runtime_error = retval;
+       } else if (dev->type && dev->type->pm
+           && dev->type->pm->runtime_resume) {
+               spin_unlock_irq(&dev->power.lock);
+
+               retval = dev->type->pm->runtime_resume(dev);
+
+               spin_lock_irq(&dev->power.lock);
+               dev->power.runtime_error = retval;
+       } else if (dev->class && dev->class->pm
+           && dev->class->pm->runtime_resume) {
+               spin_unlock_irq(&dev->power.lock);
+
+               retval = dev->class->pm->runtime_resume(dev);
+
+               spin_lock_irq(&dev->power.lock);
+               dev->power.runtime_error = retval;
        } else {
                retval = -ENOSYS;
        }
index d3400b2..7d73cd4 100644 (file)
@@ -358,7 +358,7 @@ struct port {
        u8 update_flow_control;
        struct ctrl_ul ctrl_ul;
        struct ctrl_dl ctrl_dl;
-       struct kfifo *fifo_ul;
+       struct kfifo fifo_ul;
        void __iomem *dl_addr[2];
        u32 dl_size[2];
        u8 toggle_dl;
@@ -685,8 +685,6 @@ static int nozomi_read_config_table(struct nozomi *dc)
                dump_table(dc);
 
                for (i = PORT_MDM; i < MAX_PORT; i++) {
-                       dc->port[i].fifo_ul =
-                           kfifo_alloc(FIFO_BUFFER_SIZE_UL, GFP_ATOMIC, NULL);
                        memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl));
                        memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul));
                }
@@ -798,7 +796,7 @@ static int send_data(enum port_type index, struct nozomi *dc)
        struct tty_struct *tty = tty_port_tty_get(&port->port);
 
        /* Get data from tty and place in buf for now */
-       size = __kfifo_get(port->fifo_ul, dc->send_buf,
+       size = kfifo_out(&port->fifo_ul, dc->send_buf,
                           ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX);
 
        if (size == 0) {
@@ -988,11 +986,11 @@ static int receive_flow_control(struct nozomi *dc)
 
        } else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) {
 
-               if (__kfifo_len(dc->port[port].fifo_ul)) {
+               if (kfifo_len(&dc->port[port].fifo_ul)) {
                        DBG1("Enable interrupt (0x%04X) on port: %d",
                                enable_ier, port);
                        DBG1("Data in buffer [%d], enable transmit! ",
-                               __kfifo_len(dc->port[port].fifo_ul));
+                               kfifo_len(&dc->port[port].fifo_ul));
                        enable_transmit_ul(port, dc);
                } else {
                        DBG1("No data in buffer...");
@@ -1433,6 +1431,16 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
                goto err_free_sbuf;
        }
 
+       for (i = PORT_MDM; i < MAX_PORT; i++) {
+               if (kfifo_alloc(&dc->port[i].fifo_ul,
+                     FIFO_BUFFER_SIZE_UL, GFP_ATOMIC)) {
+                       dev_err(&pdev->dev,
+                                       "Could not allocate kfifo buffer\n");
+                       ret = -ENOMEM;
+                       goto err_free_kfifo;
+               }
+       }
+
        spin_lock_init(&dc->spin_mutex);
 
        nozomi_setup_private_data(dc);
@@ -1445,7 +1453,7 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
                        NOZOMI_NAME, dc);
        if (unlikely(ret)) {
                dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq);
-               goto err_free_sbuf;
+               goto err_free_kfifo;
        }
 
        DBG1("base_addr: %p", dc->base_addr);
@@ -1464,13 +1472,28 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
        dc->state = NOZOMI_STATE_ENABLED;
 
        for (i = 0; i < MAX_PORT; i++) {
+               struct device *tty_dev;
+
                mutex_init(&dc->port[i].tty_sem);
                tty_port_init(&dc->port[i].port);
-               tty_register_device(ntty_driver, dc->index_start + i,
+               tty_dev = tty_register_device(ntty_driver, dc->index_start + i,
                                                        &pdev->dev);
+
+               if (IS_ERR(tty_dev)) {
+                       ret = PTR_ERR(tty_dev);
+                       dev_err(&pdev->dev, "Could not allocate tty?\n");
+                       goto err_free_tty;
+               }
        }
+
        return 0;
 
+err_free_tty:
+       for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i)
+               tty_unregister_device(ntty_driver, i);
+err_free_kfifo:
+       for (i = 0; i < MAX_PORT; i++)
+               kfifo_free(&dc->port[i].fifo_ul);
 err_free_sbuf:
        kfree(dc->send_buf);
        iounmap(dc->base_addr);
@@ -1536,8 +1559,7 @@ static void __devexit nozomi_card_exit(struct pci_dev *pdev)
        free_irq(pdev->irq, dc);
 
        for (i = 0; i < MAX_PORT; i++)
-               if (dc->port[i].fifo_ul)
-                       kfifo_free(dc->port[i].fifo_ul);
+               kfifo_free(&dc->port[i].fifo_ul);
 
        kfree(dc->send_buf);
 
@@ -1673,7 +1695,7 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
                goto exit;
        }
 
-       rval = __kfifo_put(port->fifo_ul, (unsigned char *)buffer, count);
+       rval = kfifo_in(&port->fifo_ul, (unsigned char *)buffer, count);
 
        /* notify card */
        if (unlikely(dc == NULL)) {
@@ -1721,7 +1743,7 @@ static int ntty_write_room(struct tty_struct *tty)
        if (!port->port.count)
                goto exit;
 
-       room = port->fifo_ul->size - __kfifo_len(port->fifo_ul);
+       room = port->fifo_ul.size - kfifo_len(&port->fifo_ul);
 
 exit:
        mutex_unlock(&port->tty_sem);
@@ -1878,7 +1900,7 @@ static s32 ntty_chars_in_buffer(struct tty_struct *tty)
                goto exit_in_buffer;
        }
 
-       rval = __kfifo_len(port->fifo_ul);
+       rval = kfifo_len(&port->fifo_ul);
 
 exit_in_buffer:
        return rval;
index 8c262aa..0798754 100644 (file)
@@ -487,7 +487,7 @@ static struct sonypi_device {
        int camera_power;
        int bluetooth_power;
        struct mutex lock;
-       struct kfifo *fifo;
+       struct kfifo fifo;
        spinlock_t fifo_lock;
        wait_queue_head_t fifo_proc_list;
        struct fasync_struct *fifo_async;
@@ -496,7 +496,7 @@ static struct sonypi_device {
        struct input_dev *input_jog_dev;
        struct input_dev *input_key_dev;
        struct work_struct input_work;
-       struct kfifo *input_fifo;
+       struct kfifo input_fifo;
        spinlock_t input_fifo_lock;
 } sonypi_device;
 
@@ -777,8 +777,9 @@ static void input_keyrelease(struct work_struct *work)
 {
        struct sonypi_keypress kp;
 
-       while (kfifo_get(sonypi_device.input_fifo, (unsigned char *)&kp,
-                        sizeof(kp)) == sizeof(kp)) {
+       while (kfifo_out_locked(&sonypi_device.input_fifo, (unsigned char *)&kp,
+                        sizeof(kp), &sonypi_device.input_fifo_lock)
+                       == sizeof(kp)) {
                msleep(10);
                input_report_key(kp.dev, kp.key, 0);
                input_sync(kp.dev);
@@ -827,8 +828,9 @@ static void sonypi_report_input_event(u8 event)
        if (kp.dev) {
                input_report_key(kp.dev, kp.key, 1);
                input_sync(kp.dev);
-               kfifo_put(sonypi_device.input_fifo,
-                         (unsigned char *)&kp, sizeof(kp));
+               kfifo_in_locked(&sonypi_device.input_fifo,
+                       (unsigned char *)&kp, sizeof(kp),
+                       &sonypi_device.input_fifo_lock);
                schedule_work(&sonypi_device.input_work);
        }
 }
@@ -880,7 +882,8 @@ found:
                acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event);
 #endif
 
-       kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event));
+       kfifo_in_locked(&sonypi_device.fifo, (unsigned char *)&event,
+                       sizeof(event), &sonypi_device.fifo_lock);
        kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
        wake_up_interruptible(&sonypi_device.fifo_proc_list);
 
@@ -906,7 +909,7 @@ static int sonypi_misc_open(struct inode *inode, struct file *file)
        mutex_lock(&sonypi_device.lock);
        /* Flush input queue on first open */
        if (!sonypi_device.open_count)
-               kfifo_reset(sonypi_device.fifo);
+               kfifo_reset(&sonypi_device.fifo);
        sonypi_device.open_count++;
        mutex_unlock(&sonypi_device.lock);
        unlock_kernel();
@@ -919,17 +922,18 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
        ssize_t ret;
        unsigned char c;
 
-       if ((kfifo_len(sonypi_device.fifo) == 0) &&
+       if ((kfifo_len(&sonypi_device.fifo) == 0) &&
            (file->f_flags & O_NONBLOCK))
                return -EAGAIN;
 
        ret = wait_event_interruptible(sonypi_device.fifo_proc_list,
-                                      kfifo_len(sonypi_device.fifo) != 0);
+                                      kfifo_len(&sonypi_device.fifo) != 0);
        if (ret)
                return ret;
 
        while (ret < count &&
-              (kfifo_get(sonypi_device.fifo, &c, sizeof(c)) == sizeof(c))) {
+              (kfifo_out_locked(&sonypi_device.fifo, &c, sizeof(c),
+                                &sonypi_device.fifo_lock) == sizeof(c))) {
                if (put_user(c, buf++))
                        return -EFAULT;
                ret++;
@@ -946,7 +950,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
 static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
 {
        poll_wait(file, &sonypi_device.fifo_proc_list, wait);
-       if (kfifo_len(sonypi_device.fifo))
+       if (kfifo_len(&sonypi_device.fifo))
                return POLLIN | POLLRDNORM;
        return 0;
 }
@@ -1313,11 +1317,10 @@ static int __devinit sonypi_probe(struct platform_device *dev)
                        "http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n");
 
        spin_lock_init(&sonypi_device.fifo_lock);
-       sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
-                                        &sonypi_device.fifo_lock);
-       if (IS_ERR(sonypi_device.fifo)) {
+       error = kfifo_alloc(&sonypi_device.fifo, SONYPI_BUF_SIZE, GFP_KERNEL);
+       if (error) {
                printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
-               return PTR_ERR(sonypi_device.fifo);
+               return error;
        }
 
        init_waitqueue_head(&sonypi_device.fifo_proc_list);
@@ -1393,12 +1396,10 @@ static int __devinit sonypi_probe(struct platform_device *dev)
                }
 
                spin_lock_init(&sonypi_device.input_fifo_lock);
-               sonypi_device.input_fifo =
-                       kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
-                                   &sonypi_device.input_fifo_lock);
-               if (IS_ERR(sonypi_device.input_fifo)) {
+               error = kfifo_alloc(&sonypi_device.input_fifo, SONYPI_BUF_SIZE,
+                               GFP_KERNEL);
+               if (error) {
                        printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
-                       error = PTR_ERR(sonypi_device.input_fifo);
                        goto err_inpdev_unregister;
                }
 
@@ -1423,7 +1424,7 @@ static int __devinit sonypi_probe(struct platform_device *dev)
                pci_disable_device(pcidev);
  err_put_pcidev:
        pci_dev_put(pcidev);
-       kfifo_free(sonypi_device.fifo);
+       kfifo_free(&sonypi_device.fifo);
 
        return error;
 }
@@ -1438,7 +1439,7 @@ static int __devexit sonypi_remove(struct platform_device *dev)
        if (useinput) {
                input_unregister_device(sonypi_device.input_key_dev);
                input_unregister_device(sonypi_device.input_jog_dev);
-               kfifo_free(sonypi_device.input_fifo);
+               kfifo_free(&sonypi_device.input_fifo);
        }
 
        misc_deregister(&sonypi_misc_device);
@@ -1451,7 +1452,7 @@ static int __devexit sonypi_remove(struct platform_device *dev)
                pci_dev_put(sonypi_device.dev);
        }
 
-       kfifo_free(sonypi_device.fifo);
+       kfifo_free(&sonypi_device.fifo);
 
        return 0;
 }
index ff2f104..766c468 100644 (file)
@@ -434,11 +434,11 @@ static int drm_version(struct drm_device *dev, void *data,
  * Looks up the ioctl function in the ::ioctls table, checking for root
  * previleges if so required, and dispatches to the respective function.
  */
-int drm_ioctl(struct inode *inode, struct file *filp,
+long drm_ioctl(struct file *filp,
              unsigned int cmd, unsigned long arg)
 {
        struct drm_file *file_priv = filp->private_data;
-       struct drm_device *dev = file_priv->minor->dev;
+       struct drm_device *dev;
        struct drm_ioctl_desc *ioctl;
        drm_ioctl_t *func;
        unsigned int nr = DRM_IOCTL_NR(cmd);
@@ -446,6 +446,7 @@ int drm_ioctl(struct inode *inode, struct file *filp,
        char stack_kdata[128];
        char *kdata = NULL;
 
+       dev = file_priv->minor->dev;
        atomic_inc(&dev->ioctl_count);
        atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
        ++file_priv->ioctl_count;
@@ -501,7 +502,13 @@ int drm_ioctl(struct inode *inode, struct file *filp,
                                goto err_i1;
                        }
                }
-               retcode = func(dev, kdata, file_priv);
+               if (ioctl->flags & DRM_UNLOCKED)
+                       retcode = func(dev, kdata, file_priv);
+               else {
+                       lock_kernel();
+                       retcode = func(dev, kdata, file_priv);
+                       unlock_kernel();
+               }
 
                if (cmd & IOC_OUT) {
                        if (copy_to_user((void __user *)arg, kdata,
index c39b26f..5c9f798 100644 (file)
@@ -913,7 +913,7 @@ static int drm_cvt_modes(struct drm_connector *connector,
        const int rates[] = { 60, 85, 75, 60, 50 };
 
        for (i = 0; i < 4; i++) {
-               int width, height;
+               int uninitialized_var(width), height;
                cvt = &(timing->data.other_data.data.cvt[i]);
 
                height = (cvt->code[0] + ((cvt->code[1] & 0xf0) << 8) + 1) * 2;
index 282d9fd..d61d185 100644 (file)
@@ -104,7 +104,7 @@ static int compat_drm_version(struct file *file, unsigned int cmd,
                          &version->desc))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
+       err = drm_ioctl(file,
                        DRM_IOCTL_VERSION, (unsigned long)version);
        if (err)
                return err;
@@ -145,8 +145,7 @@ static int compat_drm_getunique(struct file *file, unsigned int cmd,
                          &u->unique))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_GET_UNIQUE, (unsigned long)u);
+       err = drm_ioctl(file, DRM_IOCTL_GET_UNIQUE, (unsigned long)u);
        if (err)
                return err;
 
@@ -174,8 +173,7 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd,
                          &u->unique))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_SET_UNIQUE, (unsigned long)u);
+       return drm_ioctl(file, DRM_IOCTL_SET_UNIQUE, (unsigned long)u);
 }
 
 typedef struct drm_map32 {
@@ -205,8 +203,7 @@ static int compat_drm_getmap(struct file *file, unsigned int cmd,
        if (__put_user(idx, &map->offset))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_GET_MAP, (unsigned long)map);
+       err = drm_ioctl(file, DRM_IOCTL_GET_MAP, (unsigned long)map);
        if (err)
                return err;
 
@@ -246,8 +243,7 @@ static int compat_drm_addmap(struct file *file, unsigned int cmd,
            || __put_user(m32.flags, &map->flags))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_ADD_MAP, (unsigned long)map);
+       err = drm_ioctl(file, DRM_IOCTL_ADD_MAP, (unsigned long)map);
        if (err)
                return err;
 
@@ -284,8 +280,7 @@ static int compat_drm_rmmap(struct file *file, unsigned int cmd,
        if (__put_user((void *)(unsigned long)handle, &map->handle))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_RM_MAP, (unsigned long)map);
+       return drm_ioctl(file, DRM_IOCTL_RM_MAP, (unsigned long)map);
 }
 
 typedef struct drm_client32 {
@@ -314,8 +309,7 @@ static int compat_drm_getclient(struct file *file, unsigned int cmd,
        if (__put_user(idx, &client->idx))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_GET_CLIENT, (unsigned long)client);
+       err = drm_ioctl(file, DRM_IOCTL_GET_CLIENT, (unsigned long)client);
        if (err)
                return err;
 
@@ -351,8 +345,7 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd,
        if (!access_ok(VERIFY_WRITE, stats, sizeof(*stats)))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_GET_STATS, (unsigned long)stats);
+       err = drm_ioctl(file, DRM_IOCTL_GET_STATS, (unsigned long)stats);
        if (err)
                return err;
 
@@ -395,8 +388,7 @@ static int compat_drm_addbufs(struct file *file, unsigned int cmd,
            || __put_user(agp_start, &buf->agp_start))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_ADD_BUFS, (unsigned long)buf);
+       err = drm_ioctl(file, DRM_IOCTL_ADD_BUFS, (unsigned long)buf);
        if (err)
                return err;
 
@@ -427,8 +419,7 @@ static int compat_drm_markbufs(struct file *file, unsigned int cmd,
            || __put_user(b32.high_mark, &buf->high_mark))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_MARK_BUFS, (unsigned long)buf);
+       return drm_ioctl(file, DRM_IOCTL_MARK_BUFS, (unsigned long)buf);
 }
 
 typedef struct drm_buf_info32 {
@@ -469,8 +460,7 @@ static int compat_drm_infobufs(struct file *file, unsigned int cmd,
            || __put_user(list, &request->list))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_INFO_BUFS, (unsigned long)request);
+       err = drm_ioctl(file, DRM_IOCTL_INFO_BUFS, (unsigned long)request);
        if (err)
                return err;
 
@@ -531,8 +521,7 @@ static int compat_drm_mapbufs(struct file *file, unsigned int cmd,
            || __put_user(list, &request->list))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_MAP_BUFS, (unsigned long)request);
+       err = drm_ioctl(file, DRM_IOCTL_MAP_BUFS, (unsigned long)request);
        if (err)
                return err;
 
@@ -578,8 +567,7 @@ static int compat_drm_freebufs(struct file *file, unsigned int cmd,
                          &request->list))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_FREE_BUFS, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_FREE_BUFS, (unsigned long)request);
 }
 
 typedef struct drm_ctx_priv_map32 {
@@ -605,8 +593,7 @@ static int compat_drm_setsareactx(struct file *file, unsigned int cmd,
                          &request->handle))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_SET_SAREA_CTX, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_SET_SAREA_CTX, (unsigned long)request);
 }
 
 static int compat_drm_getsareactx(struct file *file, unsigned int cmd,
@@ -628,8 +615,7 @@ static int compat_drm_getsareactx(struct file *file, unsigned int cmd,
        if (__put_user(ctx_id, &request->ctx_id))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_GET_SAREA_CTX, (unsigned long)request);
+       err = drm_ioctl(file, DRM_IOCTL_GET_SAREA_CTX, (unsigned long)request);
        if (err)
                return err;
 
@@ -664,8 +650,7 @@ static int compat_drm_resctx(struct file *file, unsigned int cmd,
                          &res->contexts))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_RES_CTX, (unsigned long)res);
+       err = drm_ioctl(file, DRM_IOCTL_RES_CTX, (unsigned long)res);
        if (err)
                return err;
 
@@ -718,8 +703,7 @@ static int compat_drm_dma(struct file *file, unsigned int cmd,
                          &d->request_sizes))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_DMA, (unsigned long)d);
+       err = drm_ioctl(file, DRM_IOCTL_DMA, (unsigned long)d);
        if (err)
                return err;
 
@@ -751,8 +735,7 @@ static int compat_drm_agp_enable(struct file *file, unsigned int cmd,
        if (put_user(m32.mode, &mode->mode))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_AGP_ENABLE, (unsigned long)mode);
+       return drm_ioctl(file, DRM_IOCTL_AGP_ENABLE, (unsigned long)mode);
 }
 
 typedef struct drm_agp_info32 {
@@ -781,8 +764,7 @@ static int compat_drm_agp_info(struct file *file, unsigned int cmd,
        if (!access_ok(VERIFY_WRITE, info, sizeof(*info)))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_AGP_INFO, (unsigned long)info);
+       err = drm_ioctl(file, DRM_IOCTL_AGP_INFO, (unsigned long)info);
        if (err)
                return err;
 
@@ -827,16 +809,14 @@ static int compat_drm_agp_alloc(struct file *file, unsigned int cmd,
            || __put_user(req32.type, &request->type))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_AGP_ALLOC, (unsigned long)request);
+       err = drm_ioctl(file, DRM_IOCTL_AGP_ALLOC, (unsigned long)request);
        if (err)
                return err;
 
        if (__get_user(req32.handle, &request->handle)
            || __get_user(req32.physical, &request->physical)
            || copy_to_user(argp, &req32, sizeof(req32))) {
-               drm_ioctl(file->f_path.dentry->d_inode, file,
-                         DRM_IOCTL_AGP_FREE, (unsigned long)request);
+               drm_ioctl(file, DRM_IOCTL_AGP_FREE, (unsigned long)request);
                return -EFAULT;
        }
 
@@ -856,8 +836,7 @@ static int compat_drm_agp_free(struct file *file, unsigned int cmd,
            || __put_user(handle, &request->handle))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_AGP_FREE, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_AGP_FREE, (unsigned long)request);
 }
 
 typedef struct drm_agp_binding32 {
@@ -881,8 +860,7 @@ static int compat_drm_agp_bind(struct file *file, unsigned int cmd,
            || __put_user(req32.offset, &request->offset))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_AGP_BIND, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_AGP_BIND, (unsigned long)request);
 }
 
 static int compat_drm_agp_unbind(struct file *file, unsigned int cmd,
@@ -898,8 +876,7 @@ static int compat_drm_agp_unbind(struct file *file, unsigned int cmd,
            || __put_user(handle, &request->handle))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_AGP_UNBIND, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_AGP_UNBIND, (unsigned long)request);
 }
 #endif                         /* __OS_HAS_AGP */
 
@@ -923,8 +900,7 @@ static int compat_drm_sg_alloc(struct file *file, unsigned int cmd,
            || __put_user(x, &request->size))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_SG_ALLOC, (unsigned long)request);
+       err = drm_ioctl(file, DRM_IOCTL_SG_ALLOC, (unsigned long)request);
        if (err)
                return err;
 
@@ -950,8 +926,7 @@ static int compat_drm_sg_free(struct file *file, unsigned int cmd,
            || __put_user(x << PAGE_SHIFT, &request->handle))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_SG_FREE, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_SG_FREE, (unsigned long)request);
 }
 
 #if defined(CONFIG_X86) || defined(CONFIG_IA64)
@@ -981,8 +956,7 @@ static int compat_drm_update_draw(struct file *file, unsigned int cmd,
            __put_user(update32.data, &request->data))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_UPDATE_DRAW, (unsigned long)request);
+       err = drm_ioctl(file, DRM_IOCTL_UPDATE_DRAW, (unsigned long)request);
        return err;
 }
 #endif
@@ -1023,8 +997,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
            || __put_user(req32.request.signal, &request->request.signal))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_WAIT_VBLANK, (unsigned long)request);
+       err = drm_ioctl(file, DRM_IOCTL_WAIT_VBLANK, (unsigned long)request);
        if (err)
                return err;
 
@@ -1094,16 +1067,14 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
         * than always failing.
         */
        if (nr >= ARRAY_SIZE(drm_compat_ioctls))
-               return drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+               return drm_ioctl(filp, cmd, arg);
 
        fn = drm_compat_ioctls[nr];
 
-       lock_kernel();          /* XXX for now */
        if (fn != NULL)
                ret = (*fn) (filp, cmd, arg);
        else
-               ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
-       unlock_kernel();
+               ret = drm_ioctl(filp, cmd, arg);
 
        return ret;
 }
index d7d7eac..cdec329 100644 (file)
@@ -358,7 +358,7 @@ struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm,
                if (entry->size >= size + wasted) {
                        if (!best_match)
                                return entry;
-                       if (size < best_size) {
+                       if (entry->size < best_size) {
                                best = entry;
                                best_size = entry->size;
                        }
@@ -408,7 +408,7 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm,
                if (entry->size >= size + wasted) {
                        if (!best_match)
                                return entry;
-                       if (size < best_size) {
+                       if (entry->size < best_size) {
                                best = entry;
                                best_size = entry->size;
                        }
index 9422a74..81681a0 100644 (file)
@@ -408,6 +408,11 @@ static int ch7006_probe(struct i2c_client *client, const struct i2c_device_id *i
 
        ch7006_info(client, "Detected version ID: %x\n", val);
 
+       /* I don't know what this is for, but otherwise I get no
+        * signal.
+        */
+       ch7006_write(client, 0x3d, 0x0);
+
        return 0;
 
 fail:
index 87f5445..e447dfb 100644 (file)
@@ -427,11 +427,6 @@ void ch7006_state_load(struct i2c_client *client,
        ch7006_load_reg(client, state, CH7006_SUBC_INC7);
        ch7006_load_reg(client, state, CH7006_PLL_CONTROL);
        ch7006_load_reg(client, state, CH7006_CALC_SUBC_INC0);
-
-       /* I don't know what this is for, but otherwise I get no
-        * signal.
-        */
-       ch7006_write(client, 0x3d, 0x0);
 }
 
 void ch7006_state_save(struct i2c_client *client,
index 7d1d88c..de32d22 100644 (file)
@@ -115,7 +115,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
 static const struct file_operations i810_buffer_fops = {
        .open = drm_open,
        .release = drm_release,
-       .ioctl = drm_ioctl,
+       .unlocked_ioctl = drm_ioctl,
        .mmap = i810_mmap_buffers,
        .fasync = drm_fasync,
 };
index fabb9a8..c1e0275 100644 (file)
@@ -59,7 +59,7 @@ static struct drm_driver driver = {
                 .owner = THIS_MODULE,
                 .open = drm_open,
                 .release = drm_release,
-                .ioctl = drm_ioctl,
+                .unlocked_ioctl = drm_ioctl,
                 .mmap = drm_mmap,
                 .poll = drm_poll,
                 .fasync = drm_fasync,
index 877bf6c..06bd732 100644 (file)
@@ -117,7 +117,7 @@ static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
 static const struct file_operations i830_buffer_fops = {
        .open = drm_open,
        .release = drm_release,
-       .ioctl = drm_ioctl,
+       .unlocked_ioctl = drm_ioctl,
        .mmap = i830_mmap_buffers,
        .fasync = drm_fasync,
 };
index 389597e..44f990b 100644 (file)
@@ -70,7 +70,7 @@ static struct drm_driver driver = {
                 .owner = THIS_MODULE,
                 .open = drm_open,
                 .release = drm_release,
-                .ioctl = drm_ioctl,
+                .unlocked_ioctl = drm_ioctl,
                 .mmap = drm_mmap,
                 .poll = drm_poll,
                 .fasync = drm_fasync,
index 2fa2178..24286ca 100644 (file)
@@ -329,7 +329,7 @@ static struct drm_driver driver = {
                 .owner = THIS_MODULE,
                 .open = drm_open,
                 .release = drm_release,
-                .ioctl = drm_ioctl,
+                .unlocked_ioctl = drm_ioctl,
                 .mmap = drm_gem_mmap,
                 .poll = drm_poll,
                 .fasync = drm_fasync,
index 1fe68a2..13b0289 100644 (file)
@@ -66,8 +66,7 @@ static int compat_i915_batchbuffer(struct file *file, unsigned int cmd,
                          &batchbuffer->cliprects))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_I915_BATCHBUFFER,
+       return drm_ioctl(file, DRM_IOCTL_I915_BATCHBUFFER,
                         (unsigned long)batchbuffer);
 }
 
@@ -102,8 +101,8 @@ static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd,
                          &cmdbuffer->cliprects))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_I915_CMDBUFFER, (unsigned long)cmdbuffer);
+       return drm_ioctl(file, DRM_IOCTL_I915_CMDBUFFER,
+                        (unsigned long)cmdbuffer);
 }
 
 typedef struct drm_i915_irq_emit32 {
@@ -125,8 +124,8 @@ static int compat_i915_irq_emit(struct file *file, unsigned int cmd,
                          &request->irq_seq))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_I915_IRQ_EMIT, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_I915_IRQ_EMIT,
+                        (unsigned long)request);
 }
 typedef struct drm_i915_getparam32 {
        int param;
@@ -149,8 +148,8 @@ static int compat_i915_getparam(struct file *file, unsigned int cmd,
                          &request->value))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_I915_GETPARAM, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_I915_GETPARAM,
+                        (unsigned long)request);
 }
 
 typedef struct drm_i915_mem_alloc32 {
@@ -178,8 +177,8 @@ static int compat_i915_alloc(struct file *file, unsigned int cmd,
                          &request->region_offset))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_I915_ALLOC, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_I915_ALLOC,
+                        (unsigned long)request);
 }
 
 drm_ioctl_compat_t *i915_compat_ioctls[] = {
@@ -211,12 +210,10 @@ long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(i915_compat_ioctls))
                fn = i915_compat_ioctls[nr - DRM_COMMAND_BASE];
 
-       lock_kernel();          /* XXX for now */
        if (fn != NULL)
                ret = (*fn) (filp, cmd, arg);
        else
-               ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
-       unlock_kernel();
+               ret = drm_ioctl(filp, cmd, arg);
 
        return ret;
 }
index 97ee566..ddfe161 100644 (file)
@@ -68,7 +68,7 @@ static struct drm_driver driver = {
                .owner = THIS_MODULE,
                .open = drm_open,
                .release = drm_release,
-               .ioctl = drm_ioctl,
+               .unlocked_ioctl = drm_ioctl,
                .mmap = drm_mmap,
                .poll = drm_poll,
                .fasync = drm_fasync,
index 30d0047..c1f877b 100644 (file)
@@ -100,8 +100,7 @@ static int compat_mga_init(struct file *file, unsigned int cmd,
        if (err)
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_MGA_INIT, (unsigned long)init);
+       return drm_ioctl(file, DRM_IOCTL_MGA_INIT, (unsigned long)init);
 }
 
 typedef struct drm_mga_getparam32 {
@@ -125,8 +124,7 @@ static int compat_mga_getparam(struct file *file, unsigned int cmd,
                          &getparam->value))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
+       return drm_ioctl(file, DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
 }
 
 typedef struct drm_mga_drm_bootstrap32 {
@@ -166,8 +164,7 @@ static int compat_mga_dma_bootstrap(struct file *file, unsigned int cmd,
            || __put_user(dma_bootstrap32.agp_size, &dma_bootstrap->agp_size))
                return -EFAULT;
 
-       err = drm_ioctl(file->f_path.dentry->d_inode, file,
-                       DRM_IOCTL_MGA_DMA_BOOTSTRAP,
+       err = drm_ioctl(file, DRM_IOCTL_MGA_DMA_BOOTSTRAP,
                        (unsigned long)dma_bootstrap);
        if (err)
                return err;
@@ -220,12 +217,10 @@ long mga_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(mga_compat_ioctls))
                fn = mga_compat_ioctls[nr - DRM_COMMAND_BASE];
 
-       lock_kernel();          /* XXX for now */
        if (fn != NULL)
                ret = (*fn) (filp, cmd, arg);
        else
-               ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
-       unlock_kernel();
+               ret = drm_ioctl(filp, cmd, arg);
 
        return ret;
 }
index 1d90d4d..48c290b 100644 (file)
@@ -8,14 +8,15 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
              nouveau_sgdma.o nouveau_dma.o \
              nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
              nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
-            nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
-            nouveau_dp.o \
+             nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
+             nouveau_dp.o nouveau_grctx.o \
              nv04_timer.o \
              nv04_mc.o nv40_mc.o nv50_mc.o \
              nv04_fb.o nv10_fb.o nv40_fb.o \
              nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
              nv04_graph.o nv10_graph.o nv20_graph.o \
              nv40_graph.o nv50_graph.o \
+             nv40_grctx.o \
              nv04_instmem.o nv50_instmem.o \
              nv50_crtc.o nv50_dac.o nv50_sor.o \
              nv50_cursor.o nv50_display.o nv50_fbcon.o \
index 5eec5ed..ba14397 100644 (file)
@@ -181,43 +181,42 @@ struct methods {
        const char desc[8];
        void (*loadbios)(struct drm_device *, uint8_t *);
        const bool rw;
-       int score;
 };
 
 static struct methods nv04_methods[] = {
        { "PROM", load_vbios_prom, false },
        { "PRAMIN", load_vbios_pramin, true },
        { "PCIROM", load_vbios_pci, true },
-       { }
 };
 
 static struct methods nv50_methods[] = {
        { "PRAMIN", load_vbios_pramin, true },
        { "PROM", load_vbios_prom, false },
        { "PCIROM", load_vbios_pci, true },
-       { }
 };
 
+#define METHODCNT 3
+
 static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct methods *methods, *method;
+       struct methods *methods;
+       int i;
        int testscore = 3;
+       int scores[METHODCNT];
 
        if (nouveau_vbios) {
-               method = nv04_methods;
-               while (method->loadbios) {
-                       if (!strcasecmp(nouveau_vbios, method->desc))
+               methods = nv04_methods;
+               for (i = 0; i < METHODCNT; i++)
+                       if (!strcasecmp(nouveau_vbios, methods[i].desc))
                                break;
-                       method++;
-               }
 
-               if (method->loadbios) {
+               if (i < METHODCNT) {
                        NV_INFO(dev, "Attempting to use BIOS image from %s\n",
-                               method->desc);
+                               methods[i].desc);
 
-                       method->loadbios(dev, data);
-                       if (score_vbios(dev, data, method->rw))
+                       methods[i].loadbios(dev, data);
+                       if (score_vbios(dev, data, methods[i].rw))
                                return true;
                }
 
@@ -229,28 +228,24 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
        else
                methods = nv50_methods;
 
-       method = methods;
-       while (method->loadbios) {
+       for (i = 0; i < METHODCNT; i++) {
                NV_TRACE(dev, "Attempting to load BIOS image from %s\n",
-                        method->desc);
+                        methods[i].desc);
                data[0] = data[1] = 0;  /* avoid reuse of previous image */
-               method->loadbios(dev, data);
-               method->score = score_vbios(dev, data, method->rw);
-               if (method->score == testscore)
+               methods[i].loadbios(dev, data);
+               scores[i] = score_vbios(dev, data, methods[i].rw);
+               if (scores[i] == testscore)
                        return true;
-               method++;
        }
 
        while (--testscore > 0) {
-               method = methods;
-               while (method->loadbios) {
-                       if (method->score == testscore) {
+               for (i = 0; i < METHODCNT; i++) {
+                       if (scores[i] == testscore) {
                                NV_TRACE(dev, "Using BIOS image from %s\n",
-                                        method->desc);
-                               method->loadbios(dev, data);
+                                        methods[i].desc);
+                               methods[i].loadbios(dev, data);
                                return true;
                        }
-                       method++;
                }
        }
 
@@ -261,10 +256,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
 struct init_tbl_entry {
        char *name;
        uint8_t id;
-       int length;
-       int length_offset;
-       int length_multiplier;
-       bool (*handler)(struct nvbios *, uint16_t, struct init_exec *);
+       int (*handler)(struct nvbios *, uint16_t, struct init_exec *);
 };
 
 struct bit_entry {
@@ -820,7 +812,7 @@ static uint32_t get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
        }
 }
 
-static bool
+static int
 init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
                      struct init_exec *iexec)
 {
@@ -852,9 +844,10 @@ init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
        uint32_t reg = ROM32(bios->data[offset + 7]);
        uint8_t config;
        uint32_t configval;
+       int len = 11 + count * 4;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
                      "Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
@@ -865,7 +858,7 @@ init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
                NV_ERROR(bios->dev,
                         "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
                         offset, config, count);
-               return false;
+               return 0;
        }
 
        configval = ROM32(bios->data[offset + 11 + config * 4]);
@@ -874,10 +867,10 @@ init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
 
        bios_wr32(bios, reg, configval);
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -912,10 +905,10 @@ init_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        iexec->repeat = false;
 
-       return true;
+       return 2;
 }
 
-static bool
+static int
 init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
                     struct init_exec *iexec)
 {
@@ -951,9 +944,10 @@ init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
        uint32_t reg = ROM32(bios->data[offset + 8]);
        uint8_t config;
        uint16_t freq;
+       int len = 12 + count * 2;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
                      "Shift: 0x%02X, IO Flag Condition: 0x%02X, "
@@ -966,7 +960,7 @@ init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
                NV_ERROR(bios->dev,
                         "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
                         offset, config, count);
-               return false;
+               return 0;
        }
 
        freq = ROM16(bios->data[offset + 12 + config * 2]);
@@ -986,10 +980,10 @@ init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
 
        setPLL(bios, reg, freq * 10);
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_end_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1007,12 +1001,12 @@ init_end_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         * we're not in repeat mode
         */
        if (iexec->repeat)
-               return false;
+               return 0;
 
-       return true;
+       return 1;
 }
 
-static bool
+static int
 init_copy(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1041,7 +1035,7 @@ init_copy(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t crtcdata;
 
        if (!iexec->execute)
-               return true;
+               return 11;
 
        BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Shift: 0x%02X, SrcMask: 0x%02X, "
                      "Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X\n",
@@ -1060,10 +1054,10 @@ init_copy(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        crtcdata |= (uint8_t)data;
        bios_idxprt_wr(bios, crtcport, crtcindex, crtcdata);
 
-       return true;
+       return 11;
 }
 
-static bool
+static int
 init_not(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1079,10 +1073,10 @@ init_not(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                BIOSLOG(bios, "0x%04X: ------ Executing following commands ------\n", offset);
 
        iexec->execute = !iexec->execute;
-       return true;
+       return 1;
 }
 
-static bool
+static int
 init_io_flag_condition(struct nvbios *bios, uint16_t offset,
                       struct init_exec *iexec)
 {
@@ -1100,7 +1094,7 @@ init_io_flag_condition(struct nvbios *bios, uint16_t offset,
        uint8_t cond = bios->data[offset + 1];
 
        if (!iexec->execute)
-               return true;
+               return 2;
 
        if (io_flag_condition_met(bios, offset, cond))
                BIOSLOG(bios, "0x%04X: Condition fulfilled -- continuing to execute\n", offset);
@@ -1109,10 +1103,10 @@ init_io_flag_condition(struct nvbios *bios, uint16_t offset,
                iexec->execute = false;
        }
 
-       return true;
+       return 2;
 }
 
-static bool
+static int
 init_idx_addr_latched(struct nvbios *bios, uint16_t offset,
                      struct init_exec *iexec)
 {
@@ -1140,11 +1134,12 @@ init_idx_addr_latched(struct nvbios *bios, uint16_t offset,
        uint32_t mask = ROM32(bios->data[offset + 9]);
        uint32_t data = ROM32(bios->data[offset + 13]);
        uint8_t count = bios->data[offset + 17];
+       int len = 18 + count * 2;
        uint32_t value;
        int i;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        BIOSLOG(bios, "0x%04X: ControlReg: 0x%08X, DataReg: 0x%08X, "
                      "Mask: 0x%08X, Data: 0x%08X, Count: 0x%02X\n",
@@ -1164,10 +1159,10 @@ init_idx_addr_latched(struct nvbios *bios, uint16_t offset,
                bios_wr32(bios, controlreg, value);
        }
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_io_restrict_pll2(struct nvbios *bios, uint16_t offset,
                      struct init_exec *iexec)
 {
@@ -1196,25 +1191,26 @@ init_io_restrict_pll2(struct nvbios *bios, uint16_t offset,
        uint8_t shift = bios->data[offset + 5];
        uint8_t count = bios->data[offset + 6];
        uint32_t reg = ROM32(bios->data[offset + 7]);
+       int len = 11 + count * 4;
        uint8_t config;
        uint32_t freq;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
                      "Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
                offset, crtcport, crtcindex, mask, shift, count, reg);
 
        if (!reg)
-               return true;
+               return len;
 
        config = (bios_idxprt_rd(bios, crtcport, crtcindex) & mask) >> shift;
        if (config > count) {
                NV_ERROR(bios->dev,
                         "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
                         offset, config, count);
-               return false;
+               return 0;
        }
 
        freq = ROM32(bios->data[offset + 11 + config * 4]);
@@ -1224,10 +1220,10 @@ init_io_restrict_pll2(struct nvbios *bios, uint16_t offset,
 
        setPLL(bios, reg, freq);
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_pll2(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1244,16 +1240,16 @@ init_pll2(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint32_t freq = ROM32(bios->data[offset + 5]);
 
        if (!iexec->execute)
-               return true;
+               return 9;
 
        BIOSLOG(bios, "0x%04X: Reg: 0x%04X, Freq: %dkHz\n",
                offset, reg, freq);
 
        setPLL(bios, reg, freq);
-       return true;
+       return 9;
 }
 
-static bool
+static int
 init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1277,12 +1273,13 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t i2c_index = bios->data[offset + 1];
        uint8_t i2c_address = bios->data[offset + 2];
        uint8_t count = bios->data[offset + 3];
+       int len = 4 + count * 3;
        struct nouveau_i2c_chan *chan;
        struct i2c_msg msg;
        int i;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X, "
                      "Count: 0x%02X\n",
@@ -1290,7 +1287,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        chan = init_i2c_device_find(bios->dev, i2c_index);
        if (!chan)
-               return false;
+               return 0;
 
        for (i = 0; i < count; i++) {
                uint8_t i2c_reg = bios->data[offset + 4 + i * 3];
@@ -1303,7 +1300,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                msg.len = 1;
                msg.buf = &value;
                if (i2c_transfer(&chan->adapter, &msg, 1) != 1)
-                       return false;
+                       return 0;
 
                BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
                              "Mask: 0x%02X, Data: 0x%02X\n",
@@ -1317,14 +1314,14 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                        msg.len = 1;
                        msg.buf = &value;
                        if (i2c_transfer(&chan->adapter, &msg, 1) != 1)
-                               return false;
+                               return 0;
                }
        }
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1346,12 +1343,13 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t i2c_index = bios->data[offset + 1];
        uint8_t i2c_address = bios->data[offset + 2];
        uint8_t count = bios->data[offset + 3];
+       int len = 4 + count * 2;
        struct nouveau_i2c_chan *chan;
        struct i2c_msg msg;
        int i;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X, "
                      "Count: 0x%02X\n",
@@ -1359,7 +1357,7 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        chan = init_i2c_device_find(bios->dev, i2c_index);
        if (!chan)
-               return false;
+               return 0;
 
        for (i = 0; i < count; i++) {
                uint8_t i2c_reg = bios->data[offset + 4 + i * 2];
@@ -1374,14 +1372,14 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                        msg.len = 1;
                        msg.buf = &data;
                        if (i2c_transfer(&chan->adapter, &msg, 1) != 1)
-                               return false;
+                               return 0;
                }
        }
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1401,13 +1399,14 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t i2c_index = bios->data[offset + 1];
        uint8_t i2c_address = bios->data[offset + 2];
        uint8_t count = bios->data[offset + 3];
+       int len = 4 + count;
        struct nouveau_i2c_chan *chan;
        struct i2c_msg msg;
        uint8_t data[256];
        int i;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X, "
                      "Count: 0x%02X\n",
@@ -1415,7 +1414,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        chan = init_i2c_device_find(bios->dev, i2c_index);
        if (!chan)
-               return false;
+               return 0;
 
        for (i = 0; i < count; i++) {
                data[i] = bios->data[offset + 4 + i];
@@ -1429,13 +1428,13 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                msg.len = count;
                msg.buf = data;
                if (i2c_transfer(&chan->adapter, &msg, 1) != 1)
-                       return false;
+                       return 0;
        }
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1460,7 +1459,7 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint32_t reg, value;
 
        if (!iexec->execute)
-               return true;
+               return 5;
 
        BIOSLOG(bios, "0x%04X: MagicLookupValue: 0x%02X, TMDSAddr: 0x%02X, "
                      "Mask: 0x%02X, Data: 0x%02X\n",
@@ -1468,7 +1467,7 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        reg = get_tmds_index_reg(bios->dev, mlv);
        if (!reg)
-               return false;
+               return 0;
 
        bios_wr32(bios, reg,
                  tmdsaddr | NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE);
@@ -1476,10 +1475,10 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        bios_wr32(bios, reg + 4, value);
        bios_wr32(bios, reg, tmdsaddr);
 
-       return true;
+       return 5;
 }
 
-static bool
+static int
 init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
                   struct init_exec *iexec)
 {
@@ -1500,18 +1499,19 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
 
        uint8_t mlv = bios->data[offset + 1];
        uint8_t count = bios->data[offset + 2];
+       int len = 3 + count * 2;
        uint32_t reg;
        int i;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        BIOSLOG(bios, "0x%04X: MagicLookupValue: 0x%02X, Count: 0x%02X\n",
                offset, mlv, count);
 
        reg = get_tmds_index_reg(bios->dev, mlv);
        if (!reg)
-               return false;
+               return 0;
 
        for (i = 0; i < count; i++) {
                uint8_t tmdsaddr = bios->data[offset + 3 + i * 2];
@@ -1521,10 +1521,10 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset,
                bios_wr32(bios, reg, tmdsaddr);
        }
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_cr_idx_adr_latch(struct nvbios *bios, uint16_t offset,
                      struct init_exec *iexec)
 {
@@ -1547,11 +1547,12 @@ init_cr_idx_adr_latch(struct nvbios *bios, uint16_t offset,
        uint8_t crtcindex2 = bios->data[offset + 2];
        uint8_t baseaddr = bios->data[offset + 3];
        uint8_t count = bios->data[offset + 4];
+       int len = 5 + count;
        uint8_t oldaddr, data;
        int i;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        BIOSLOG(bios, "0x%04X: Index1: 0x%02X, Index2: 0x%02X, "
                      "BaseAddr: 0x%02X, Count: 0x%02X\n",
@@ -1568,10 +1569,10 @@ init_cr_idx_adr_latch(struct nvbios *bios, uint16_t offset,
 
        bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, crtcindex1, oldaddr);
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1592,7 +1593,7 @@ init_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t value;
 
        if (!iexec->execute)
-               return true;
+               return 4;
 
        BIOSLOG(bios, "0x%04X: Index: 0x%02X, Mask: 0x%02X, Data: 0x%02X\n",
                offset, crtcindex, mask, data);
@@ -1601,10 +1602,10 @@ init_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        value |= data;
        bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, crtcindex, value);
 
-       return true;
+       return 4;
 }
 
-static bool
+static int
 init_zm_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1621,14 +1622,14 @@ init_zm_cr(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t data = bios->data[offset + 2];
 
        if (!iexec->execute)
-               return true;
+               return 3;
 
        bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, crtcindex, data);
 
-       return true;
+       return 3;
 }
 
-static bool
+static int
 init_zm_cr_group(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1645,18 +1646,19 @@ init_zm_cr_group(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         */
 
        uint8_t count = bios->data[offset + 1];
+       int len = 2 + count * 2;
        int i;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        for (i = 0; i < count; i++)
                init_zm_cr(bios, offset + 2 + 2 * i - 1, iexec);
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_condition_time(struct nvbios *bios, uint16_t offset,
                    struct init_exec *iexec)
 {
@@ -1680,7 +1682,7 @@ init_condition_time(struct nvbios *bios, uint16_t offset,
        unsigned cnt;
 
        if (!iexec->execute)
-               return true;
+               return 3;
 
        if (retries > 100)
                retries = 100;
@@ -1711,10 +1713,10 @@ init_condition_time(struct nvbios *bios, uint16_t offset,
                iexec->execute = false;
        }
 
-       return true;
+       return 3;
 }
 
-static bool
+static int
 init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
                     struct init_exec *iexec)
 {
@@ -1734,10 +1736,11 @@ init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
 
        uint32_t basereg = ROM32(bios->data[offset + 1]);
        uint32_t count = bios->data[offset + 5];
+       int len = 6 + count * 4;
        int i;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        BIOSLOG(bios, "0x%04X: BaseReg: 0x%08X, Count: 0x%02X\n",
                offset, basereg, count);
@@ -1749,10 +1752,10 @@ init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
                bios_wr32(bios, reg, data);
        }
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1768,7 +1771,7 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint16_t sub_offset = ROM16(bios->data[offset + 1]);
 
        if (!iexec->execute)
-               return true;
+               return 3;
 
        BIOSLOG(bios, "0x%04X: Executing subroutine at 0x%04X\n",
                offset, sub_offset);
@@ -1777,10 +1780,10 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        BIOSLOG(bios, "0x%04X: End of 0x%04X subroutine\n", offset, sub_offset);
 
-       return true;
+       return 3;
 }
 
-static bool
+static int
 init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1808,7 +1811,7 @@ init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint32_t srcvalue, dstvalue;
 
        if (!iexec->execute)
-               return true;
+               return 22;
 
        BIOSLOG(bios, "0x%04X: SrcReg: 0x%08X, Shift: 0x%02X, SrcMask: 0x%08X, "
                      "Xor: 0x%08X, DstReg: 0x%08X, DstMask: 0x%08X\n",
@@ -1827,10 +1830,10 @@ init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        bios_wr32(bios, dstreg, dstvalue | srcvalue);
 
-       return true;
+       return 22;
 }
 
-static bool
+static int
 init_zm_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1848,14 +1851,14 @@ init_zm_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t data = bios->data[offset + 4];
 
        if (!iexec->execute)
-               return true;
+               return 5;
 
        bios_idxprt_wr(bios, crtcport, crtcindex, data);
 
-       return true;
+       return 5;
 }
 
-static bool
+static int
 init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1904,7 +1907,7 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
 
        if (dev_priv->card_type >= NV_50)
-               return true;
+               return 1;
 
        /*
         * On every card I've seen, this step gets done for us earlier in
@@ -1922,10 +1925,10 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        /* write back the saved configuration value */
        bios_wr32(bios, NV_PFB_CFG0, bios->state.saved_nv_pfb_cfg0);
 
-       return true;
+       return 1;
 }
 
-static bool
+static int
 init_reset(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -1959,10 +1962,10 @@ init_reset(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        pci_nv_20 &= ~NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED;     /* 0xfffffffe */
        bios_wr32(bios, NV_PBUS_PCI_NV_20, pci_nv_20);
 
-       return true;
+       return 13;
 }
 
-static bool
+static int
 init_configure_mem(struct nvbios *bios, uint16_t offset,
                   struct init_exec *iexec)
 {
@@ -1983,7 +1986,7 @@ init_configure_mem(struct nvbios *bios, uint16_t offset,
        uint32_t reg, data;
 
        if (bios->major_version > 2)
-               return false;
+               return 0;
 
        bios_idxprt_wr(bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX, bios_idxprt_rd(
                       bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX) | 0x20);
@@ -2015,10 +2018,10 @@ init_configure_mem(struct nvbios *bios, uint16_t offset,
                bios_wr32(bios, reg, data);
        }
 
-       return true;
+       return 1;
 }
 
-static bool
+static int
 init_configure_clk(struct nvbios *bios, uint16_t offset,
                   struct init_exec *iexec)
 {
@@ -2038,7 +2041,7 @@ init_configure_clk(struct nvbios *bios, uint16_t offset,
        int clock;
 
        if (bios->major_version > 2)
-               return false;
+               return 0;
 
        clock = ROM16(bios->data[meminitoffs + 4]) * 10;
        setPLL(bios, NV_PRAMDAC_NVPLL_COEFF, clock);
@@ -2048,10 +2051,10 @@ init_configure_clk(struct nvbios *bios, uint16_t offset,
                clock *= 2;
        setPLL(bios, NV_PRAMDAC_MPLL_COEFF, clock);
 
-       return true;
+       return 1;
 }
 
-static bool
+static int
 init_configure_preinit(struct nvbios *bios, uint16_t offset,
                       struct init_exec *iexec)
 {
@@ -2071,15 +2074,15 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset,
        uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6));
 
        if (bios->major_version > 2)
-               return false;
+               return 0;
 
        bios_idxprt_wr(bios, NV_CIO_CRX__COLOR,
                             NV_CIO_CRE_SCRATCH4__INDEX, cr3c);
 
-       return true;
+       return 1;
 }
 
-static bool
+static int
 init_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2099,7 +2102,7 @@ init_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t data = bios->data[offset + 4];
 
        if (!iexec->execute)
-               return true;
+               return 5;
 
        BIOSLOG(bios, "0x%04X: Port: 0x%04X, Mask: 0x%02X, Data: 0x%02X\n",
                offset, crtcport, mask, data);
@@ -2158,15 +2161,15 @@ init_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                for (i = 0; i < 2; i++)
                        bios_wr32(bios, 0x614108 + (i*0x800), bios_rd32(
                                  bios, 0x614108 + (i*0x800)) & 0x0fffffff);
-               return true;
+               return 5;
        }
 
        bios_port_wr(bios, crtcport, (bios_port_rd(bios, crtcport) & mask) |
                                                                        data);
-       return true;
+       return 5;
 }
 
-static bool
+static int
 init_sub(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2181,7 +2184,7 @@ init_sub(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t sub = bios->data[offset + 1];
 
        if (!iexec->execute)
-               return true;
+               return 2;
 
        BIOSLOG(bios, "0x%04X: Calling script %d\n", offset, sub);
 
@@ -2191,10 +2194,10 @@ init_sub(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 
        BIOSLOG(bios, "0x%04X: End of script %d\n", offset, sub);
 
-       return true;
+       return 2;
 }
 
-static bool
+static int
 init_ram_condition(struct nvbios *bios, uint16_t offset,
                   struct init_exec *iexec)
 {
@@ -2215,7 +2218,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset,
        uint8_t data;
 
        if (!iexec->execute)
-               return true;
+               return 3;
 
        data = bios_rd32(bios, NV_PFB_BOOT_0) & mask;
 
@@ -2229,10 +2232,10 @@ init_ram_condition(struct nvbios *bios, uint16_t offset,
                iexec->execute = false;
        }
 
-       return true;
+       return 3;
 }
 
-static bool
+static int
 init_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2251,17 +2254,17 @@ init_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint32_t data = ROM32(bios->data[offset + 9]);
 
        if (!iexec->execute)
-               return true;
+               return 13;
 
        BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Mask: 0x%08X, Data: 0x%08X\n",
                offset, reg, mask, data);
 
        bios_wr32(bios, reg, (bios_rd32(bios, reg) & mask) | data);
 
-       return true;
+       return 13;
 }
 
-static bool
+static int
 init_macro(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2285,7 +2288,7 @@ init_macro(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        int i;
 
        if (!iexec->execute)
-               return true;
+               return 2;
 
        BIOSLOG(bios, "0x%04X: Macro: 0x%02X, MacroTableIndex: 0x%02X, "
                      "Count: 0x%02X\n",
@@ -2300,10 +2303,10 @@ init_macro(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                bios_wr32(bios, reg, data);
        }
 
-       return true;
+       return 2;
 }
 
-static bool
+static int
 init_done(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2315,10 +2318,10 @@ init_done(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         */
 
        /* mild retval abuse to stop parsing this table */
-       return false;
+       return 0;
 }
 
-static bool
+static int
 init_resume(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2330,15 +2333,15 @@ init_resume(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         */
 
        if (iexec->execute)
-               return true;
+               return 1;
 
        iexec->execute = true;
        BIOSLOG(bios, "0x%04X: ---- Executing following commands ----\n", offset);
 
-       return true;
+       return 1;
 }
 
-static bool
+static int
 init_time(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2353,7 +2356,7 @@ init_time(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        unsigned time = ROM16(bios->data[offset + 1]);
 
        if (!iexec->execute)
-               return true;
+               return 3;
 
        BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X microseconds\n",
                offset, time);
@@ -2363,10 +2366,10 @@ init_time(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        else
                msleep((time + 900) / 1000);
 
-       return true;
+       return 3;
 }
 
-static bool
+static int
 init_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2383,7 +2386,7 @@ init_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t cond = bios->data[offset + 1];
 
        if (!iexec->execute)
-               return true;
+               return 2;
 
        BIOSLOG(bios, "0x%04X: Condition: 0x%02X\n", offset, cond);
 
@@ -2394,10 +2397,10 @@ init_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                iexec->execute = false;
        }
 
-       return true;
+       return 2;
 }
 
-static bool
+static int
 init_io_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2414,7 +2417,7 @@ init_io_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t cond = bios->data[offset + 1];
 
        if (!iexec->execute)
-               return true;
+               return 2;
 
        BIOSLOG(bios, "0x%04X: IO condition: 0x%02X\n", offset, cond);
 
@@ -2425,10 +2428,10 @@ init_io_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                iexec->execute = false;
        }
 
-       return true;
+       return 2;
 }
 
-static bool
+static int
 init_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2451,7 +2454,7 @@ init_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint8_t value;
 
        if (!iexec->execute)
-               return true;
+               return 6;
 
        BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
                      "Data: 0x%02X\n",
@@ -2460,10 +2463,10 @@ init_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        value = (bios_idxprt_rd(bios, crtcport, crtcindex) & mask) | data;
        bios_idxprt_wr(bios, crtcport, crtcindex, value);
 
-       return true;
+       return 6;
 }
 
-static bool
+static int
 init_pll(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2481,16 +2484,16 @@ init_pll(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint16_t freq = ROM16(bios->data[offset + 5]);
 
        if (!iexec->execute)
-               return true;
+               return 7;
 
        BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Freq: %d0kHz\n", offset, reg, freq);
 
        setPLL(bios, reg, freq * 10);
 
-       return true;
+       return 7;
 }
 
-static bool
+static int
 init_zm_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2507,17 +2510,17 @@ init_zm_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint32_t value = ROM32(bios->data[offset + 5]);
 
        if (!iexec->execute)
-               return true;
+               return 9;
 
        if (reg == 0x000200)
                value |= 1;
 
        bios_wr32(bios, reg, value);
 
-       return true;
+       return 9;
 }
 
-static bool
+static int
 init_ram_restrict_pll(struct nvbios *bios, uint16_t offset,
                      struct init_exec *iexec)
 {
@@ -2543,14 +2546,15 @@ init_ram_restrict_pll(struct nvbios *bios, uint16_t offset,
        uint8_t type = bios->data[offset + 1];
        uint32_t freq = ROM32(bios->data[offset + 2 + (index * 4)]);
        uint8_t *pll_limits = &bios->data[bios->pll_limit_tbl_ptr], *entry;
+       int len = 2 + bios->ram_restrict_group_count * 4;
        int i;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        if (!bios->pll_limit_tbl_ptr || (pll_limits[0] & 0xf0) != 0x30) {
                NV_ERROR(dev, "PLL limits table not version 3.x\n");
-               return true; /* deliberate, allow default clocks to remain */
+               return len; /* deliberate, allow default clocks to remain */
        }
 
        entry = pll_limits + pll_limits[1];
@@ -2563,15 +2567,15 @@ init_ram_restrict_pll(struct nvbios *bios, uint16_t offset,
                                offset, type, reg, freq);
 
                        setPLL(bios, reg, freq);
-                       return true;
+                       return len;
                }
        }
 
        NV_ERROR(dev, "PLL type 0x%02x not found in PLL limits table", type);
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_8c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2581,10 +2585,10 @@ init_8c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         *
         */
 
-       return true;
+       return 1;
 }
 
-static bool
+static int
 init_8d(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2594,10 +2598,10 @@ init_8d(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         *
         */
 
-       return true;
+       return 1;
 }
 
-static bool
+static int
 init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2615,14 +2619,17 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        const uint8_t *gpio_entry;
        int i;
 
+       if (!iexec->execute)
+               return 1;
+
        if (bios->bdcb.version != 0x40) {
                NV_ERROR(bios->dev, "DCB table not version 4.0\n");
-               return false;
+               return 0;
        }
 
        if (!bios->bdcb.gpio_table_ptr) {
                NV_WARN(bios->dev, "Invalid pointer to INIT_8E table\n");
-               return false;
+               return 0;
        }
 
        gpio_entry = gpio_table + gpio_table[1];
@@ -2660,13 +2667,10 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                bios_wr32(bios, r, v);
        }
 
-       return true;
+       return 1;
 }
 
-/* hack to avoid moving the itbl_entry array before this function */
-int init_ram_restrict_zm_reg_group_blocklen;
-
-static bool
+static int
 init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset,
                               struct init_exec *iexec)
 {
@@ -2692,21 +2696,21 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset,
        uint8_t regincrement = bios->data[offset + 5];
        uint8_t count = bios->data[offset + 6];
        uint32_t strap_ramcfg, data;
-       uint16_t blocklen;
+       /* previously set by 'M' BIT table */
+       uint16_t blocklen = bios->ram_restrict_group_count * 4;
+       int len = 7 + count * blocklen;
        uint8_t index;
        int i;
 
-       /* previously set by 'M' BIT table */
-       blocklen = init_ram_restrict_zm_reg_group_blocklen;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        if (!blocklen) {
                NV_ERROR(bios->dev,
                         "0x%04X: Zero block length - has the M table "
                         "been parsed?\n", offset);
-               return false;
+               return 0;
        }
 
        strap_ramcfg = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) >> 2) & 0xf;
@@ -2724,10 +2728,10 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset,
                reg += regincrement;
        }
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_copy_zm_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2744,14 +2748,14 @@ init_copy_zm_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        uint32_t dstreg = ROM32(bios->data[offset + 5]);
 
        if (!iexec->execute)
-               return true;
+               return 9;
 
        bios_wr32(bios, dstreg, bios_rd32(bios, srcreg));
 
-       return true;
+       return 9;
 }
 
-static bool
+static int
 init_zm_reg_group_addr_latched(struct nvbios *bios, uint16_t offset,
                               struct init_exec *iexec)
 {
@@ -2769,20 +2773,21 @@ init_zm_reg_group_addr_latched(struct nvbios *bios, uint16_t offset,
 
        uint32_t reg = ROM32(bios->data[offset + 1]);
        uint8_t count = bios->data[offset + 5];
+       int len = 6 + count * 4;
        int i;
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        for (i = 0; i < count; i++) {
                uint32_t data = ROM32(bios->data[offset + 6 + 4 * i]);
                bios_wr32(bios, reg, data);
        }
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_reserved(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2793,10 +2798,10 @@ init_reserved(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         * Seemingly does nothing
         */
 
-       return true;
+       return 1;
 }
 
-static bool
+static int
 init_96(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2829,13 +2834,13 @@ init_96(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        val <<= bios->data[offset + 16];
 
        if (!iexec->execute)
-               return true;
+               return 17;
 
        bios_wr32(bios, reg, (bios_rd32(bios, reg) & mask) | val);
-       return true;
+       return 17;
 }
 
-static bool
+static int
 init_97(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2859,13 +2864,13 @@ init_97(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        val = (val & mask) | ((val + add) & ~mask);
 
        if (!iexec->execute)
-               return true;
+               return 13;
 
        bios_wr32(bios, reg, val);
-       return true;
+       return 13;
 }
 
-static bool
+static int
 init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2883,32 +2888,33 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        struct drm_device *dev = bios->dev;
        struct nouveau_i2c_chan *auxch;
        uint32_t addr = ROM32(bios->data[offset + 1]);
-       uint8_t len = bios->data[offset + 5];
+       uint8_t count = bios->data[offset + 5];
+       int len = 6 + count * 2;
        int ret, i;
 
        if (!bios->display.output) {
                NV_ERROR(dev, "INIT_AUXCH: no active output\n");
-               return false;
+               return 0;
        }
 
        auxch = init_i2c_device_find(dev, bios->display.output->i2c_index);
        if (!auxch) {
                NV_ERROR(dev, "INIT_AUXCH: couldn't get auxch %d\n",
                         bios->display.output->i2c_index);
-               return false;
+               return 0;
        }
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        offset += 6;
-       for (i = 0; i < len; i++, offset += 2) {
+       for (i = 0; i < count; i++, offset += 2) {
                uint8_t data;
 
                ret = nouveau_dp_auxch(auxch, 9, addr, &data, 1);
                if (ret) {
                        NV_ERROR(dev, "INIT_AUXCH: rd auxch fail %d\n", ret);
-                       return false;
+                       return 0;
                }
 
                data &= bios->data[offset + 0];
@@ -2917,14 +2923,14 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
                ret = nouveau_dp_auxch(auxch, 8, addr, &data, 1);
                if (ret) {
                        NV_ERROR(dev, "INIT_AUXCH: wr auxch fail %d\n", ret);
-                       return false;
+                       return 0;
                }
        }
 
-       return true;
+       return len;
 }
 
-static bool
+static int
 init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
 {
        /*
@@ -2941,106 +2947,99 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
        struct drm_device *dev = bios->dev;
        struct nouveau_i2c_chan *auxch;
        uint32_t addr = ROM32(bios->data[offset + 1]);
-       uint8_t len = bios->data[offset + 5];
+       uint8_t count = bios->data[offset + 5];
+       int len = 6 + count;
        int ret, i;
 
        if (!bios->display.output) {
                NV_ERROR(dev, "INIT_ZM_AUXCH: no active output\n");
-               return false;
+               return 0;
        }
 
        auxch = init_i2c_device_find(dev, bios->display.output->i2c_index);
        if (!auxch) {
                NV_ERROR(dev, "INIT_ZM_AUXCH: couldn't get auxch %d\n",
                         bios->display.output->i2c_index);
-               return false;
+               return 0;
        }
 
        if (!iexec->execute)
-               return true;
+               return len;
 
        offset += 6;
-       for (i = 0; i < len; i++, offset++) {
+       for (i = 0; i < count; i++, offset++) {
                ret = nouveau_dp_auxch(auxch, 8, addr, &bios->data[offset], 1);
                if (ret) {
                        NV_ERROR(dev, "INIT_ZM_AUXCH: wr auxch fail %d\n", ret);
-                       return false;
+                       return 0;
                }
        }
 
-       return true;
+       return len;
 }
 
 static struct init_tbl_entry itbl_entry[] = {
        /* command name                       , id  , length  , offset  , mult    , command handler                 */
        /* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */
-       { "INIT_IO_RESTRICT_PROG"             , 0x32, 11      , 6       , 4       , init_io_restrict_prog           },
-       { "INIT_REPEAT"                       , 0x33, 2       , 0       , 0       , init_repeat                     },
-       { "INIT_IO_RESTRICT_PLL"              , 0x34, 12      , 7       , 2       , init_io_restrict_pll            },
-       { "INIT_END_REPEAT"                   , 0x36, 1       , 0       , 0       , init_end_repeat                 },
-       { "INIT_COPY"                         , 0x37, 11      , 0       , 0       , init_copy                       },
-       { "INIT_NOT"                          , 0x38, 1       , 0       , 0       , init_not                        },
-       { "INIT_IO_FLAG_CONDITION"            , 0x39, 2       , 0       , 0       , init_io_flag_condition          },
-       { "INIT_INDEX_ADDRESS_LATCHED"        , 0x49, 18      , 17      , 2       , init_idx_addr_latched           },
-       { "INIT_IO_RESTRICT_PLL2"             , 0x4A, 11      , 6       , 4       , init_io_restrict_pll2           },
-       { "INIT_PLL2"                         , 0x4B, 9       , 0       , 0       , init_pll2                       },
-       { "INIT_I2C_BYTE"                     , 0x4C, 4       , 3       , 3       , init_i2c_byte                   },
-       { "INIT_ZM_I2C_BYTE"                  , 0x4D, 4       , 3       , 2       , init_zm_i2c_byte                },
-       { "INIT_ZM_I2C"                       , 0x4E, 4       , 3       , 1       , init_zm_i2c                     },
-       { "INIT_TMDS"                         , 0x4F, 5       , 0       , 0       , init_tmds                       },
-       { "INIT_ZM_TMDS_GROUP"                , 0x50, 3       , 2       , 2       , init_zm_tmds_group              },
-       { "INIT_CR_INDEX_ADDRESS_LATCHED"     , 0x51, 5       , 4       , 1       , init_cr_idx_adr_latch           },
-       { "INIT_CR"                           , 0x52, 4       , 0       , 0       , init_cr                         },
-       { "INIT_ZM_CR"                        , 0x53, 3       , 0       , 0       , init_zm_cr                      },
-       { "INIT_ZM_CR_GROUP"                  , 0x54, 2       , 1       , 2       , init_zm_cr_group                },
-       { "INIT_CONDITION_TIME"               , 0x56, 3       , 0       , 0       , init_condition_time             },
-       { "INIT_ZM_REG_SEQUENCE"              , 0x58, 6       , 5       , 4       , init_zm_reg_sequence            },
+       { "INIT_IO_RESTRICT_PROG"             , 0x32, init_io_restrict_prog           },
+       { "INIT_REPEAT"                       , 0x33, init_repeat                     },
+       { "INIT_IO_RESTRICT_PLL"              , 0x34, init_io_restrict_pll            },
+       { "INIT_END_REPEAT"                   , 0x36, init_end_repeat                 },
+       { "INIT_COPY"                         , 0x37, init_copy                       },
+       { "INIT_NOT"                          , 0x38, init_not                        },
+       { "INIT_IO_FLAG_CONDITION"            , 0x39, init_io_flag_condition          },
+       { "INIT_INDEX_ADDRESS_LATCHED"        , 0x49, init_idx_addr_latched           },
+       { "INIT_IO_RESTRICT_PLL2"             , 0x4A, init_io_restrict_pll2           },
+       { "INIT_PLL2"                         , 0x4B, init_pll2                       },
+       { "INIT_I2C_BYTE"                     , 0x4C, init_i2c_byte                   },
+       { "INIT_ZM_I2C_BYTE"                  , 0x4D, init_zm_i2c_byte                },
+       { "INIT_ZM_I2C"                       , 0x4E, init_zm_i2c                     },
+       { "INIT_TMDS"                         , 0x4F, init_tmds                       },
+       { "INIT_ZM_TMDS_GROUP"                , 0x50, init_zm_tmds_group              },
+       { "INIT_CR_INDEX_ADDRESS_LATCHED"     , 0x51, init_cr_idx_adr_latch           },
+       { "INIT_CR"                           , 0x52, init_cr                         },
+       { "INIT_ZM_CR"                        , 0x53, init_zm_cr                      },
+       { "INIT_ZM_CR_GROUP"                  , 0x54, init_zm_cr_group                },
+       { "INIT_CONDITION_TIME"               , 0x56, init_condition_time             },
+       { "INIT_ZM_REG_SEQUENCE"              , 0x58, init_zm_reg_sequence            },
        /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
-       { "INIT_SUB_DIRECT"                   , 0x5B, 3       , 0       , 0       , init_sub_direct                 },
-       { "INIT_COPY_NV_REG"                  , 0x5F, 22      , 0       , 0       , init_copy_nv_reg                },
-       { "INIT_ZM_INDEX_IO"                  , 0x62, 5       , 0       , 0       , init_zm_index_io                },
-       { "INIT_COMPUTE_MEM"                  , 0x63, 1       , 0       , 0       , init_compute_mem                },
-       { "INIT_RESET"                        , 0x65, 13      , 0       , 0       , init_reset                      },
-       { "INIT_CONFIGURE_MEM"                , 0x66, 1       , 0       , 0       , init_configure_mem              },
-       { "INIT_CONFIGURE_CLK"                , 0x67, 1       , 0       , 0       , init_configure_clk              },
-       { "INIT_CONFIGURE_PREINIT"            , 0x68, 1       , 0       , 0       , init_configure_preinit          },
-       { "INIT_IO"                           , 0x69, 5       , 0       , 0       , init_io                         },
-       { "INIT_SUB"                          , 0x6B, 2       , 0       , 0       , init_sub                        },
-       { "INIT_RAM_CONDITION"                , 0x6D, 3       , 0       , 0       , init_ram_condition              },
-       { "INIT_NV_REG"                       , 0x6E, 13      , 0       , 0       , init_nv_reg                     },
-       { "INIT_MACRO"                        , 0x6F, 2       , 0       , 0       , init_macro                      },
-       { "INIT_DONE"                         , 0x71, 1       , 0       , 0       , init_done                       },
-       { "INIT_RESUME"                       , 0x72, 1       , 0       , 0       , init_resume                     },
+       { "INIT_SUB_DIRECT"                   , 0x5B, init_sub_direct                 },
+       { "INIT_COPY_NV_REG"                  , 0x5F, init_copy_nv_reg                },
+       { "INIT_ZM_INDEX_IO"                  , 0x62, init_zm_index_io                },
+       { "INIT_COMPUTE_MEM"                  , 0x63, init_compute_mem                },
+       { "INIT_RESET"                        , 0x65, init_reset                      },
+       { "INIT_CONFIGURE_MEM"                , 0x66, init_configure_mem              },
+       { "INIT_CONFIGURE_CLK"                , 0x67, init_configure_clk              },
+       { "INIT_CONFIGURE_PREINIT"            , 0x68, init_configure_preinit          },
+       { "INIT_IO"                           , 0x69, init_io                         },
+       { "INIT_SUB"                          , 0x6B, init_sub                        },
+       { "INIT_RAM_CONDITION"                , 0x6D, init_ram_condition              },
+       { "INIT_NV_REG"                       , 0x6E, init_nv_reg                     },
+       { "INIT_MACRO"                        , 0x6F, init_macro                      },
+       { "INIT_DONE"                         , 0x71, init_done                       },
+       { "INIT_RESUME"                       , 0x72, init_resume                     },
        /* INIT_RAM_CONDITION2 (0x73, 9, 0, 0) removed due to no example of use */
-       { "INIT_TIME"                         , 0x74, 3       , 0       , 0       , init_time                       },
-       { "INIT_CONDITION"                    , 0x75, 2       , 0       , 0       , init_condition                  },
-       { "INIT_IO_CONDITION"                 , 0x76, 2       , 0       , 0       , init_io_condition               },
-       { "INIT_INDEX_IO"                     , 0x78, 6       , 0       , 0       , init_index_io                   },
-       { "INIT_PLL"                          , 0x79, 7       , 0       , 0       , init_pll                        },
-       { "INIT_ZM_REG"                       , 0x7A, 9       , 0       , 0       , init_zm_reg                     },
-       /* INIT_RAM_RESTRICT_PLL's length is adjusted by the BIT M table */
-       { "INIT_RAM_RESTRICT_PLL"             , 0x87, 2       , 0       , 0       , init_ram_restrict_pll           },
-       { "INIT_8C"                           , 0x8C, 1       , 0       , 0       , init_8c                         },
-       { "INIT_8D"                           , 0x8D, 1       , 0       , 0       , init_8d                         },
-       { "INIT_GPIO"                         , 0x8E, 1       , 0       , 0       , init_gpio                       },
-       /* INIT_RAM_RESTRICT_ZM_REG_GROUP's mult is loaded by M table in BIT */
-       { "INIT_RAM_RESTRICT_ZM_REG_GROUP"    , 0x8F, 7       , 6       , 0       , init_ram_restrict_zm_reg_group  },
-       { "INIT_COPY_ZM_REG"                  , 0x90, 9       , 0       , 0       , init_copy_zm_reg                },
-       { "INIT_ZM_REG_GROUP_ADDRESS_LATCHED" , 0x91, 6       , 5       , 4       , init_zm_reg_group_addr_latched  },
-       { "INIT_RESERVED"                     , 0x92, 1       , 0       , 0       , init_reserved                   },
-       { "INIT_96"                           , 0x96, 17      , 0       , 0       , init_96                         },
-       { "INIT_97"                           , 0x97, 13      , 0       , 0       , init_97                         },
-       { "INIT_AUXCH"                        , 0x98, 6       , 5       , 2       , init_auxch                      },
-       { "INIT_ZM_AUXCH"                     , 0x99, 6       , 5       , 1       , init_zm_auxch                   },
-       { NULL                                , 0   , 0       , 0       , 0       , NULL                            }
+       { "INIT_TIME"                         , 0x74, init_time                       },
+       { "INIT_CONDITION"                    , 0x75, init_condition                  },
+       { "INIT_IO_CONDITION"                 , 0x76, init_io_condition               },
+       { "INIT_INDEX_IO"                     , 0x78, init_index_io                   },
+       { "INIT_PLL"                          , 0x79, init_pll                        },
+       { "INIT_ZM_REG"                       , 0x7A, init_zm_reg                     },
+       { "INIT_RAM_RESTRICT_PLL"             , 0x87, init_ram_restrict_pll           },
+       { "INIT_8C"                           , 0x8C, init_8c                         },
+       { "INIT_8D"                           , 0x8D, init_8d                         },
+       { "INIT_GPIO"                         , 0x8E, init_gpio                       },
+       { "INIT_RAM_RESTRICT_ZM_REG_GROUP"    , 0x8F, init_ram_restrict_zm_reg_group  },
+       { "INIT_COPY_ZM_REG"                  , 0x90, init_copy_zm_reg                },
+       { "INIT_ZM_REG_GROUP_ADDRESS_LATCHED" , 0x91, init_zm_reg_group_addr_latched  },
+       { "INIT_RESERVED"                     , 0x92, init_reserved                   },
+       { "INIT_96"                           , 0x96, init_96                         },
+       { "INIT_97"                           , 0x97, init_97                         },
+       { "INIT_AUXCH"                        , 0x98, init_auxch                      },
+       { "INIT_ZM_AUXCH"                     , 0x99, init_zm_auxch                   },
+       { NULL                                , 0   , NULL                            }
 };
 
-static unsigned int get_init_table_entry_length(struct nvbios *bios, unsigned int offset, int i)
-{
-       /* Calculates the length of a given init table entry. */
-       return itbl_entry[i].length + bios->data[offset + itbl_entry[i].length_offset]*itbl_entry[i].length_multiplier;
-}
-
 #define MAX_TABLE_OPS 1000
 
 static int
@@ -3056,7 +3055,7 @@ parse_init_table(struct nvbios *bios, unsigned int offset,
         * is changed back to EXECUTE.
         */
 
-       int count = 0, i;
+       int count = 0, i, res;
        uint8_t id;
 
        /*
@@ -3076,22 +3075,21 @@ parse_init_table(struct nvbios *bios, unsigned int offset,
                                offset, itbl_entry[i].id, itbl_entry[i].name);
 
                        /* execute eventual command handler */
-                       if (itbl_entry[i].handler)
-                               if (!(*itbl_entry[i].handler)(bios, offset, iexec))
-                                       break;
+                       res = (*itbl_entry[i].handler)(bios, offset, iexec);
+                       if (!res)
+                               break;
+                       /*
+                        * Add the offset of the current command including all data
+                        * of that command. The offset will then be pointing on the
+                        * next op code.
+                        */
+                       offset += res;
                } else {
                        NV_ERROR(bios->dev,
                                 "0x%04X: Init table command not found: "
                                 "0x%02X\n", offset, id);
                        return -ENOENT;
                }
-
-               /*
-                * Add the offset of the current command including all data
-                * of that command. The offset will then be pointing on the
-                * next op code.
-                */
-               offset += get_init_table_entry_length(bios, offset, i);
        }
 
        if (offset >= bios->length)
@@ -3854,7 +3852,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
         * script tables is a pointer to the script to execute.
         */
 
-       NV_DEBUG(dev, "Searching for output entry for %d %d %d\n",
+       NV_DEBUG_KMS(dev, "Searching for output entry for %d %d %d\n",
                        dcbent->type, dcbent->location, dcbent->or);
        otable = bios_output_config_match(dev, dcbent, table[1] +
                                          bios->display.script_table_ptr,
@@ -3884,7 +3882,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
        if (pxclk == 0) {
                script = ROM16(otable[6]);
                if (!script) {
-                       NV_DEBUG(dev, "output script 0 not found\n");
+                       NV_DEBUG_KMS(dev, "output script 0 not found\n");
                        return 1;
                }
 
@@ -3894,7 +3892,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
        if (pxclk == -1) {
                script = ROM16(otable[8]);
                if (!script) {
-                       NV_DEBUG(dev, "output script 1 not found\n");
+                       NV_DEBUG_KMS(dev, "output script 1 not found\n");
                        return 1;
                }
 
@@ -3907,7 +3905,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
                else
                        script = 0;
                if (!script) {
-                       NV_DEBUG(dev, "output script 2 not found\n");
+                       NV_DEBUG_KMS(dev, "output script 2 not found\n");
                        return 1;
                }
 
@@ -3931,7 +3929,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
                if (script)
                        script = clkcmptable(bios, script, -pxclk);
                if (!script) {
-                       NV_DEBUG(dev, "clock script 1 not found\n");
+                       NV_DEBUG_KMS(dev, "clock script 1 not found\n");
                        return 1;
                }
 
@@ -4606,10 +4604,6 @@ parse_bit_M_tbl_entry(struct drm_device *dev, struct nvbios *bios,
         * stuff that we don't use - their use currently unknown
         */
 
-       uint16_t rr_strap_xlat;
-       uint8_t rr_group_count;
-       int i;
-
        /*
         * Older bios versions don't have a sufficiently long table for
         * what we want
@@ -4618,24 +4612,13 @@ parse_bit_M_tbl_entry(struct drm_device *dev, struct nvbios *bios,
                return 0;
 
        if (bitentry->id[1] < 2) {
-               rr_group_count = bios->data[bitentry->offset + 2];
-               rr_strap_xlat = ROM16(bios->data[bitentry->offset + 3]);
+               bios->ram_restrict_group_count = bios->data[bitentry->offset + 2];
+               bios->ram_restrict_tbl_ptr = ROM16(bios->data[bitentry->offset + 3]);
        } else {
-               rr_group_count = bios->data[bitentry->offset + 0];
-               rr_strap_xlat = ROM16(bios->data[bitentry->offset + 1]);
+               bios->ram_restrict_group_count = bios->data[bitentry->offset + 0];
+               bios->ram_restrict_tbl_ptr = ROM16(bios->data[bitentry->offset + 1]);
        }
 
-       /* adjust length of INIT_87 */
-       for (i = 0; itbl_entry[i].name && (itbl_entry[i].id != 0x87); i++);
-       itbl_entry[i].length += rr_group_count * 4;
-
-       /* set up multiplier for INIT_RAM_RESTRICT_ZM_REG_GROUP */
-       for (; itbl_entry[i].name && (itbl_entry[i].id != 0x8f); i++);
-       itbl_entry[i].length_multiplier = rr_group_count * 4;
-
-       init_ram_restrict_zm_reg_group_blocklen = itbl_entry[i].length_multiplier;
-       bios->ram_restrict_tbl_ptr = rr_strap_xlat;
-
        return 0;
 }
 
@@ -5234,7 +5217,7 @@ parse_dcb_connector_table(struct nvbios *bios)
        int i;
 
        if (!bios->bdcb.connector_table_ptr) {
-               NV_DEBUG(dev, "No DCB connector table present\n");
+               NV_DEBUG_KMS(dev, "No DCB connector table present\n");
                return;
        }
 
index 1d5f10b..058e98c 100644 (file)
@@ -227,6 +227,7 @@ struct nvbios {
 
        uint16_t pll_limit_tbl_ptr;
        uint16_t ram_restrict_tbl_ptr;
+       uint8_t ram_restrict_group_count;
 
        uint16_t some_script_ptr; /* BIT I + 14 */
        uint16_t init96_tbl_ptr; /* BIT I + 16 */
index aa2dfbc..0cad6d8 100644 (file)
@@ -154,6 +154,11 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t memtype)
        nvbo->placement.busy_placement = nvbo->placements;
        nvbo->placement.num_placement = n;
        nvbo->placement.num_busy_placement = n;
+
+       if (nvbo->pin_refcnt) {
+               while (n--)
+                       nvbo->placements[n] |= TTM_PL_FLAG_NO_EVICT;
+       }
 }
 
 int
@@ -400,10 +405,16 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
        struct nouveau_bo *nvbo = nouveau_bo(bo);
 
        switch (bo->mem.mem_type) {
+       case TTM_PL_VRAM:
+               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT |
+                                        TTM_PL_FLAG_SYSTEM);
+               break;
        default:
                nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM);
                break;
        }
+
+       *pl = nvbo->placement;
 }
 
 
@@ -455,11 +466,8 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, int no_wait,
        int ret;
 
        chan = nvbo->channel;
-       if (!chan || nvbo->tile_flags || nvbo->no_vm) {
+       if (!chan || nvbo->tile_flags || nvbo->no_vm)
                chan = dev_priv->channel;
-               if (!chan)
-                       return -EINVAL;
-       }
 
        src_offset = old_mem->mm_node->start << PAGE_SHIFT;
        dst_offset = new_mem->mm_node->start << PAGE_SHIFT;
@@ -625,7 +633,8 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
                        return ret;
        }
 
-       if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE)
+       if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE ||
+           !dev_priv->channel)
                return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem);
 
        if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) {
index 032cf09..5a10deb 100644 (file)
@@ -86,7 +86,7 @@ nouveau_connector_destroy(struct drm_connector *drm_connector)
        struct nouveau_connector *connector = nouveau_connector(drm_connector);
        struct drm_device *dev = connector->base.dev;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        if (!connector)
                return;
@@ -420,7 +420,7 @@ nouveau_connector_native_mode(struct nouveau_connector *connector)
        /* Use preferred mode if there is one.. */
        list_for_each_entry(mode, &connector->base.probed_modes, head) {
                if (mode->type & DRM_MODE_TYPE_PREFERRED) {
-                       NV_DEBUG(dev, "native mode from preferred\n");
+                       NV_DEBUG_KMS(dev, "native mode from preferred\n");
                        return drm_mode_duplicate(dev, mode);
                }
        }
@@ -445,7 +445,7 @@ nouveau_connector_native_mode(struct nouveau_connector *connector)
                largest = mode;
        }
 
-       NV_DEBUG(dev, "native mode from largest: %dx%d@%d\n",
+       NV_DEBUG_KMS(dev, "native mode from largest: %dx%d@%d\n",
                      high_w, high_h, high_v);
        return largest ? drm_mode_duplicate(dev, largest) : NULL;
 }
@@ -725,7 +725,7 @@ nouveau_connector_create(struct drm_device *dev, int index, int type)
        struct drm_encoder *encoder;
        int ret;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
        if (!nv_connector)
index de61f46..9e2926c 100644 (file)
@@ -187,7 +187,7 @@ nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config)
        if (ret)
                return false;
 
-       NV_DEBUG(dev, "\t\tadjust 0x%02x 0x%02x\n", request[0], request[1]);
+       NV_DEBUG_KMS(dev, "\t\tadjust 0x%02x 0x%02x\n", request[0], request[1]);
 
        /* Keep all lanes at the same level.. */
        for (i = 0; i < nv_encoder->dp.link_nr; i++) {
@@ -228,7 +228,7 @@ nouveau_dp_link_train_commit(struct drm_encoder *encoder, uint8_t *config)
        int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1);
        int dpe_headerlen, ret, i;
 
-       NV_DEBUG(dev, "\t\tconfig 0x%02x 0x%02x 0x%02x 0x%02x\n",
+       NV_DEBUG_KMS(dev, "\t\tconfig 0x%02x 0x%02x 0x%02x 0x%02x\n",
                 config[0], config[1], config[2], config[3]);
 
        dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
@@ -276,12 +276,12 @@ nouveau_dp_link_train(struct drm_encoder *encoder)
        bool cr_done, cr_max_vs, eq_done;
        int ret = 0, i, tries, voltage;
 
-       NV_DEBUG(dev, "link training!!\n");
+       NV_DEBUG_KMS(dev, "link training!!\n");
 train:
        cr_done = eq_done = false;
 
        /* set link configuration */
-       NV_DEBUG(dev, "\tbegin train: bw %d, lanes %d\n",
+       NV_DEBUG_KMS(dev, "\tbegin train: bw %d, lanes %d\n",
                 nv_encoder->dp.link_bw, nv_encoder->dp.link_nr);
 
        ret = nouveau_dp_link_bw_set(encoder, nv_encoder->dp.link_bw);
@@ -297,7 +297,7 @@ train:
                return false;
 
        /* clock recovery */
-       NV_DEBUG(dev, "\tbegin cr\n");
+       NV_DEBUG_KMS(dev, "\tbegin cr\n");
        ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_1);
        if (ret)
                goto stop;
@@ -314,7 +314,7 @@ train:
                ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 2);
                if (ret)
                        break;
-               NV_DEBUG(dev, "\t\tstatus: 0x%02x 0x%02x\n",
+               NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n",
                         status[0], status[1]);
 
                cr_done = true;
@@ -346,7 +346,7 @@ train:
                goto stop;
 
        /* channel equalisation */
-       NV_DEBUG(dev, "\tbegin eq\n");
+       NV_DEBUG_KMS(dev, "\tbegin eq\n");
        ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_2);
        if (ret)
                goto stop;
@@ -357,7 +357,7 @@ train:
                ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 3);
                if (ret)
                        break;
-               NV_DEBUG(dev, "\t\tstatus: 0x%02x 0x%02x\n",
+               NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n",
                         status[0], status[1]);
 
                eq_done = true;
@@ -395,9 +395,9 @@ stop:
 
        /* retry at a lower setting, if possible */
        if (!ret && !(eq_done && cr_done)) {
-               NV_DEBUG(dev, "\twe failed\n");
+               NV_DEBUG_KMS(dev, "\twe failed\n");
                if (nv_encoder->dp.link_bw != DP_LINK_BW_1_62) {
-                       NV_DEBUG(dev, "retry link training at low rate\n");
+                       NV_DEBUG_KMS(dev, "retry link training at low rate\n");
                        nv_encoder->dp.link_bw = DP_LINK_BW_1_62;
                        goto train;
                }
@@ -418,7 +418,7 @@ nouveau_dp_detect(struct drm_encoder *encoder)
        if (ret)
                return false;
 
-       NV_DEBUG(dev, "encoder: link_bw %d, link_nr %d\n"
+       NV_DEBUG_KMS(dev, "encoder: link_bw %d, link_nr %d\n"
                      "display: link_bw %d, link_nr %d version 0x%02x\n",
                 nv_encoder->dcb->dpconf.link_bw,
                 nv_encoder->dcb->dpconf.link_nr,
@@ -446,7 +446,7 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
        uint32_t tmp, ctrl, stat = 0, data32[4] = {};
        int ret = 0, i, index = auxch->rd;
 
-       NV_DEBUG(dev, "ch %d cmd %d addr 0x%x len %d\n", index, cmd, addr, data_nr);
+       NV_DEBUG_KMS(dev, "ch %d cmd %d addr 0x%x len %d\n", index, cmd, addr, data_nr);
 
        tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd));
        nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp | 0x00100000);
@@ -472,7 +472,7 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
        if (!(cmd & 1)) {
                memcpy(data32, data, data_nr);
                for (i = 0; i < 4; i++) {
-                       NV_DEBUG(dev, "wr %d: 0x%08x\n", i, data32[i]);
+                       NV_DEBUG_KMS(dev, "wr %d: 0x%08x\n", i, data32[i]);
                        nv_wr32(dev, NV50_AUXCH_DATA_OUT(index, i), data32[i]);
                }
        }
@@ -504,7 +504,7 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
        if (cmd & 1) {
                for (i = 0; i < 4; i++) {
                        data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i));
-                       NV_DEBUG(dev, "rd %d: 0x%08x\n", i, data32[i]);
+                       NV_DEBUG_KMS(dev, "rd %d: 0x%08x\n", i, data32[i]);
                }
                memcpy(data, data32, data_nr);
        }
index 35249c3..06eb993 100644 (file)
 
 #include "drm_pciids.h"
 
+MODULE_PARM_DESC(ctxfw, "Use external firmware blob for grctx init (NV40)");
+int nouveau_ctxfw = 0;
+module_param_named(ctxfw, nouveau_ctxfw, int, 0400);
+
 MODULE_PARM_DESC(noagp, "Disable AGP");
 int nouveau_noagp;
 module_param_named(noagp, nouveau_noagp, int, 0400);
@@ -273,7 +277,7 @@ nouveau_pci_resume(struct pci_dev *pdev)
 
                for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
                        chan = dev_priv->fifos[i];
-                       if (!chan)
+                       if (!chan || !chan->pushbuf_bo)
                                continue;
 
                        for (j = 0; j < NOUVEAU_DMA_SKIPS; j++)
@@ -341,7 +345,7 @@ static struct drm_driver driver = {
                .owner = THIS_MODULE,
                .open = drm_open,
                .release = drm_release,
-               .ioctl = drm_ioctl,
+               .unlocked_ioctl = drm_ioctl,
                .mmap = nouveau_ttm_mmap,
                .poll = drm_poll,
                .fasync = drm_fasync,
index 88b4c7b..5f8cbb7 100644 (file)
@@ -54,6 +54,7 @@ struct nouveau_fpriv {
 #include "nouveau_drm.h"
 #include "nouveau_reg.h"
 #include "nouveau_bios.h"
+struct nouveau_grctx;
 
 #define MAX_NUM_DCB_ENTRIES 16
 
@@ -317,6 +318,7 @@ struct nouveau_pgraph_engine {
        bool accel_blocked;
        void *ctxprog;
        void *ctxvals;
+       int grctx_size;
 
        int  (*init)(struct drm_device *);
        void (*takedown)(struct drm_device *);
@@ -647,6 +649,7 @@ extern int nouveau_fbpercrtc;
 extern char *nouveau_tv_norm;
 extern int nouveau_reg_debug;
 extern char *nouveau_vbios;
+extern int nouveau_ctxfw;
 
 /* nouveau_state.c */
 extern void nouveau_preclose(struct drm_device *dev, struct drm_file *);
@@ -959,9 +962,7 @@ extern int  nv40_graph_create_context(struct nouveau_channel *);
 extern void nv40_graph_destroy_context(struct nouveau_channel *);
 extern int  nv40_graph_load_context(struct nouveau_channel *);
 extern int  nv40_graph_unload_context(struct drm_device *);
-extern int  nv40_grctx_init(struct drm_device *);
-extern void nv40_grctx_fini(struct drm_device *);
-extern void nv40_grctx_vals_load(struct drm_device *, struct nouveau_gpuobj *);
+extern void nv40_grctx_init(struct nouveau_grctx *);
 
 /* nv50_graph.c */
 extern struct nouveau_pgraph_object_class nv50_graph_grclass[];
@@ -975,6 +976,12 @@ extern int  nv50_graph_load_context(struct nouveau_channel *);
 extern int  nv50_graph_unload_context(struct drm_device *);
 extern void nv50_graph_context_switch(struct drm_device *);
 
+/* nouveau_grctx.c */
+extern int  nouveau_grctx_prog_load(struct drm_device *);
+extern void nouveau_grctx_vals_load(struct drm_device *,
+                                   struct nouveau_gpuobj *);
+extern void nouveau_grctx_fini(struct drm_device *);
+
 /* nv04_instmem.c */
 extern int  nv04_instmem_init(struct drm_device *);
 extern void nv04_instmem_takedown(struct drm_device *);
@@ -1207,14 +1214,24 @@ static inline void nv_wo32(struct drm_device *dev, struct nouveau_gpuobj *obj,
                                        pci_name(d->pdev), ##arg)
 #ifndef NV_DEBUG_NOTRACE
 #define NV_DEBUG(d, fmt, arg...) do {                                          \
-       if (drm_debug) {                                                       \
+       if (drm_debug & DRM_UT_DRIVER) {                                       \
+               NV_PRINTK(KERN_DEBUG, d, "%s:%d - " fmt, __func__,             \
+                         __LINE__, ##arg);                                    \
+       }                                                                      \
+} while (0)
+#define NV_DEBUG_KMS(d, fmt, arg...) do {                                      \
+       if (drm_debug & DRM_UT_KMS) {                                          \
                NV_PRINTK(KERN_DEBUG, d, "%s:%d - " fmt, __func__,             \
                          __LINE__, ##arg);                                    \
        }                                                                      \
 } while (0)
 #else
 #define NV_DEBUG(d, fmt, arg...) do {                                          \
-       if (drm_debug)                                                         \
+       if (drm_debug & DRM_UT_DRIVER)                                         \
+               NV_PRINTK(KERN_DEBUG, d, fmt, ##arg);                          \
+} while (0)
+#define NV_DEBUG_KMS(d, fmt, arg...) do {                                      \
+       if (drm_debug & DRM_UT_KMS)                                            \
                NV_PRINTK(KERN_DEBUG, d, fmt, ##arg);                          \
 } while (0)
 #endif
index 36e8c5e..84af25c 100644 (file)
@@ -58,7 +58,7 @@ nouveau_fbcon_sync(struct fb_info *info)
        struct nouveau_channel *chan = dev_priv->channel;
        int ret, i;
 
-       if (!chan->accel_done ||
+       if (!chan || !chan->accel_done ||
            info->state != FBINFO_STATE_RUNNING ||
            info->flags & FBINFO_HWACCEL_DISABLED)
                return 0;
@@ -318,14 +318,16 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
        par->nouveau_fb = nouveau_fb;
        par->dev = dev;
 
-       switch (dev_priv->card_type) {
-       case NV_50:
-               nv50_fbcon_accel_init(info);
-               break;
-       default:
-               nv04_fbcon_accel_init(info);
-               break;
-       };
+       if (dev_priv->channel) {
+               switch (dev_priv->card_type) {
+               case NV_50:
+                       nv50_fbcon_accel_init(info);
+                       break;
+               default:
+                       nv04_fbcon_accel_init(info);
+                       break;
+               };
+       }
 
        nouveau_fbcon_zfill(dev);
 
@@ -347,7 +349,7 @@ out:
 int
 nouveau_fbcon_probe(struct drm_device *dev)
 {
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_create);
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.c b/drivers/gpu/drm/nouveau/nouveau_grctx.c
new file mode 100644 (file)
index 0000000..419f4c2
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2009 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <linux/firmware.h>
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+
+struct nouveau_ctxprog {
+       uint32_t signature;
+       uint8_t  version;
+       uint16_t length;
+       uint32_t data[];
+} __attribute__ ((packed));
+
+struct nouveau_ctxvals {
+       uint32_t signature;
+       uint8_t  version;
+       uint32_t length;
+       struct {
+               uint32_t offset;
+               uint32_t value;
+       } data[];
+} __attribute__ ((packed));
+
+int
+nouveau_grctx_prog_load(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+       const int chipset = dev_priv->chipset;
+       const struct firmware *fw;
+       const struct nouveau_ctxprog *cp;
+       const struct nouveau_ctxvals *cv;
+       char name[32];
+       int ret, i;
+
+       if (pgraph->accel_blocked)
+               return -ENODEV;
+
+       if (!pgraph->ctxprog) {
+               sprintf(name, "nouveau/nv%02x.ctxprog", chipset);
+               ret = request_firmware(&fw, name, &dev->pdev->dev);
+               if (ret) {
+                       NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset);
+                       return ret;
+               }
+
+               pgraph->ctxprog = kmalloc(fw->size, GFP_KERNEL);
+               if (!pgraph->ctxprog) {
+                       NV_ERROR(dev, "OOM copying ctxprog\n");
+                       release_firmware(fw);
+                       return -ENOMEM;
+               }
+               memcpy(pgraph->ctxprog, fw->data, fw->size);
+
+               cp = pgraph->ctxprog;
+               if (le32_to_cpu(cp->signature) != 0x5043564e ||
+                   cp->version != 0 ||
+                   le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) {
+                       NV_ERROR(dev, "ctxprog invalid\n");
+                       release_firmware(fw);
+                       nouveau_grctx_fini(dev);
+                       return -EINVAL;
+               }
+               release_firmware(fw);
+       }
+
+       if (!pgraph->ctxvals) {
+               sprintf(name, "nouveau/nv%02x.ctxvals", chipset);
+               ret = request_firmware(&fw, name, &dev->pdev->dev);
+               if (ret) {
+                       NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset);
+                       nouveau_grctx_fini(dev);
+                       return ret;
+               }
+
+               pgraph->ctxvals = kmalloc(fw->size, GFP_KERNEL);
+               if (!pgraph->ctxprog) {
+                       NV_ERROR(dev, "OOM copying ctxprog\n");
+                       release_firmware(fw);
+                       nouveau_grctx_fini(dev);
+                       return -ENOMEM;
+               }
+               memcpy(pgraph->ctxvals, fw->data, fw->size);
+
+               cv = (void *)pgraph->ctxvals;
+               if (le32_to_cpu(cv->signature) != 0x5643564e ||
+                   cv->version != 0 ||
+                   le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) {
+                       NV_ERROR(dev, "ctxvals invalid\n");
+                       release_firmware(fw);
+                       nouveau_grctx_fini(dev);
+                       return -EINVAL;
+               }
+               release_firmware(fw);
+       }
+
+       cp = pgraph->ctxprog;
+
+       nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+       for (i = 0; i < le16_to_cpu(cp->length); i++)
+               nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA,
+                       le32_to_cpu(cp->data[i]));
+
+       return 0;
+}
+
+void
+nouveau_grctx_fini(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+
+       if (pgraph->ctxprog) {
+               kfree(pgraph->ctxprog);
+               pgraph->ctxprog = NULL;
+       }
+
+       if (pgraph->ctxvals) {
+               kfree(pgraph->ctxprog);
+               pgraph->ctxvals = NULL;
+       }
+}
+
+void
+nouveau_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+       struct nouveau_ctxvals *cv = pgraph->ctxvals;
+       int i;
+
+       if (!cv)
+               return;
+
+       for (i = 0; i < le32_to_cpu(cv->length); i++)
+               nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset),
+                       le32_to_cpu(cv->data[i].value));
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.h b/drivers/gpu/drm/nouveau/nouveau_grctx.h
new file mode 100644 (file)
index 0000000..5d39c4c
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef __NOUVEAU_GRCTX_H__
+#define __NOUVEAU_GRCTX_H__
+
+struct nouveau_grctx {
+       struct drm_device *dev;
+
+       enum {
+               NOUVEAU_GRCTX_PROG,
+               NOUVEAU_GRCTX_VALS
+       } mode;
+       void *data;
+
+       uint32_t ctxprog_max;
+       uint32_t ctxprog_len;
+       uint32_t ctxprog_reg;
+       int      ctxprog_label[32];
+       uint32_t ctxvals_pos;
+       uint32_t ctxvals_base;
+};
+
+#ifdef CP_CTX
+static inline void
+cp_out(struct nouveau_grctx *ctx, uint32_t inst)
+{
+       uint32_t *ctxprog = ctx->data;
+
+       if (ctx->mode != NOUVEAU_GRCTX_PROG)
+               return;
+
+       BUG_ON(ctx->ctxprog_len == ctx->ctxprog_max);
+       ctxprog[ctx->ctxprog_len++] = inst;
+}
+
+static inline void
+cp_lsr(struct nouveau_grctx *ctx, uint32_t val)
+{
+       cp_out(ctx, CP_LOAD_SR | val);
+}
+
+static inline void
+cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length)
+{
+       ctx->ctxprog_reg = (reg - 0x00400000) >> 2;
+
+       ctx->ctxvals_base = ctx->ctxvals_pos;
+       ctx->ctxvals_pos = ctx->ctxvals_base + length;
+
+       if (length > (CP_CTX_COUNT >> CP_CTX_COUNT_SHIFT)) {
+               cp_lsr(ctx, length);
+               length = 0;
+       }
+
+       cp_out(ctx, CP_CTX | (length << CP_CTX_COUNT_SHIFT) | ctx->ctxprog_reg);
+}
+
+static inline void
+cp_name(struct nouveau_grctx *ctx, int name)
+{
+       uint32_t *ctxprog = ctx->data;
+       int i;
+
+       if (ctx->mode != NOUVEAU_GRCTX_PROG)
+               return;
+
+       ctx->ctxprog_label[name] = ctx->ctxprog_len;
+       for (i = 0; i < ctx->ctxprog_len; i++) {
+               if ((ctxprog[i] & 0xfff00000) != 0xff400000)
+                       continue;
+               if ((ctxprog[i] & CP_BRA_IP) != ((name) << CP_BRA_IP_SHIFT))
+                       continue;
+               ctxprog[i] = (ctxprog[i] & 0x00ff00ff) |
+                            (ctx->ctxprog_len << CP_BRA_IP_SHIFT);
+       }
+}
+
+static inline void
+_cp_bra(struct nouveau_grctx *ctx, u32 mod, int flag, int state, int name)
+{
+       int ip = 0;
+
+       if (mod != 2) {
+               ip = ctx->ctxprog_label[name] << CP_BRA_IP_SHIFT;
+               if (ip == 0)
+                       ip = 0xff000000 | (name << CP_BRA_IP_SHIFT);
+       }
+
+       cp_out(ctx, CP_BRA | (mod << 18) | ip | flag |
+                   (state ? 0 : CP_BRA_IF_CLEAR));
+}
+#define cp_bra(c,f,s,n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#ifdef CP_BRA_MOD
+#define cp_cal(c,f,s,n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_ret(c,f,s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
+#endif
+
+static inline void
+_cp_wait(struct nouveau_grctx *ctx, int flag, int state)
+{
+       cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0));
+}
+#define cp_wait(c,f,s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+
+static inline void
+_cp_set(struct nouveau_grctx *ctx, int flag, int state)
+{
+       cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0));
+}
+#define cp_set(c,f,s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+
+static inline void
+cp_pos(struct nouveau_grctx *ctx, int offset)
+{
+       ctx->ctxvals_pos = offset;
+       ctx->ctxvals_base = ctx->ctxvals_pos;
+
+       cp_lsr(ctx, ctx->ctxvals_pos);
+       cp_out(ctx, CP_SET_CONTEXT_POINTER);
+}
+
+static inline void
+gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val)
+{
+       if (ctx->mode != NOUVEAU_GRCTX_VALS)
+               return;
+
+       reg = (reg - 0x00400000) / 4;
+       reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base;
+
+       nv_wo32(ctx->dev, ctx->data, reg, val);
+}
+#endif
+
+#endif
index a2c30f4..475ba81 100644 (file)
@@ -61,12 +61,10 @@ long nouveau_compat_ioctl(struct file *filp, unsigned int cmd,
        if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(mga_compat_ioctls))
                fn = nouveau_compat_ioctls[nr - DRM_COMMAND_BASE];
 #endif
-       lock_kernel();    /* XXX for now */
        if (fn != NULL)
                ret = (*fn)(filp, cmd, arg);
        else
-               ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
-       unlock_kernel();
+               ret = drm_ioctl(filp, cmd, arg);
 
        return ret;
 }
index 2ed41d3..e76ec2d 100644 (file)
@@ -299,12 +299,57 @@ nouveau_vga_set_decode(void *priv, bool state)
                return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
 }
 
+static int
+nouveau_card_init_channel(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *gpuobj;
+       int ret;
+
+       ret = nouveau_channel_alloc(dev, &dev_priv->channel,
+                                   (struct drm_file *)-2,
+                                   NvDmaFB, NvDmaTT);
+       if (ret)
+               return ret;
+
+       gpuobj = NULL;
+       ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
+                                    0, nouveau_mem_fb_amount(dev),
+                                    NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
+                                    &gpuobj);
+       if (ret)
+               goto out_err;
+
+       ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaVRAM,
+                                    gpuobj, NULL);
+       if (ret)
+               goto out_err;
+
+       gpuobj = NULL;
+       ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0,
+                                         dev_priv->gart_info.aper_size,
+                                         NV_DMA_ACCESS_RW, &gpuobj, NULL);
+       if (ret)
+               goto out_err;
+
+       ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaGART,
+                                    gpuobj, NULL);
+       if (ret)
+               goto out_err;
+
+       return 0;
+out_err:
+       nouveau_gpuobj_del(dev, &gpuobj);
+       nouveau_channel_free(dev_priv->channel);
+       dev_priv->channel = NULL;
+       return ret;
+}
+
 int
 nouveau_card_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine;
-       struct nouveau_gpuobj *gpuobj;
        int ret;
 
        NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
@@ -317,7 +362,7 @@ nouveau_card_init(struct drm_device *dev)
        /* Initialise internal driver API hooks */
        ret = nouveau_init_engine_ptrs(dev);
        if (ret)
-               return ret;
+               goto out;
        engine = &dev_priv->engine;
        dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
 
@@ -325,12 +370,12 @@ nouveau_card_init(struct drm_device *dev)
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                ret = nouveau_bios_init(dev);
                if (ret)
-                       return ret;
+                       goto out;
        }
 
        ret = nouveau_gpuobj_early_init(dev);
        if (ret)
-               return ret;
+               goto out_bios;
 
        /* Initialise instance memory, must happen before mem_init so we
         * know exactly how much VRAM we're able to use for "normal"
@@ -338,100 +383,68 @@ nouveau_card_init(struct drm_device *dev)
         */
        ret = engine->instmem.init(dev);
        if (ret)
-               return ret;
+               goto out_gpuobj_early;
 
        /* Setup the memory manager */
        ret = nouveau_mem_init(dev);
        if (ret)
-               return ret;
+               goto out_instmem;
 
        ret = nouveau_gpuobj_init(dev);
        if (ret)
-               return ret;
+               goto out_mem;
 
        /* PMC */
        ret = engine->mc.init(dev);
        if (ret)
-               return ret;
+               goto out_gpuobj;
 
        /* PTIMER */
        ret = engine->timer.init(dev);
        if (ret)
-               return ret;
+               goto out_mc;
 
        /* PFB */
        ret = engine->fb.init(dev);
        if (ret)
-               return ret;
+               goto out_timer;
 
        /* PGRAPH */
        ret = engine->graph.init(dev);
        if (ret)
-               return ret;
+               goto out_fb;
 
        /* PFIFO */
        ret = engine->fifo.init(dev);
        if (ret)
-               return ret;
+               goto out_graph;
 
        /* this call irq_preinstall, register irq handler and
         * call irq_postinstall
         */
        ret = drm_irq_install(dev);
        if (ret)
-               return ret;
+               goto out_fifo;
 
        ret = drm_vblank_init(dev, 0);
        if (ret)
-               return ret;
+               goto out_irq;
 
        /* what about PVIDEO/PCRTC/PRAMDAC etc? */
 
-       ret = nouveau_channel_alloc(dev, &dev_priv->channel,
-                                   (struct drm_file *)-2,
-                                   NvDmaFB, NvDmaTT);
-       if (ret)
-               return ret;
-
-       gpuobj = NULL;
-       ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
-                                    0, nouveau_mem_fb_amount(dev),
-                                    NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
-                                    &gpuobj);
-       if (ret)
-               return ret;
-
-       ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaVRAM,
-                                    gpuobj, NULL);
-       if (ret) {
-               nouveau_gpuobj_del(dev, &gpuobj);
-               return ret;
-       }
-
-       gpuobj = NULL;
-       ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0,
-                                         dev_priv->gart_info.aper_size,
-                                         NV_DMA_ACCESS_RW, &gpuobj, NULL);
-       if (ret)
-               return ret;
-
-       ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, NvDmaGART,
-                                    gpuobj, NULL);
-       if (ret) {
-               nouveau_gpuobj_del(dev, &gpuobj);
-               return ret;
+       if (!engine->graph.accel_blocked) {
+               ret = nouveau_card_init_channel(dev);
+               if (ret)
+                       goto out_irq;
        }
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               if (dev_priv->card_type >= NV_50) {
+               if (dev_priv->card_type >= NV_50)
                        ret = nv50_display_create(dev);
-                       if (ret)
-                               return ret;
-               } else {
+               else
                        ret = nv04_display_create(dev);
-                       if (ret)
-                               return ret;
-               }
+               if (ret)
+                       goto out_irq;
        }
 
        ret = nouveau_backlight_init(dev);
@@ -444,6 +457,32 @@ nouveau_card_init(struct drm_device *dev)
                drm_helper_initial_config(dev);
 
        return 0;
+
+out_irq:
+       drm_irq_uninstall(dev);
+out_fifo:
+       engine->fifo.takedown(dev);
+out_graph:
+       engine->graph.takedown(dev);
+out_fb:
+       engine->fb.takedown(dev);
+out_timer:
+       engine->timer.takedown(dev);
+out_mc:
+       engine->mc.takedown(dev);
+out_gpuobj:
+       nouveau_gpuobj_takedown(dev);
+out_mem:
+       nouveau_mem_close(dev);
+out_instmem:
+       engine->instmem.takedown(dev);
+out_gpuobj_early:
+       nouveau_gpuobj_late_takedown(dev);
+out_bios:
+       nouveau_bios_takedown(dev);
+out:
+       vga_client_register(dev->pdev, NULL, NULL, NULL);
+       return ret;
 }
 
 static void nouveau_card_takedown(struct drm_device *dev)
index b913636..d2f143e 100644 (file)
@@ -143,10 +143,10 @@ static void nv_crtc_calc_state_ext(struct drm_crtc *crtc, struct drm_display_mod
        state->pllsel |= nv_crtc->index ? PLLSEL_VPLL2_MASK : PLLSEL_VPLL1_MASK;
 
        if (pv->NM2)
-               NV_TRACE(dev, "vpll: n1 %d n2 %d m1 %d m2 %d log2p %d\n",
+               NV_DEBUG_KMS(dev, "vpll: n1 %d n2 %d m1 %d m2 %d log2p %d\n",
                         pv->N1, pv->N2, pv->M1, pv->M2, pv->log2P);
        else
-               NV_TRACE(dev, "vpll: n %d m %d log2p %d\n",
+               NV_DEBUG_KMS(dev, "vpll: n %d m %d log2p %d\n",
                         pv->N1, pv->M1, pv->log2P);
 
        nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.offset);
@@ -160,7 +160,7 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
        unsigned char seq1 = 0, crtc17 = 0;
        unsigned char crtc1A;
 
-       NV_TRACE(dev, "Setting dpms mode %d on CRTC %d\n", mode,
+       NV_DEBUG_KMS(dev, "Setting dpms mode %d on CRTC %d\n", mode,
                                                        nv_crtc->index);
 
        if (nv_crtc->last_dpms == mode) /* Don't do unnecesary mode changes. */
@@ -603,7 +603,7 @@ nv_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-       NV_DEBUG(dev, "CTRC mode on CRTC %d:\n", nv_crtc->index);
+       NV_DEBUG_KMS(dev, "CTRC mode on CRTC %d:\n", nv_crtc->index);
        drm_mode_debug_printmodeline(adjusted_mode);
 
        /* unlock must come after turning off FP_TG_CONTROL in output_prepare */
@@ -703,7 +703,7 @@ static void nv_crtc_destroy(struct drm_crtc *crtc)
 {
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 
-       NV_DEBUG(crtc->dev, "\n");
+       NV_DEBUG_KMS(crtc->dev, "\n");
 
        if (!nv_crtc)
                return;
index a5fa517..d9f3287 100644 (file)
@@ -205,7 +205,7 @@ out:
        NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1);
 
        if (blue == 0x18) {
-               NV_TRACE(dev, "Load detected on head A\n");
+               NV_INFO(dev, "Load detected on head A\n");
                return connector_status_connected;
        }
 
@@ -350,14 +350,10 @@ static void nv04_dac_mode_set(struct drm_encoder *encoder,
                              struct drm_display_mode *mode,
                              struct drm_display_mode *adjusted_mode)
 {
-       struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct drm_device *dev = encoder->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        int head = nouveau_crtc(encoder->crtc)->index;
 
-       NV_TRACE(dev, "%s called for encoder %d\n", __func__,
-                     nv_encoder->dcb->index);
-
        if (nv_gf4_disp_arch(dev)) {
                struct drm_encoder *rebind;
                uint32_t dac_offset = nv04_dac_output_offset(encoder);
@@ -466,7 +462,7 @@ static void nv04_dac_destroy(struct drm_encoder *encoder)
 {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
 
-       NV_DEBUG(encoder->dev, "\n");
+       NV_DEBUG_KMS(encoder->dev, "\n");
 
        drm_encoder_cleanup(encoder);
        kfree(nv_encoder);
index e5b3333..483f875 100644 (file)
@@ -261,7 +261,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
        struct drm_display_mode *output_mode = &nv_encoder->mode;
        uint32_t mode_ratio, panel_ratio;
 
-       NV_DEBUG(dev, "Output mode on CRTC %d:\n", nv_crtc->index);
+       NV_DEBUG_KMS(dev, "Output mode on CRTC %d:\n", nv_crtc->index);
        drm_mode_debug_printmodeline(output_mode);
 
        /* Initialize the FP registers in this CRTC. */
@@ -413,7 +413,9 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
        struct dcb_entry *dcbe = nv_encoder->dcb;
        int head = nouveau_crtc(encoder->crtc)->index;
 
-       NV_TRACE(dev, "%s called for encoder %d\n", __func__, nv_encoder->dcb->index);
+       NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
+               drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
+               nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
 
        if (dcbe->type == OUTPUT_TMDS)
                run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock);
@@ -550,7 +552,7 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder)
 {
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
 
-       NV_DEBUG(encoder->dev, "\n");
+       NV_DEBUG_KMS(encoder->dev, "\n");
 
        drm_encoder_cleanup(encoder);
        kfree(nv_encoder);
index b47c757..ef77215 100644 (file)
@@ -99,10 +99,11 @@ nv04_display_create(struct drm_device *dev)
        uint16_t connector[16] = { 0 };
        int i, ret;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        if (nv_two_heads(dev))
                nv04_display_store_initial_head_owner(dev);
+       nouveau_hw_save_vga_fonts(dev, 1);
 
        drm_mode_config_init(dev);
        drm_mode_create_scaling_mode_property(dev);
@@ -203,8 +204,6 @@ nv04_display_create(struct drm_device *dev)
        /* Save previous state */
        NVLockVgaCrtcs(dev, false);
 
-       nouveau_hw_save_vga_fonts(dev, 1);
-
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
                crtc->funcs->save(crtc);
 
@@ -223,7 +222,7 @@ nv04_display_destroy(struct drm_device *dev)
        struct drm_encoder *encoder;
        struct drm_crtc *crtc;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        /* Turn every CRTC off. */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -246,9 +245,9 @@ nv04_display_destroy(struct drm_device *dev)
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
                crtc->funcs->restore(crtc);
 
-       nouveau_hw_save_vga_fonts(dev, 0);
-
        drm_mode_config_cleanup(dev);
+
+       nouveau_hw_save_vga_fonts(dev, 0);
 }
 
 void
index 396ee92..d561d77 100644 (file)
@@ -543,7 +543,7 @@ nv04_graph_mthd_set_operation(struct nouveau_channel *chan, int grclass,
 
        nv_wi32(dev, instance, tmp);
        nv_wr32(dev, NV04_PGRAPH_CTX_SWITCH1, tmp);
-       nv_wr32(dev, NV04_PGRAPH_CTX_CACHE1 + subc, tmp);
+       nv_wr32(dev, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
        return 0;
 }
 
index 6bf6804..6870e0e 100644 (file)
@@ -389,49 +389,50 @@ struct graph_state {
        int nv10[ARRAY_SIZE(nv10_graph_ctx_regs)];
        int nv17[ARRAY_SIZE(nv17_graph_ctx_regs)];
        struct pipe_state pipe_state;
+       uint32_t lma_window[4];
 };
 
+#define PIPE_SAVE(dev, state, addr)                                    \
+       do {                                                            \
+               int __i;                                                \
+               nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr);           \
+               for (__i = 0; __i < ARRAY_SIZE(state); __i++)           \
+                       state[__i] = nv_rd32(dev, NV10_PGRAPH_PIPE_DATA); \
+       } while (0)
+
+#define PIPE_RESTORE(dev, state, addr)                                 \
+       do {                                                            \
+               int __i;                                                \
+               nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr);           \
+               for (__i = 0; __i < ARRAY_SIZE(state); __i++)           \
+                       nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, state[__i]); \
+       } while (0)
+
 static void nv10_graph_save_pipe(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
        struct graph_state *pgraph_ctx = chan->pgraph_ctx;
-       struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
-       int i;
-#define PIPE_SAVE(addr) \
-       do { \
-               nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr); \
-               for (i = 0; i < ARRAY_SIZE(fifo_pipe_state->pipe_##addr); i++) \
-                       fifo_pipe_state->pipe_##addr[i] = nv_rd32(dev, NV10_PGRAPH_PIPE_DATA); \
-       } while (0)
-
-       PIPE_SAVE(0x4400);
-       PIPE_SAVE(0x0200);
-       PIPE_SAVE(0x6400);
-       PIPE_SAVE(0x6800);
-       PIPE_SAVE(0x6c00);
-       PIPE_SAVE(0x7000);
-       PIPE_SAVE(0x7400);
-       PIPE_SAVE(0x7800);
-       PIPE_SAVE(0x0040);
-       PIPE_SAVE(0x0000);
-
-#undef PIPE_SAVE
+       struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+
+       PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
+       PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
+       PIPE_SAVE(dev, pipe->pipe_0x6400, 0x6400);
+       PIPE_SAVE(dev, pipe->pipe_0x6800, 0x6800);
+       PIPE_SAVE(dev, pipe->pipe_0x6c00, 0x6c00);
+       PIPE_SAVE(dev, pipe->pipe_0x7000, 0x7000);
+       PIPE_SAVE(dev, pipe->pipe_0x7400, 0x7400);
+       PIPE_SAVE(dev, pipe->pipe_0x7800, 0x7800);
+       PIPE_SAVE(dev, pipe->pipe_0x0040, 0x0040);
+       PIPE_SAVE(dev, pipe->pipe_0x0000, 0x0000);
 }
 
 static void nv10_graph_load_pipe(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
        struct graph_state *pgraph_ctx = chan->pgraph_ctx;
-       struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
-       int i;
+       struct pipe_state *pipe = &pgraph_ctx->pipe_state;
        uint32_t xfmode0, xfmode1;
-#define PIPE_RESTORE(addr) \
-       do { \
-               nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr); \
-               for (i = 0; i < ARRAY_SIZE(fifo_pipe_state->pipe_##addr); i++) \
-                       nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, fifo_pipe_state->pipe_##addr[i]); \
-       } while (0)
-
+       int i;
 
        nouveau_wait_for_idle(dev);
        /* XXX check haiku comments */
@@ -457,24 +458,22 @@ static void nv10_graph_load_pipe(struct nouveau_channel *chan)
        nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008);
 
 
-       PIPE_RESTORE(0x0200);
+       PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200);
        nouveau_wait_for_idle(dev);
 
        /* restore XFMODE */
        nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0);
        nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1);
-       PIPE_RESTORE(0x6400);
-       PIPE_RESTORE(0x6800);
-       PIPE_RESTORE(0x6c00);
-       PIPE_RESTORE(0x7000);
-       PIPE_RESTORE(0x7400);
-       PIPE_RESTORE(0x7800);
-       PIPE_RESTORE(0x4400);
-       PIPE_RESTORE(0x0000);
-       PIPE_RESTORE(0x0040);
+       PIPE_RESTORE(dev, pipe->pipe_0x6400, 0x6400);
+       PIPE_RESTORE(dev, pipe->pipe_0x6800, 0x6800);
+       PIPE_RESTORE(dev, pipe->pipe_0x6c00, 0x6c00);
+       PIPE_RESTORE(dev, pipe->pipe_0x7000, 0x7000);
+       PIPE_RESTORE(dev, pipe->pipe_0x7400, 0x7400);
+       PIPE_RESTORE(dev, pipe->pipe_0x7800, 0x7800);
+       PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400);
+       PIPE_RESTORE(dev, pipe->pipe_0x0000, 0x0000);
+       PIPE_RESTORE(dev, pipe->pipe_0x0040, 0x0040);
        nouveau_wait_for_idle(dev);
-
-#undef PIPE_RESTORE
 }
 
 static void nv10_graph_create_pipe(struct nouveau_channel *chan)
@@ -832,6 +831,9 @@ int nv10_graph_init(struct drm_device *dev)
                                      (1<<31));
        if (dev_priv->chipset >= 0x17) {
                nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x1f000000);
+               nv_wr32(dev, 0x400a10, 0x3ff3fb6);
+               nv_wr32(dev, 0x400838, 0x2f8684);
+               nv_wr32(dev, 0x40083c, 0x115f3f);
                nv_wr32(dev, 0x004006b0, 0x40000020);
        } else
                nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000);
@@ -867,6 +869,115 @@ void nv10_graph_takedown(struct drm_device *dev)
 {
 }
 
+static int
+nv17_graph_mthd_lma_window(struct nouveau_channel *chan, int grclass,
+                          int mthd, uint32_t data)
+{
+       struct drm_device *dev = chan->dev;
+       struct graph_state *ctx = chan->pgraph_ctx;
+       struct pipe_state *pipe = &ctx->pipe_state;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+       uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
+       uint32_t xfmode0, xfmode1;
+       int i;
+
+       ctx->lma_window[(mthd - 0x1638) / 4] = data;
+
+       if (mthd != 0x1644)
+               return 0;
+
+       nouveau_wait_for_idle(dev);
+
+       PIPE_SAVE(dev, pipe_0x0040, 0x0040);
+       PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
+
+       PIPE_RESTORE(dev, ctx->lma_window, 0x6790);
+
+       nouveau_wait_for_idle(dev);
+
+       xfmode0 = nv_rd32(dev, NV10_PGRAPH_XFMODE0);
+       xfmode1 = nv_rd32(dev, NV10_PGRAPH_XFMODE1);
+
+       PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
+       PIPE_SAVE(dev, pipe_0x64c0, 0x64c0);
+       PIPE_SAVE(dev, pipe_0x6ab0, 0x6ab0);
+       PIPE_SAVE(dev, pipe_0x6a80, 0x6a80);
+
+       nouveau_wait_for_idle(dev);
+
+       nv_wr32(dev, NV10_PGRAPH_XFMODE0, 0x10000000);
+       nv_wr32(dev, NV10_PGRAPH_XFMODE1, 0x00000000);
+       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+       for (i = 0; i < 4; i++)
+               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+       for (i = 0; i < 4; i++)
+               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+       for (i = 0; i < 3; i++)
+               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+
+       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+       for (i = 0; i < 3; i++)
+               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+       nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+
+       PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200);
+
+       nouveau_wait_for_idle(dev);
+
+       PIPE_RESTORE(dev, pipe_0x0040, 0x0040);
+
+       nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0);
+       nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1);
+
+       PIPE_RESTORE(dev, pipe_0x64c0, 0x64c0);
+       PIPE_RESTORE(dev, pipe_0x6ab0, 0x6ab0);
+       PIPE_RESTORE(dev, pipe_0x6a80, 0x6a80);
+       PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400);
+
+       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
+       nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+       nouveau_wait_for_idle(dev);
+
+       pgraph->fifo_access(dev, true);
+
+       return 0;
+}
+
+static int
+nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, int grclass,
+                          int mthd, uint32_t data)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+
+       nouveau_wait_for_idle(dev);
+
+       nv_wr32(dev, NV10_PGRAPH_DEBUG_4,
+               nv_rd32(dev, NV10_PGRAPH_DEBUG_4) | 0x1 << 8);
+       nv_wr32(dev, 0x004006b0,
+               nv_rd32(dev, 0x004006b0) | 0x8 << 24);
+
+       pgraph->fifo_access(dev, true);
+
+       return 0;
+}
+
+static struct nouveau_pgraph_object_method nv17_graph_celsius_mthds[] = {
+       { 0x1638, nv17_graph_mthd_lma_window },
+       { 0x163c, nv17_graph_mthd_lma_window },
+       { 0x1640, nv17_graph_mthd_lma_window },
+       { 0x1644, nv17_graph_mthd_lma_window },
+       { 0x1658, nv17_graph_mthd_lma_enable },
+       {}
+};
+
 struct nouveau_pgraph_object_class nv10_graph_grclass[] = {
        { 0x0030, false, NULL }, /* null */
        { 0x0039, false, NULL }, /* m2mf */
@@ -887,6 +998,6 @@ struct nouveau_pgraph_object_class nv10_graph_grclass[] = {
        { 0x0095, false, NULL }, /* multitex_tri */
        { 0x0056, false, NULL }, /* celcius (nv10) */
        { 0x0096, false, NULL }, /* celcius (nv11) */
-       { 0x0099, false, NULL }, /* celcius (nv17) */
+       { 0x0099, false, nv17_graph_celsius_mthds }, /* celcius (nv17) */
        {}
 };
index 46cfd9c..81c0135 100644 (file)
@@ -219,7 +219,7 @@ static void  nv17_tv_dpms(struct drm_encoder *encoder, int mode)
                return;
        nouveau_encoder(encoder)->last_dpms = mode;
 
-       NV_TRACE(dev, "Setting dpms mode %d on TV encoder (output %d)\n",
+       NV_INFO(dev, "Setting dpms mode %d on TV encoder (output %d)\n",
                 mode, nouveau_encoder(encoder)->dcb->index);
 
        regs->ptv_200 &= ~1;
@@ -619,7 +619,7 @@ static void nv17_tv_destroy(struct drm_encoder *encoder)
 {
        struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
 
-       NV_DEBUG(encoder->dev, "\n");
+       NV_DEBUG_KMS(encoder->dev, "\n");
 
        drm_encoder_cleanup(encoder);
        kfree(tv_enc);
index 7e8547c..2b332bb 100644 (file)
  *
  */
 
-#include <linux/firmware.h>
-
 #include "drmP.h"
 #include "drm.h"
 #include "nouveau_drv.h"
-
-MODULE_FIRMWARE("nouveau/nv40.ctxprog");
-MODULE_FIRMWARE("nouveau/nv40.ctxvals");
-MODULE_FIRMWARE("nouveau/nv41.ctxprog");
-MODULE_FIRMWARE("nouveau/nv41.ctxvals");
-MODULE_FIRMWARE("nouveau/nv42.ctxprog");
-MODULE_FIRMWARE("nouveau/nv42.ctxvals");
-MODULE_FIRMWARE("nouveau/nv43.ctxprog");
-MODULE_FIRMWARE("nouveau/nv43.ctxvals");
-MODULE_FIRMWARE("nouveau/nv44.ctxprog");
-MODULE_FIRMWARE("nouveau/nv44.ctxvals");
-MODULE_FIRMWARE("nouveau/nv46.ctxprog");
-MODULE_FIRMWARE("nouveau/nv46.ctxvals");
-MODULE_FIRMWARE("nouveau/nv47.ctxprog");
-MODULE_FIRMWARE("nouveau/nv47.ctxvals");
-MODULE_FIRMWARE("nouveau/nv49.ctxprog");
-MODULE_FIRMWARE("nouveau/nv49.ctxvals");
-MODULE_FIRMWARE("nouveau/nv4a.ctxprog");
-MODULE_FIRMWARE("nouveau/nv4a.ctxvals");
-MODULE_FIRMWARE("nouveau/nv4b.ctxprog");
-MODULE_FIRMWARE("nouveau/nv4b.ctxvals");
-MODULE_FIRMWARE("nouveau/nv4c.ctxprog");
-MODULE_FIRMWARE("nouveau/nv4c.ctxvals");
-MODULE_FIRMWARE("nouveau/nv4e.ctxprog");
-MODULE_FIRMWARE("nouveau/nv4e.ctxvals");
+#include "nouveau_grctx.h"
 
 struct nouveau_channel *
 nv40_graph_channel(struct drm_device *dev)
@@ -83,27 +57,30 @@ nv40_graph_create_context(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj *ctx;
+       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        int ret;
 
-       /* Allocate a 175KiB block of PRAMIN to store the context.  This
-        * is massive overkill for a lot of chipsets, but it should be safe
-        * until we're able to implement this properly (will happen at more
-        * or less the same time we're able to write our own context programs.
-        */
-       ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 175*1024, 16,
-                                         NVOBJ_FLAG_ZERO_ALLOC,
-                                         &chan->ramin_grctx);
+       ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
+                                    16, NVOBJ_FLAG_ZERO_ALLOC,
+                                    &chan->ramin_grctx);
        if (ret)
                return ret;
-       ctx = chan->ramin_grctx->gpuobj;
 
        /* Initialise default context values */
        dev_priv->engine.instmem.prepare_access(dev, true);
-       nv40_grctx_vals_load(dev, ctx);
-       nv_wo32(dev, ctx, 0, ctx->im_pramin->start);
-       dev_priv->engine.instmem.finish_access(dev);
+       if (!pgraph->ctxprog) {
+               struct nouveau_grctx ctx = {};
 
+               ctx.dev = chan->dev;
+               ctx.mode = NOUVEAU_GRCTX_VALS;
+               ctx.data = chan->ramin_grctx->gpuobj;
+               nv40_grctx_init(&ctx);
+       } else {
+               nouveau_grctx_vals_load(dev, chan->ramin_grctx->gpuobj);
+       }
+       nv_wo32(dev, chan->ramin_grctx->gpuobj, 0,
+                    chan->ramin_grctx->gpuobj->im_pramin->start);
+       dev_priv->engine.instmem.finish_access(dev);
        return 0;
 }
 
@@ -204,139 +181,6 @@ nv40_graph_unload_context(struct drm_device *dev)
        return ret;
 }
 
-struct nouveau_ctxprog {
-       uint32_t signature;
-       uint8_t  version;
-       uint16_t length;
-       uint32_t data[];
-} __attribute__ ((packed));
-
-struct nouveau_ctxvals {
-       uint32_t signature;
-       uint8_t  version;
-       uint32_t length;
-       struct {
-               uint32_t offset;
-               uint32_t value;
-       } data[];
-} __attribute__ ((packed));
-
-int
-nv40_grctx_init(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       const int chipset = dev_priv->chipset;
-       const struct firmware *fw;
-       const struct nouveau_ctxprog *cp;
-       const struct nouveau_ctxvals *cv;
-       char name[32];
-       int ret, i;
-
-       pgraph->accel_blocked = true;
-
-       if (!pgraph->ctxprog) {
-               sprintf(name, "nouveau/nv%02x.ctxprog", chipset);
-               ret = request_firmware(&fw, name, &dev->pdev->dev);
-               if (ret) {
-                       NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset);
-                       return ret;
-               }
-
-               pgraph->ctxprog = kmalloc(fw->size, GFP_KERNEL);
-               if (!pgraph->ctxprog) {
-                       NV_ERROR(dev, "OOM copying ctxprog\n");
-                       release_firmware(fw);
-                       return -ENOMEM;
-               }
-               memcpy(pgraph->ctxprog, fw->data, fw->size);
-
-               cp = pgraph->ctxprog;
-               if (le32_to_cpu(cp->signature) != 0x5043564e ||
-                   cp->version != 0 ||
-                   le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) {
-                       NV_ERROR(dev, "ctxprog invalid\n");
-                       release_firmware(fw);
-                       nv40_grctx_fini(dev);
-                       return -EINVAL;
-               }
-               release_firmware(fw);
-       }
-
-       if (!pgraph->ctxvals) {
-               sprintf(name, "nouveau/nv%02x.ctxvals", chipset);
-               ret = request_firmware(&fw, name, &dev->pdev->dev);
-               if (ret) {
-                       NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset);
-                       nv40_grctx_fini(dev);
-                       return ret;
-               }
-
-               pgraph->ctxvals = kmalloc(fw->size, GFP_KERNEL);
-               if (!pgraph->ctxprog) {
-                       NV_ERROR(dev, "OOM copying ctxprog\n");
-                       release_firmware(fw);
-                       nv40_grctx_fini(dev);
-                       return -ENOMEM;
-               }
-               memcpy(pgraph->ctxvals, fw->data, fw->size);
-
-               cv = (void *)pgraph->ctxvals;
-               if (le32_to_cpu(cv->signature) != 0x5643564e ||
-                   cv->version != 0 ||
-                   le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) {
-                       NV_ERROR(dev, "ctxvals invalid\n");
-                       release_firmware(fw);
-                       nv40_grctx_fini(dev);
-                       return -EINVAL;
-               }
-               release_firmware(fw);
-       }
-
-       cp = pgraph->ctxprog;
-
-       nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
-       for (i = 0; i < le16_to_cpu(cp->length); i++)
-               nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA,
-                       le32_to_cpu(cp->data[i]));
-
-       pgraph->accel_blocked = false;
-       return 0;
-}
-
-void
-nv40_grctx_fini(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-
-       if (pgraph->ctxprog) {
-               kfree(pgraph->ctxprog);
-               pgraph->ctxprog = NULL;
-       }
-
-       if (pgraph->ctxvals) {
-               kfree(pgraph->ctxprog);
-               pgraph->ctxvals = NULL;
-       }
-}
-
-void
-nv40_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_ctxvals *cv = pgraph->ctxvals;
-       int i;
-
-       if (!cv)
-               return;
-
-       for (i = 0; i < le32_to_cpu(cv->length); i++)
-               nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset),
-                       le32_to_cpu(cv->data[i].value));
-}
-
 /*
  * G70         0x47
  * G71         0x49
@@ -359,7 +203,26 @@ nv40_graph_init(struct drm_device *dev)
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
                         NV_PMC_ENABLE_PGRAPH);
 
-       nv40_grctx_init(dev);
+       if (nouveau_ctxfw) {
+               nouveau_grctx_prog_load(dev);
+               dev_priv->engine.graph.grctx_size = 175 * 1024;
+       }
+
+       if (!dev_priv->engine.graph.ctxprog) {
+               struct nouveau_grctx ctx = {};
+               uint32_t cp[256];
+
+               ctx.dev = dev;
+               ctx.mode = NOUVEAU_GRCTX_PROG;
+               ctx.data = cp;
+               ctx.ctxprog_max = 256;
+               nv40_grctx_init(&ctx);
+               dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
+
+               nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+               for (i = 0; i < ctx.ctxprog_len; i++)
+                       nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
+       }
 
        /* No context present currently */
        nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
@@ -539,6 +402,7 @@ nv40_graph_init(struct drm_device *dev)
 
 void nv40_graph_takedown(struct drm_device *dev)
 {
+       nouveau_grctx_fini(dev);
 }
 
 struct nouveau_pgraph_object_class nv40_graph_grclass[] = {
diff --git a/drivers/gpu/drm/nouveau/nv40_grctx.c b/drivers/gpu/drm/nouveau/nv40_grctx.c
new file mode 100644 (file)
index 0000000..11b11c3
--- /dev/null
@@ -0,0 +1,678 @@
+/*
+ * Copyright 2009 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/* NVIDIA context programs handle a number of other conditions which are
+ * not implemented in our versions.  It's not clear why NVIDIA context
+ * programs have this code, nor whether it's strictly necessary for
+ * correct operation.  We'll implement additional handling if/when we
+ * discover it's necessary.
+ *
+ * - On context save, NVIDIA set 0x400314 bit 0 to 1 if the "3D state"
+ *   flag is set, this gets saved into the context.
+ * - On context save, the context program for all cards load nsource
+ *   into a flag register and check for ILLEGAL_MTHD.  If it's set,
+ *   opcode 0x60000d is called before resuming normal operation.
+ * - Some context programs check more conditions than the above.  NV44
+ *   checks: ((nsource & 0x0857) || (0x400718 & 0x0100) || (intr & 0x0001))
+ *   and calls 0x60000d before resuming normal operation.
+ * - At the very beginning of NVIDIA's context programs, flag 9 is checked
+ *   and if true 0x800001 is called with count=0, pos=0, the flag is cleared
+ *   and then the ctxprog is aborted.  It looks like a complicated NOP,
+ *   its purpose is unknown.
+ * - In the section of code that loads the per-vs state, NVIDIA check
+ *   flag 10.  If it's set, they only transfer the small 0x300 byte block
+ *   of state + the state for a single vs as opposed to the state for
+ *   all vs units.  It doesn't seem likely that it'll occur in normal
+ *   operation, especially seeing as it appears NVIDIA may have screwed
+ *   up the ctxprogs for some cards and have an invalid instruction
+ *   rather than a cp_lsr(ctx, dwords_for_1_vs_unit) instruction.
+ * - There's a number of places where context offset 0 (where we place
+ *   the PRAMIN offset of the context) is loaded into either 0x408000,
+ *   0x408004 or 0x408008.  Not sure what's up there either.
+ * - The ctxprogs for some cards save 0x400a00 again during the cleanup
+ *   path for auto-loadctx.
+ */
+
+#define CP_FLAG_CLEAR                 0
+#define CP_FLAG_SET                   1
+#define CP_FLAG_SWAP_DIRECTION        ((0 * 32) + 0)
+#define CP_FLAG_SWAP_DIRECTION_LOAD   0
+#define CP_FLAG_SWAP_DIRECTION_SAVE   1
+#define CP_FLAG_USER_SAVE             ((0 * 32) + 5)
+#define CP_FLAG_USER_SAVE_NOT_PENDING 0
+#define CP_FLAG_USER_SAVE_PENDING     1
+#define CP_FLAG_USER_LOAD             ((0 * 32) + 6)
+#define CP_FLAG_USER_LOAD_NOT_PENDING 0
+#define CP_FLAG_USER_LOAD_PENDING     1
+#define CP_FLAG_STATUS                ((3 * 32) + 0)
+#define CP_FLAG_STATUS_IDLE           0
+#define CP_FLAG_STATUS_BUSY           1
+#define CP_FLAG_AUTO_SAVE             ((3 * 32) + 4)
+#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0
+#define CP_FLAG_AUTO_SAVE_PENDING     1
+#define CP_FLAG_AUTO_LOAD             ((3 * 32) + 5)
+#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
+#define CP_FLAG_AUTO_LOAD_PENDING     1
+#define CP_FLAG_UNK54                 ((3 * 32) + 6)
+#define CP_FLAG_UNK54_CLEAR           0
+#define CP_FLAG_UNK54_SET             1
+#define CP_FLAG_ALWAYS                ((3 * 32) + 8)
+#define CP_FLAG_ALWAYS_FALSE          0
+#define CP_FLAG_ALWAYS_TRUE           1
+#define CP_FLAG_UNK57                 ((3 * 32) + 9)
+#define CP_FLAG_UNK57_CLEAR           0
+#define CP_FLAG_UNK57_SET             1
+
+#define CP_CTX                   0x00100000
+#define CP_CTX_COUNT             0x000fc000
+#define CP_CTX_COUNT_SHIFT               14
+#define CP_CTX_REG               0x00003fff
+#define CP_LOAD_SR               0x00200000
+#define CP_LOAD_SR_VALUE         0x000fffff
+#define CP_BRA                   0x00400000
+#define CP_BRA_IP                0x0000ff00
+#define CP_BRA_IP_SHIFT                   8
+#define CP_BRA_IF_CLEAR          0x00000080
+#define CP_BRA_FLAG              0x0000007f
+#define CP_WAIT                  0x00500000
+#define CP_WAIT_SET              0x00000080
+#define CP_WAIT_FLAG             0x0000007f
+#define CP_SET                   0x00700000
+#define CP_SET_1                 0x00000080
+#define CP_SET_FLAG              0x0000007f
+#define CP_NEXT_TO_SWAP          0x00600007
+#define CP_NEXT_TO_CURRENT       0x00600009
+#define CP_SET_CONTEXT_POINTER   0x0060000a
+#define CP_END                   0x0060000e
+#define CP_LOAD_MAGIC_UNK01      0x00800001 /* unknown */
+#define CP_LOAD_MAGIC_NV44TCL    0x00800029 /* per-vs state (0x4497) */
+#define CP_LOAD_MAGIC_NV40TCL    0x00800041 /* per-vs state (0x4097) */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_grctx.h"
+
+/* TODO:
+ *  - get vs count from 0x1540
+ *  - document unimplemented bits compared to nvidia
+ *    - nsource handling
+ *    - R0 & 0x0200 handling
+ *    - single-vs handling
+ *    - 400314 bit 0
+ */
+
+static int
+nv40_graph_4097(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if ((dev_priv->chipset & 0xf0) == 0x60)
+               return 0;
+
+       return !!(0x0baf & (1 << dev_priv->chipset));
+}
+
+static int
+nv40_graph_vs_count(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       switch (dev_priv->chipset) {
+       case 0x47:
+       case 0x49:
+       case 0x4b:
+               return 8;
+       case 0x40:
+               return 6;
+       case 0x41:
+       case 0x42:
+               return 5;
+       case 0x43:
+       case 0x44:
+       case 0x46:
+       case 0x4a:
+               return 3;
+       case 0x4c:
+       case 0x4e:
+       case 0x67:
+       default:
+               return 1;
+       }
+}
+
+
+enum cp_label {
+       cp_check_load = 1,
+       cp_setup_auto_load,
+       cp_setup_load,
+       cp_setup_save,
+       cp_swap_state,
+       cp_swap_state3d_3_is_save,
+       cp_prepare_exit,
+       cp_exit,
+};
+
+static void
+nv40_graph_construct_general(struct nouveau_grctx *ctx)
+{
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       int i;
+
+       cp_ctx(ctx, 0x4000a4, 1);
+       gr_def(ctx, 0x4000a4, 0x00000008);
+       cp_ctx(ctx, 0x400144, 58);
+       gr_def(ctx, 0x400144, 0x00000001);
+       cp_ctx(ctx, 0x400314, 1);
+       gr_def(ctx, 0x400314, 0x00000000);
+       cp_ctx(ctx, 0x400400, 10);
+       cp_ctx(ctx, 0x400480, 10);
+       cp_ctx(ctx, 0x400500, 19);
+       gr_def(ctx, 0x400514, 0x00040000);
+       gr_def(ctx, 0x400524, 0x55555555);
+       gr_def(ctx, 0x400528, 0x55555555);
+       gr_def(ctx, 0x40052c, 0x55555555);
+       gr_def(ctx, 0x400530, 0x55555555);
+       cp_ctx(ctx, 0x400560, 6);
+       gr_def(ctx, 0x400568, 0x0000ffff);
+       gr_def(ctx, 0x40056c, 0x0000ffff);
+       cp_ctx(ctx, 0x40057c, 5);
+       cp_ctx(ctx, 0x400710, 3);
+       gr_def(ctx, 0x400710, 0x20010001);
+       gr_def(ctx, 0x400714, 0x0f73ef00);
+       cp_ctx(ctx, 0x400724, 1);
+       gr_def(ctx, 0x400724, 0x02008821);
+       cp_ctx(ctx, 0x400770, 3);
+       if (dev_priv->chipset == 0x40) {
+               cp_ctx(ctx, 0x400814, 4);
+               cp_ctx(ctx, 0x400828, 5);
+               cp_ctx(ctx, 0x400840, 5);
+               gr_def(ctx, 0x400850, 0x00000040);
+               cp_ctx(ctx, 0x400858, 4);
+               gr_def(ctx, 0x400858, 0x00000040);
+               gr_def(ctx, 0x40085c, 0x00000040);
+               gr_def(ctx, 0x400864, 0x80000000);
+               cp_ctx(ctx, 0x40086c, 9);
+               gr_def(ctx, 0x40086c, 0x80000000);
+               gr_def(ctx, 0x400870, 0x80000000);
+               gr_def(ctx, 0x400874, 0x80000000);
+               gr_def(ctx, 0x400878, 0x80000000);
+               gr_def(ctx, 0x400888, 0x00000040);
+               gr_def(ctx, 0x40088c, 0x80000000);
+               cp_ctx(ctx, 0x4009c0, 8);
+               gr_def(ctx, 0x4009cc, 0x80000000);
+               gr_def(ctx, 0x4009dc, 0x80000000);
+       } else {
+               cp_ctx(ctx, 0x400840, 20);
+               if (!nv40_graph_4097(ctx->dev)) {
+                       for (i = 0; i < 8; i++)
+                               gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
+               }
+               gr_def(ctx, 0x400880, 0x00000040);
+               gr_def(ctx, 0x400884, 0x00000040);
+               gr_def(ctx, 0x400888, 0x00000040);
+               cp_ctx(ctx, 0x400894, 11);
+               gr_def(ctx, 0x400894, 0x00000040);
+               if (nv40_graph_4097(ctx->dev)) {
+                       for (i = 0; i < 8; i++)
+                               gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
+               }
+               cp_ctx(ctx, 0x4008e0, 2);
+               cp_ctx(ctx, 0x4008f8, 2);
+               if (dev_priv->chipset == 0x4c ||
+                   (dev_priv->chipset & 0xf0) == 0x60)
+                       cp_ctx(ctx, 0x4009f8, 1);
+       }
+       cp_ctx(ctx, 0x400a00, 73);
+       gr_def(ctx, 0x400b0c, 0x0b0b0b0c);
+       cp_ctx(ctx, 0x401000, 4);
+       cp_ctx(ctx, 0x405004, 1);
+       switch (dev_priv->chipset) {
+       case 0x47:
+       case 0x49:
+       case 0x4b:
+               cp_ctx(ctx, 0x403448, 1);
+               gr_def(ctx, 0x403448, 0x00001010);
+               break;
+       default:
+               cp_ctx(ctx, 0x403440, 1);
+               switch (dev_priv->chipset) {
+               case 0x40:
+                       gr_def(ctx, 0x403440, 0x00000010);
+                       break;
+               case 0x44:
+               case 0x46:
+               case 0x4a:
+                       gr_def(ctx, 0x403440, 0x00003010);
+                       break;
+               case 0x41:
+               case 0x42:
+               case 0x43:
+               case 0x4c:
+               case 0x4e:
+               case 0x67:
+               default:
+                       gr_def(ctx, 0x403440, 0x00001010);
+                       break;
+               }
+               break;
+       }
+}
+
+static void
+nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
+{
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       int i;
+
+       if (dev_priv->chipset == 0x40) {
+               cp_ctx(ctx, 0x401880, 51);
+               gr_def(ctx, 0x401940, 0x00000100);
+       } else
+       if (dev_priv->chipset == 0x46 || dev_priv->chipset == 0x47 ||
+           dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) {
+               cp_ctx(ctx, 0x401880, 32);
+               for (i = 0; i < 16; i++)
+                       gr_def(ctx, 0x401880 + (i * 4), 0x00000111);
+               if (dev_priv->chipset == 0x46)
+                       cp_ctx(ctx, 0x401900, 16);
+               cp_ctx(ctx, 0x401940, 3);
+       }
+       cp_ctx(ctx, 0x40194c, 18);
+       gr_def(ctx, 0x401954, 0x00000111);
+       gr_def(ctx, 0x401958, 0x00080060);
+       gr_def(ctx, 0x401974, 0x00000080);
+       gr_def(ctx, 0x401978, 0xffff0000);
+       gr_def(ctx, 0x40197c, 0x00000001);
+       gr_def(ctx, 0x401990, 0x46400000);
+       if (dev_priv->chipset == 0x40) {
+               cp_ctx(ctx, 0x4019a0, 2);
+               cp_ctx(ctx, 0x4019ac, 5);
+       } else {
+               cp_ctx(ctx, 0x4019a0, 1);
+               cp_ctx(ctx, 0x4019b4, 3);
+       }
+       gr_def(ctx, 0x4019bc, 0xffff0000);
+       switch (dev_priv->chipset) {
+       case 0x46:
+       case 0x47:
+       case 0x49:
+       case 0x4b:
+               cp_ctx(ctx, 0x4019c0, 18);
+               for (i = 0; i < 16; i++)
+                       gr_def(ctx, 0x4019c0 + (i * 4), 0x88888888);
+               break;
+       }
+       cp_ctx(ctx, 0x401a08, 8);
+       gr_def(ctx, 0x401a10, 0x0fff0000);
+       gr_def(ctx, 0x401a14, 0x0fff0000);
+       gr_def(ctx, 0x401a1c, 0x00011100);
+       cp_ctx(ctx, 0x401a2c, 4);
+       cp_ctx(ctx, 0x401a44, 26);
+       for (i = 0; i < 16; i++)
+               gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000);
+       gr_def(ctx, 0x401a8c, 0x4b7fffff);
+       if (dev_priv->chipset == 0x40) {
+               cp_ctx(ctx, 0x401ab8, 3);
+       } else {
+               cp_ctx(ctx, 0x401ab8, 1);
+               cp_ctx(ctx, 0x401ac0, 1);
+       }
+       cp_ctx(ctx, 0x401ad0, 8);
+       gr_def(ctx, 0x401ad0, 0x30201000);
+       gr_def(ctx, 0x401ad4, 0x70605040);
+       gr_def(ctx, 0x401ad8, 0xb8a89888);
+       gr_def(ctx, 0x401adc, 0xf8e8d8c8);
+       cp_ctx(ctx, 0x401b10, dev_priv->chipset == 0x40 ? 2 : 1);
+       gr_def(ctx, 0x401b10, 0x40100000);
+       cp_ctx(ctx, 0x401b18, dev_priv->chipset == 0x40 ? 6 : 5);
+       gr_def(ctx, 0x401b28, dev_priv->chipset == 0x40 ?
+                             0x00000004 : 0x00000000);
+       cp_ctx(ctx, 0x401b30, 25);
+       gr_def(ctx, 0x401b34, 0x0000ffff);
+       gr_def(ctx, 0x401b68, 0x435185d6);
+       gr_def(ctx, 0x401b6c, 0x2155b699);
+       gr_def(ctx, 0x401b70, 0xfedcba98);
+       gr_def(ctx, 0x401b74, 0x00000098);
+       gr_def(ctx, 0x401b84, 0xffffffff);
+       gr_def(ctx, 0x401b88, 0x00ff7000);
+       gr_def(ctx, 0x401b8c, 0x0000ffff);
+       if (dev_priv->chipset != 0x44 && dev_priv->chipset != 0x4a &&
+           dev_priv->chipset != 0x4e)
+               cp_ctx(ctx, 0x401b94, 1);
+       cp_ctx(ctx, 0x401b98, 8);
+       gr_def(ctx, 0x401b9c, 0x00ff0000);
+       cp_ctx(ctx, 0x401bc0, 9);
+       gr_def(ctx, 0x401be0, 0x00ffff00);
+       cp_ctx(ctx, 0x401c00, 192);
+       for (i = 0; i < 16; i++) { /* fragment texture units */
+               gr_def(ctx, 0x401c40 + (i * 4), 0x00018488);
+               gr_def(ctx, 0x401c80 + (i * 4), 0x00028202);
+               gr_def(ctx, 0x401d00 + (i * 4), 0x0000aae4);
+               gr_def(ctx, 0x401d40 + (i * 4), 0x01012000);
+               gr_def(ctx, 0x401d80 + (i * 4), 0x00080008);
+               gr_def(ctx, 0x401e00 + (i * 4), 0x00100008);
+       }
+       for (i = 0; i < 4; i++) { /* vertex texture units */
+               gr_def(ctx, 0x401e90 + (i * 4), 0x0001bc80);
+               gr_def(ctx, 0x401ea0 + (i * 4), 0x00000202);
+               gr_def(ctx, 0x401ec0 + (i * 4), 0x00000008);
+               gr_def(ctx, 0x401ee0 + (i * 4), 0x00080008);
+       }
+       cp_ctx(ctx, 0x400f5c, 3);
+       gr_def(ctx, 0x400f5c, 0x00000002);
+       cp_ctx(ctx, 0x400f84, 1);
+}
+
+static void
+nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
+{
+       struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+       int i;
+
+       cp_ctx(ctx, 0x402000, 1);
+       cp_ctx(ctx, 0x402404, dev_priv->chipset == 0x40 ? 1 : 2);
+       switch (dev_priv->chipset) {
+       case 0x40:
+               gr_def(ctx, 0x402404, 0x00000001);
+               break;
+       case 0x4c:
+       case 0x4e:
+       case 0x67:
+               gr_def(ctx, 0x402404, 0x00000020);
+               break;
+       case 0x46:
+       case 0x49:
+       case 0x4b:
+               gr_def(ctx, 0x402404, 0x00000421);
+               break;
+       default:
+               gr_def(ctx, 0x402404, 0x00000021);
+       }
+       if (dev_priv->chipset != 0x40)
+               gr_def(ctx, 0x402408, 0x030c30c3);
+       switch (dev_priv->chipset) {
+       case 0x44:
+       case 0x46:
+       case 0x4a:
+       case 0x4c:
+       case 0x4e:
+       case 0x67:
+               cp_ctx(ctx, 0x402440, 1);
+               gr_def(ctx, 0x402440, 0x00011001);
+               break;
+       default:
+               break;
+       }
+       cp_ctx(ctx, 0x402480, dev_priv->chipset == 0x40 ? 8 : 9);
+       gr_def(ctx, 0x402488, 0x3e020200);
+       gr_def(ctx, 0x40248c, 0x00ffffff);
+       switch (dev_priv->chipset) {
+       case 0x40:
+               gr_def(ctx, 0x402490, 0x60103f00);
+               break;
+       case 0x47:
+               gr_def(ctx, 0x402490, 0x40103f00);
+               break;
+       case 0x41:
+       case 0x42:
+       case 0x49:
+       case 0x4b:
+               gr_def(ctx, 0x402490, 0x20103f00);
+               break;
+       default:
+               gr_def(ctx, 0x402490, 0x0c103f00);
+               break;
+       }
+       gr_def(ctx, 0x40249c, dev_priv->chipset <= 0x43 ?
+                             0x00020000 : 0x00040000);
+       cp_ctx(ctx, 0x402500, 31);
+       gr_def(ctx, 0x402530, 0x00008100);
+       if (dev_priv->chipset == 0x40)
+               cp_ctx(ctx, 0x40257c, 6);
+       cp_ctx(ctx, 0x402594, 16);
+       cp_ctx(ctx, 0x402800, 17);
+       gr_def(ctx, 0x402800, 0x00000001);
+       switch (dev_priv->chipset) {
+       case 0x47:
+       case 0x49:
+       case 0x4b:
+               cp_ctx(ctx, 0x402864, 1);
+               gr_def(ctx, 0x402864, 0x00001001);
+               cp_ctx(ctx, 0x402870, 3);
+               gr_def(ctx, 0x402878, 0x00000003);
+               if (dev_priv->chipset != 0x47) { /* belong at end!! */
+                       cp_ctx(ctx, 0x402900, 1);
+                       cp_ctx(ctx, 0x402940, 1);
+                       cp_ctx(ctx, 0x402980, 1);
+                       cp_ctx(ctx, 0x4029c0, 1);
+                       cp_ctx(ctx, 0x402a00, 1);
+                       cp_ctx(ctx, 0x402a40, 1);
+                       cp_ctx(ctx, 0x402a80, 1);
+                       cp_ctx(ctx, 0x402ac0, 1);
+               }
+               break;
+       case 0x40:
+               cp_ctx(ctx, 0x402844, 1);
+               gr_def(ctx, 0x402844, 0x00000001);
+               cp_ctx(ctx, 0x402850, 1);
+               break;
+       default:
+               cp_ctx(ctx, 0x402844, 1);
+               gr_def(ctx, 0x402844, 0x00001001);
+               cp_ctx(ctx, 0x402850, 2);
+               gr_def(ctx, 0x402854, 0x00000003);
+               break;
+       }
+
+       cp_ctx(ctx, 0x402c00, 4);
+       gr_def(ctx, 0x402c00, dev_priv->chipset == 0x40 ?
+                             0x80800001 : 0x00888001);
+       switch (dev_priv->chipset) {
+       case 0x47:
+       case 0x49:
+       case 0x4b:
+               cp_ctx(ctx, 0x402c20, 40);
+               for (i = 0; i < 32; i++)
+                       gr_def(ctx, 0x402c40 + (i * 4), 0xffffffff);
+               cp_ctx(ctx, 0x4030b8, 13);
+               gr_def(ctx, 0x4030dc, 0x00000005);
+               gr_def(ctx, 0x4030e8, 0x0000ffff);
+               break;
+       default:
+               cp_ctx(ctx, 0x402c10, 4);
+               if (dev_priv->chipset == 0x40)
+                       cp_ctx(ctx, 0x402c20, 36);
+               else
+               if (dev_priv->chipset <= 0x42)
+                       cp_ctx(ctx, 0x402c20, 24);
+               else
+               if (dev_priv->chipset <= 0x4a)
+                       cp_ctx(ctx, 0x402c20, 16);
+               else
+                       cp_ctx(ctx, 0x402c20, 8);
+               cp_ctx(ctx, 0x402cb0, dev_priv->chipset == 0x40 ? 12 : 13);
+               gr_def(ctx, 0x402cd4, 0x00000005);
+               if (dev_priv->chipset != 0x40)
+                       gr_def(ctx, 0x402ce0, 0x0000ffff);
+               break;
+       }
+
+       cp_ctx(ctx, 0x403400, dev_priv->chipset == 0x40 ? 4 : 3);
+       cp_ctx(ctx, 0x403410, dev_priv->chipset == 0x40 ? 4 : 3);
+       cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->dev));
+       for (i = 0; i < nv40_graph_vs_count(ctx->dev); i++)
+               gr_def(ctx, 0x403420 + (i * 4), 0x00005555);
+
+       if (dev_priv->chipset != 0x40) {
+               cp_ctx(ctx, 0x403600, 1);
+               gr_def(ctx, 0x403600, 0x00000001);
+       }
+       cp_ctx(ctx, 0x403800, 1);
+
+       cp_ctx(ctx, 0x403c18, 1);
+       gr_def(ctx, 0x403c18, 0x00000001);
+       switch (dev_priv->chipset) {
+       case 0x46:
+       case 0x47:
+       case 0x49:
+       case 0x4b:
+               cp_ctx(ctx, 0x405018, 1);
+               gr_def(ctx, 0x405018, 0x08e00001);
+               cp_ctx(ctx, 0x405c24, 1);
+               gr_def(ctx, 0x405c24, 0x000e3000);
+               break;
+       }
+       if (dev_priv->chipset != 0x4e)
+               cp_ctx(ctx, 0x405800, 11);
+       cp_ctx(ctx, 0x407000, 1);
+}
+
+static void
+nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
+{
+       int len = nv40_graph_4097(ctx->dev) ? 0x0684 : 0x0084;
+
+       cp_out (ctx, 0x300000);
+       cp_lsr (ctx, len - 4);
+       cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_swap_state3d_3_is_save);
+       cp_lsr (ctx, len);
+       cp_name(ctx, cp_swap_state3d_3_is_save);
+       cp_out (ctx, 0x800001);
+
+       ctx->ctxvals_pos += len;
+}
+
+static void
+nv40_graph_construct_shader(struct nouveau_grctx *ctx)
+{
+       struct drm_device *dev = ctx->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *obj = ctx->data;
+       int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
+       int offset, i;
+
+       vs_nr    = nv40_graph_vs_count(ctx->dev);
+       vs_nr_b0 = 363;
+       vs_nr_b1 = dev_priv->chipset == 0x40 ? 128 : 64;
+       if (dev_priv->chipset == 0x40) {
+               b0_offset = 0x2200/4; /* 33a0 */
+               b1_offset = 0x55a0/4; /* 1500 */
+               vs_len = 0x6aa0/4;
+       } else
+       if (dev_priv->chipset == 0x41 || dev_priv->chipset == 0x42) {
+               b0_offset = 0x2200/4; /* 2200 */
+               b1_offset = 0x4400/4; /* 0b00 */
+               vs_len = 0x4f00/4;
+       } else {
+               b0_offset = 0x1d40/4; /* 2200 */
+               b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
+               vs_len = nv40_graph_4097(dev) ? 0x4a40/4 : 0x4980/4;
+       }
+
+       cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
+       cp_out(ctx, nv40_graph_4097(dev) ? 0x800041 : 0x800029);
+
+       offset = ctx->ctxvals_pos;
+       ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
+
+       if (ctx->mode != NOUVEAU_GRCTX_VALS)
+               return;
+
+       offset += 0x0280/4;
+       for (i = 0; i < 16; i++, offset += 2)
+               nv_wo32(dev, obj, offset, 0x3f800000);
+
+       for (vs = 0; vs < vs_nr; vs++, offset += vs_len) {
+               for (i = 0; i < vs_nr_b0 * 6; i += 6)
+                       nv_wo32(dev, obj, offset + b0_offset + i, 0x00000001);
+               for (i = 0; i < vs_nr_b1 * 4; i += 4)
+                       nv_wo32(dev, obj, offset + b1_offset + i, 0x3f800000);
+       }
+}
+
+void
+nv40_grctx_init(struct nouveau_grctx *ctx)
+{
+       /* decide whether we're loading/unloading the context */
+       cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
+       cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
+
+       cp_name(ctx, cp_check_load);
+       cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
+       cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
+       cp_bra (ctx, ALWAYS, TRUE, cp_exit);
+
+       /* setup for context load */
+       cp_name(ctx, cp_setup_auto_load);
+       cp_wait(ctx, STATUS, IDLE);
+       cp_out (ctx, CP_NEXT_TO_SWAP);
+       cp_name(ctx, cp_setup_load);
+       cp_wait(ctx, STATUS, IDLE);
+       cp_set (ctx, SWAP_DIRECTION, LOAD);
+       cp_out (ctx, 0x00910880); /* ?? */
+       cp_out (ctx, 0x00901ffe); /* ?? */
+       cp_out (ctx, 0x01940000); /* ?? */
+       cp_lsr (ctx, 0x20);
+       cp_out (ctx, 0x0060000b); /* ?? */
+       cp_wait(ctx, UNK57, CLEAR);
+       cp_out (ctx, 0x0060000c); /* ?? */
+       cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);
+
+       /* setup for context save */
+       cp_name(ctx, cp_setup_save);
+       cp_set (ctx, SWAP_DIRECTION, SAVE);
+
+       /* general PGRAPH state */
+       cp_name(ctx, cp_swap_state);
+       cp_pos (ctx, 0x00020/4);
+       nv40_graph_construct_general(ctx);
+       cp_wait(ctx, STATUS, IDLE);
+
+       /* 3D state, block 1 */
+       cp_bra (ctx, UNK54, CLEAR, cp_prepare_exit);
+       nv40_graph_construct_state3d(ctx);
+       cp_wait(ctx, STATUS, IDLE);
+
+       /* 3D state, block 2 */
+       nv40_graph_construct_state3d_2(ctx);
+
+       /* Some other block of "random" state */
+       nv40_graph_construct_state3d_3(ctx);
+
+       /* Per-vertex shader state */
+       cp_pos (ctx, ctx->ctxvals_pos);
+       nv40_graph_construct_shader(ctx);
+
+       /* pre-exit state updates */
+       cp_name(ctx, cp_prepare_exit);
+       cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
+       cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
+       cp_out (ctx, CP_NEXT_TO_CURRENT);
+
+       cp_name(ctx, cp_exit);
+       cp_set (ctx, USER_SAVE, NOT_PENDING);
+       cp_set (ctx, USER_LOAD, NOT_PENDING);
+       cp_out (ctx, CP_END);
+}
+
index f8e28a1..118d328 100644 (file)
@@ -45,7 +45,7 @@ nv50_crtc_lut_load(struct drm_crtc *crtc)
        void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo);
        int i;
 
-       NV_DEBUG(crtc->dev, "\n");
+       NV_DEBUG_KMS(crtc->dev, "\n");
 
        for (i = 0; i < 256; i++) {
                writew(nv_crtc->lut.r[i] >> 2, lut + 8*i + 0);
@@ -68,8 +68,8 @@ nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked)
        struct nouveau_channel *evo = dev_priv->evo;
        int index = nv_crtc->index, ret;
 
-       NV_DEBUG(dev, "index %d\n", nv_crtc->index);
-       NV_DEBUG(dev, "%s\n", blanked ? "blanked" : "unblanked");
+       NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+       NV_DEBUG_KMS(dev, "%s\n", blanked ? "blanked" : "unblanked");
 
        if (blanked) {
                nv_crtc->cursor.hide(nv_crtc, false);
@@ -139,7 +139,7 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update)
        struct nouveau_channel *evo = dev_priv->evo;
        int ret;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        ret = RING_SPACE(evo, 2 + (update ? 2 : 0));
        if (ret) {
@@ -193,7 +193,7 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update)
        uint32_t outX, outY, horiz, vert;
        int ret;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        switch (scaling_mode) {
        case DRM_MODE_SCALE_NONE:
@@ -301,7 +301,7 @@ nv50_crtc_destroy(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        if (!crtc)
                return;
@@ -433,7 +433,7 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        struct drm_encoder *encoder;
 
-       NV_DEBUG(dev, "index %d\n", nv_crtc->index);
+       NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
 
        /* Disconnect all unused encoders. */
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
@@ -458,7 +458,7 @@ nv50_crtc_commit(struct drm_crtc *crtc)
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        int ret;
 
-       NV_DEBUG(dev, "index %d\n", nv_crtc->index);
+       NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
 
        nv50_crtc_blank(nv_crtc, false);
 
@@ -497,7 +497,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, int x, int y,
        struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
        int ret, format;
 
-       NV_DEBUG(dev, "index %d\n", nv_crtc->index);
+       NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
 
        switch (drm_fb->depth) {
        case  8:
@@ -612,7 +612,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 
        *nv_crtc->mode = *adjusted_mode;
 
-       NV_DEBUG(dev, "index %d\n", nv_crtc->index);
+       NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
 
        hsync_dur = adjusted_mode->hsync_end - adjusted_mode->hsync_start;
        vsync_dur = adjusted_mode->vsync_end - adjusted_mode->vsync_start;
@@ -706,7 +706,7 @@ nv50_crtc_create(struct drm_device *dev, int index)
        struct nouveau_crtc *nv_crtc = NULL;
        int ret, i;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL);
        if (!nv_crtc)
index e2e79a8..753e723 100644 (file)
@@ -41,7 +41,7 @@ nv50_cursor_show(struct nouveau_crtc *nv_crtc, bool update)
        struct drm_device *dev = nv_crtc->base.dev;
        int ret;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        if (update && nv_crtc->cursor.visible)
                return;
@@ -76,7 +76,7 @@ nv50_cursor_hide(struct nouveau_crtc *nv_crtc, bool update)
        struct drm_device *dev = nv_crtc->base.dev;
        int ret;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        if (update && !nv_crtc->cursor.visible)
                return;
@@ -116,7 +116,7 @@ nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
 static void
 nv50_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset)
 {
-       NV_DEBUG(nv_crtc->base.dev, "\n");
+       NV_DEBUG_KMS(nv_crtc->base.dev, "\n");
        if (offset == nv_crtc->cursor.offset)
                return;
 
@@ -143,7 +143,7 @@ nv50_cursor_fini(struct nouveau_crtc *nv_crtc)
        struct drm_device *dev = nv_crtc->base.dev;
        int idx = nv_crtc->index;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0);
        if (!nv_wait(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx),
index fb5838e..f08f042 100644 (file)
@@ -44,7 +44,7 @@ nv50_dac_disconnect(struct nouveau_encoder *nv_encoder)
        struct nouveau_channel *evo = dev_priv->evo;
        int ret;
 
-       NV_DEBUG(dev, "Disconnecting DAC %d\n", nv_encoder->or);
+       NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
 
        ret = RING_SPACE(evo, 2);
        if (ret) {
@@ -81,11 +81,11 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
        /* Use bios provided value if possible. */
        if (dev_priv->vbios->dactestval) {
                load_pattern = dev_priv->vbios->dactestval;
-               NV_DEBUG(dev, "Using bios provided load_pattern of %d\n",
+               NV_DEBUG_KMS(dev, "Using bios provided load_pattern of %d\n",
                          load_pattern);
        } else {
                load_pattern = 340;
-               NV_DEBUG(dev, "Using default load_pattern of %d\n",
+               NV_DEBUG_KMS(dev, "Using default load_pattern of %d\n",
                         load_pattern);
        }
 
@@ -103,9 +103,9 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
                status = connector_status_connected;
 
        if (status == connector_status_connected)
-               NV_DEBUG(dev, "Load was detected on output with or %d\n", or);
+               NV_DEBUG_KMS(dev, "Load was detected on output with or %d\n", or);
        else
-               NV_DEBUG(dev, "Load was not detected on output with or %d\n", or);
+               NV_DEBUG_KMS(dev, "Load was not detected on output with or %d\n", or);
 
        return status;
 }
@@ -118,7 +118,7 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode)
        uint32_t val;
        int or = nv_encoder->or;
 
-       NV_DEBUG(dev, "or %d mode %d\n", or, mode);
+       NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
 
        /* wait for it to be done */
        if (!nv_wait(NV50_PDISPLAY_DAC_DPMS_CTRL(or),
@@ -173,7 +173,7 @@ nv50_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nouveau_connector *connector;
 
-       NV_DEBUG(encoder->dev, "or %d\n", nv_encoder->or);
+       NV_DEBUG_KMS(encoder->dev, "or %d\n", nv_encoder->or);
 
        connector = nouveau_encoder_connector_get(nv_encoder);
        if (!connector) {
@@ -213,7 +213,7 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        uint32_t mode_ctl = 0, mode_ctl2 = 0;
        int ret;
 
-       NV_DEBUG(dev, "or %d\n", nv_encoder->or);
+       NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
 
        nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
 
@@ -264,7 +264,7 @@ nv50_dac_destroy(struct drm_encoder *encoder)
        if (!encoder)
                return;
 
-       NV_DEBUG(encoder->dev, "\n");
+       NV_DEBUG_KMS(encoder->dev, "\n");
 
        drm_encoder_cleanup(encoder);
        kfree(nv_encoder);
@@ -280,7 +280,7 @@ nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
        struct nouveau_encoder *nv_encoder;
        struct drm_encoder *encoder;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
        NV_INFO(dev, "Detected a DAC output\n");
 
        nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
index 12c5ee6..a9263d9 100644 (file)
@@ -188,7 +188,7 @@ nv50_display_init(struct drm_device *dev)
        uint64_t start;
        int ret, i;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        nv_wr32(dev, 0x00610184, nv_rd32(dev, 0x00614004));
        /*
@@ -232,7 +232,7 @@ nv50_display_init(struct drm_device *dev)
        nv_wr32(dev, NV50_PDISPLAY_UNK_380, 0);
        /* RAM is clamped to 256 MiB. */
        ram_amount = nouveau_mem_fb_amount(dev);
-       NV_DEBUG(dev, "ram_amount %d\n", ram_amount);
+       NV_DEBUG_KMS(dev, "ram_amount %d\n", ram_amount);
        if (ram_amount > 256*1024*1024)
                ram_amount = 256*1024*1024;
        nv_wr32(dev, NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1);
@@ -398,7 +398,7 @@ static int nv50_display_disable(struct drm_device *dev)
        struct drm_crtc *drm_crtc;
        int ret, i;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_crtc *crtc = nouveau_crtc(drm_crtc);
@@ -469,7 +469,7 @@ int nv50_display_create(struct drm_device *dev)
        uint32_t connector[16] = {};
        int ret, i;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        /* init basic kernel modesetting */
        drm_mode_config_init(dev);
@@ -573,7 +573,7 @@ int nv50_display_destroy(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        drm_mode_config_cleanup(dev);
 
@@ -617,7 +617,7 @@ nv50_display_irq_head(struct drm_device *dev, int *phead,
         * CRTC separately, and submission will be blocked by the GPU
         * until we handle each in turn.
         */
-       NV_DEBUG(dev, "0x610030: 0x%08x\n", unk30);
+       NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
        head = ffs((unk30 >> 9) & 3) - 1;
        if (head < 0)
                return -EINVAL;
@@ -661,7 +661,7 @@ nv50_display_irq_head(struct drm_device *dev, int *phead,
                or = i;
        }
 
-       NV_DEBUG(dev, "type %d, or %d\n", type, or);
+       NV_DEBUG_KMS(dev, "type %d, or %d\n", type, or);
        if (type == OUTPUT_ANY) {
                NV_ERROR(dev, "unknown encoder!!\n");
                return -1;
@@ -811,7 +811,7 @@ nv50_display_unk20_handler(struct drm_device *dev)
        pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
        script = nv50_display_script_select(dev, dcbent, pclk);
 
-       NV_DEBUG(dev, "head %d pxclk: %dKHz\n", head, pclk);
+       NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk);
 
        if (dcbent->type != OUTPUT_DP)
                nouveau_bios_run_display_table(dev, dcbent, 0, -2);
@@ -870,7 +870,7 @@ nv50_display_irq_handler_bh(struct work_struct *work)
                uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
                uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
 
-               NV_DEBUG(dev, "PDISPLAY_INTR_BH 0x%08x 0x%08x\n", intr0, intr1);
+               NV_DEBUG_KMS(dev, "PDISPLAY_INTR_BH 0x%08x 0x%08x\n", intr0, intr1);
 
                if (intr1 & NV50_PDISPLAY_INTR_1_CLK_UNK10)
                        nv50_display_unk10_handler(dev);
@@ -974,7 +974,7 @@ nv50_display_irq_handler(struct drm_device *dev)
                uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1);
                uint32_t clock;
 
-               NV_DEBUG(dev, "PDISPLAY_INTR 0x%08x 0x%08x\n", intr0, intr1);
+               NV_DEBUG_KMS(dev, "PDISPLAY_INTR 0x%08x 0x%08x\n", intr0, intr1);
 
                if (!intr0 && !(intr1 & ~delayed))
                        break;
index 77ae1aa..b728228 100644 (file)
@@ -416,7 +416,7 @@ nv50_fifo_unload_context(struct drm_device *dev)
        NV_DEBUG(dev, "\n");
 
        chid = pfifo->channel_id(dev);
-       if (chid < 0 || chid >= dev_priv->engine.fifo.channels)
+       if (chid < 1 || chid >= dev_priv->engine.fifo.channels - 1)
                return 0;
 
        chan = dev_priv->fifos[chid];
index 177d822..ca79f32 100644 (file)
@@ -107,9 +107,13 @@ nv50_graph_init_regs(struct drm_device *dev)
 static int
 nv50_graph_init_ctxctl(struct drm_device *dev)
 {
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
        NV_DEBUG(dev, "\n");
 
-       nv40_grctx_init(dev);
+       nouveau_grctx_prog_load(dev);
+       if (!dev_priv->engine.graph.ctxprog)
+               dev_priv->engine.graph.accel_blocked = true;
 
        nv_wr32(dev, 0x400320, 4);
        nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0);
@@ -140,7 +144,7 @@ void
 nv50_graph_takedown(struct drm_device *dev)
 {
        NV_DEBUG(dev, "\n");
-       nv40_grctx_fini(dev);
+       nouveau_grctx_fini(dev);
 }
 
 void
@@ -207,7 +211,7 @@ nv50_graph_create_context(struct nouveau_channel *chan)
        dev_priv->engine.instmem.finish_access(dev);
 
        dev_priv->engine.instmem.prepare_access(dev, true);
-       nv40_grctx_vals_load(dev, ctx);
+       nouveau_grctx_vals_load(dev, ctx);
        nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12);
        if ((dev_priv->chipset & 0xf0) == 0xa0)
                nv_wo32(dev, ctx, 0x00004/4, 0x00000000);
index 8c28046..e395c16 100644 (file)
@@ -44,7 +44,7 @@ nv50_sor_disconnect(struct nouveau_encoder *nv_encoder)
        struct nouveau_channel *evo = dev_priv->evo;
        int ret;
 
-       NV_DEBUG(dev, "Disconnecting SOR %d\n", nv_encoder->or);
+       NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
 
        ret = RING_SPACE(evo, 2);
        if (ret) {
@@ -70,7 +70,7 @@ nv50_sor_dp_link_train(struct drm_encoder *encoder)
        }
 
        if (dpe->script0) {
-               NV_DEBUG(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
+               NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
                nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
                                            nv_encoder->dcb);
        }
@@ -79,7 +79,7 @@ nv50_sor_dp_link_train(struct drm_encoder *encoder)
                NV_ERROR(dev, "SOR-%d: link training failed\n", nv_encoder->or);
 
        if (dpe->script1) {
-               NV_DEBUG(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
+               NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
                nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
                                            nv_encoder->dcb);
        }
@@ -93,7 +93,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
        uint32_t val;
        int or = nv_encoder->or;
 
-       NV_DEBUG(dev, "or %d mode %d\n", or, mode);
+       NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
 
        /* wait for it to be done */
        if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or),
@@ -142,7 +142,7 @@ nv50_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
        struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
        struct nouveau_connector *connector;
 
-       NV_DEBUG(encoder->dev, "or %d\n", nv_encoder->or);
+       NV_DEBUG_KMS(encoder->dev, "or %d\n", nv_encoder->or);
 
        connector = nouveau_encoder_connector_get(nv_encoder);
        if (!connector) {
@@ -182,7 +182,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        uint32_t mode_ctl = 0;
        int ret;
 
-       NV_DEBUG(dev, "or %d\n", nv_encoder->or);
+       NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
 
        nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
 
@@ -246,7 +246,7 @@ nv50_sor_destroy(struct drm_encoder *encoder)
        if (!encoder)
                return;
 
-       NV_DEBUG(encoder->dev, "\n");
+       NV_DEBUG_KMS(encoder->dev, "\n");
 
        drm_encoder_cleanup(encoder);
 
@@ -265,7 +265,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
        bool dum;
        int type;
 
-       NV_DEBUG(dev, "\n");
+       NV_DEBUG_KMS(dev, "\n");
 
        switch (entry->type) {
        case OUTPUT_TMDS:
index 601f4c0..b806fdc 100644 (file)
@@ -64,7 +64,7 @@ static struct drm_driver driver = {
                .owner = THIS_MODULE,
                .open = drm_open,
                .release = drm_release,
-               .ioctl = drm_ioctl,
+               .unlocked_ioctl = drm_ioctl,
                .mmap = drm_mmap,
                .poll = drm_poll,
                .fasync = drm_fasync,
index d3cb676..51c99fc 100644 (file)
@@ -95,8 +95,7 @@ static int compat_r128_init(struct file *file, unsigned int cmd,
                          &init->agp_textures_offset))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_R128_INIT, (unsigned long)init);
+       return drm_ioctl(file, DRM_IOCTL_R128_INIT, (unsigned long)init);
 }
 
 typedef struct drm_r128_depth32 {
@@ -129,8 +128,7 @@ static int compat_r128_depth(struct file *file, unsigned int cmd,
                          &depth->mask))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_R128_DEPTH, (unsigned long)depth);
+       return drm_ioctl(file, DRM_IOCTL_R128_DEPTH, (unsigned long)depth);
 
 }
 
@@ -153,8 +151,7 @@ static int compat_r128_stipple(struct file *file, unsigned int cmd,
                          &stipple->mask))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
+       return drm_ioctl(file, DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
 }
 
 typedef struct drm_r128_getparam32 {
@@ -178,8 +175,7 @@ static int compat_r128_getparam(struct file *file, unsigned int cmd,
                          &getparam->value))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
+       return drm_ioctl(file, DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
 }
 
 drm_ioctl_compat_t *r128_compat_ioctls[] = {
@@ -210,12 +206,10 @@ long r128_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(r128_compat_ioctls))
                fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE];
 
-       lock_kernel();          /* XXX for now */
        if (fn != NULL)
                ret = (*fn) (filp, cmd, arg);
        else
-               ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
-       unlock_kernel();
+               ret = drm_ioctl(filp, cmd, arg);
 
        return ret;
 }
index 6578d19..388140a 100644 (file)
@@ -58,6 +58,7 @@ typedef struct {
 } atom_exec_context;
 
 int atom_debug = 0;
+static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params);
 void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
 
 static uint32_t atom_arg_mask[8] =
@@ -573,7 +574,7 @@ static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
        else
                SDEBUG("   table: %d\n", idx);
        if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
-               atom_execute_table(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
+               atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
 }
 
 static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
@@ -1040,7 +1041,7 @@ static struct {
        atom_op_shr, ATOM_ARG_MC}, {
 atom_op_debug, 0},};
 
-void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
+static void atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t * params)
 {
        int base = CU16(ctx->cmd_table + 4 + 2 * index);
        int len, ws, ps, ptr;
@@ -1092,6 +1093,13 @@ void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
                kfree(ectx.ws);
 }
 
+void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
+{
+       mutex_lock(&ctx->mutex);
+       atom_execute_table_locked(ctx, index, params);
+       mutex_unlock(&ctx->mutex);
+}
+
 static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
 
 static void atom_index_iio(struct atom_context *ctx, int base)
index 6671848..47fd943 100644 (file)
@@ -120,6 +120,7 @@ struct card_info {
 
 struct atom_context {
        struct card_info *card;
+       struct mutex mutex;
        void *bios;
        uint32_t cmd_table, data_table;
        uint16_t *iio;
index 5f48515..91ad0d1 100644 (file)
@@ -4690,6 +4690,205 @@ typedef struct _ATOM_POWERPLAY_INFO_V3 {
        ATOM_POWERMODE_INFO_V3 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
 } ATOM_POWERPLAY_INFO_V3;
 
+/* New PPlib */
+/**************************************************************************/
+typedef struct _ATOM_PPLIB_THERMALCONTROLLER
+
+{
+    UCHAR ucType;           // one of ATOM_PP_THERMALCONTROLLER_*
+    UCHAR ucI2cLine;        // as interpreted by DAL I2C
+    UCHAR ucI2cAddress;
+    UCHAR ucFanParameters;  // Fan Control Parameters.
+    UCHAR ucFanMinRPM;      // Fan Minimum RPM (hundreds) -- for display purposes only.
+    UCHAR ucFanMaxRPM;      // Fan Maximum RPM (hundreds) -- for display purposes only.
+    UCHAR ucReserved;       // ----
+    UCHAR ucFlags;          // to be defined
+} ATOM_PPLIB_THERMALCONTROLLER;
+
+#define ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK 0x0f
+#define ATOM_PP_FANPARAMETERS_NOFAN                                 0x80    // No fan is connected to this controller.
+
+#define ATOM_PP_THERMALCONTROLLER_NONE      0
+#define ATOM_PP_THERMALCONTROLLER_LM63      1  // Not used by PPLib
+#define ATOM_PP_THERMALCONTROLLER_ADM1032   2  // Not used by PPLib
+#define ATOM_PP_THERMALCONTROLLER_ADM1030   3  // Not used by PPLib
+#define ATOM_PP_THERMALCONTROLLER_MUA6649   4  // Not used by PPLib
+#define ATOM_PP_THERMALCONTROLLER_LM64      5
+#define ATOM_PP_THERMALCONTROLLER_F75375    6  // Not used by PPLib
+#define ATOM_PP_THERMALCONTROLLER_RV6xx     7
+#define ATOM_PP_THERMALCONTROLLER_RV770     8
+#define ATOM_PP_THERMALCONTROLLER_ADT7473   9
+
+typedef struct _ATOM_PPLIB_STATE
+{
+    UCHAR ucNonClockStateIndex;
+    UCHAR ucClockStateIndices[1]; // variable-sized
+} ATOM_PPLIB_STATE;
+
+//// ATOM_PPLIB_POWERPLAYTABLE::ulPlatformCaps
+#define ATOM_PP_PLATFORM_CAP_BACKBIAS 1
+#define ATOM_PP_PLATFORM_CAP_POWERPLAY 2
+#define ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE 4
+#define ATOM_PP_PLATFORM_CAP_ASPM_L0s 8
+#define ATOM_PP_PLATFORM_CAP_ASPM_L1 16
+#define ATOM_PP_PLATFORM_CAP_HARDWAREDC 32
+#define ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY 64
+#define ATOM_PP_PLATFORM_CAP_STEPVDDC 128
+#define ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL 256
+#define ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL 512
+#define ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 1024
+#define ATOM_PP_PLATFORM_CAP_HTLINKCONTROL 2048
+
+typedef struct _ATOM_PPLIB_POWERPLAYTABLE
+{
+      ATOM_COMMON_TABLE_HEADER sHeader;
+
+      UCHAR ucDataRevision;
+
+      UCHAR ucNumStates;
+      UCHAR ucStateEntrySize;
+      UCHAR ucClockInfoSize;
+      UCHAR ucNonClockSize;
+
+      // offset from start of this table to array of ucNumStates ATOM_PPLIB_STATE structures
+      USHORT usStateArrayOffset;
+
+      // offset from start of this table to array of ASIC-specific structures,
+      // currently ATOM_PPLIB_CLOCK_INFO.
+      USHORT usClockInfoArrayOffset;
+
+      // offset from start of this table to array of ATOM_PPLIB_NONCLOCK_INFO
+      USHORT usNonClockInfoArrayOffset;
+
+      USHORT usBackbiasTime;    // in microseconds
+      USHORT usVoltageTime;     // in microseconds
+      USHORT usTableSize;       //the size of this structure, or the extended structure
+
+      ULONG ulPlatformCaps;            // See ATOM_PPLIB_CAPS_*
+
+      ATOM_PPLIB_THERMALCONTROLLER    sThermalController;
+
+      USHORT usBootClockInfoOffset;
+      USHORT usBootNonClockInfoOffset;
+
+} ATOM_PPLIB_POWERPLAYTABLE;
+
+//// ATOM_PPLIB_NONCLOCK_INFO::usClassification
+#define ATOM_PPLIB_CLASSIFICATION_UI_MASK          0x0007
+#define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT         0
+#define ATOM_PPLIB_CLASSIFICATION_UI_NONE          0
+#define ATOM_PPLIB_CLASSIFICATION_UI_BATTERY       1
+#define ATOM_PPLIB_CLASSIFICATION_UI_BALANCED      3
+#define ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE   5
+// 2, 4, 6, 7 are reserved
+
+#define ATOM_PPLIB_CLASSIFICATION_BOOT                   0x0008
+#define ATOM_PPLIB_CLASSIFICATION_THERMAL                0x0010
+#define ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE     0x0020
+#define ATOM_PPLIB_CLASSIFICATION_REST                   0x0040
+#define ATOM_PPLIB_CLASSIFICATION_FORCED                 0x0080
+#define ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE          0x0100
+#define ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE      0x0200
+#define ATOM_PPLIB_CLASSIFICATION_UVDSTATE               0x0400
+#define ATOM_PPLIB_CLASSIFICATION_3DLOW                  0x0800
+#define ATOM_PPLIB_CLASSIFICATION_ACPI                   0x1000
+// remaining 3 bits are reserved
+
+//// ATOM_PPLIB_NONCLOCK_INFO::ulCapsAndSettings
+#define ATOM_PPLIB_SINGLE_DISPLAY_ONLY           0x00000001
+#define ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK         0x00000002
+
+// 0 is 2.5Gb/s, 1 is 5Gb/s
+#define ATOM_PPLIB_PCIE_LINK_SPEED_MASK            0x00000004
+#define ATOM_PPLIB_PCIE_LINK_SPEED_SHIFT           2
+
+// lanes - 1: 1, 2, 4, 8, 12, 16 permitted by PCIE spec
+#define ATOM_PPLIB_PCIE_LINK_WIDTH_MASK            0x000000F8
+#define ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT           3
+
+// lookup into reduced refresh-rate table
+#define ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK  0x00000F00
+#define ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT 8
+
+#define ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED    0
+#define ATOM_PPLIB_LIMITED_REFRESHRATE_50HZ         1
+// 2-15 TBD as needed.
+
+#define ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING        0x00001000
+#define ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS  0x00002000
+#define ATOM_PPLIB_ENABLE_VARIBRIGHT                     0x00008000
+
+#define ATOM_PPLIB_DISALLOW_ON_DC                       0x00004000
+
+// Contained in an array starting at the offset
+// in ATOM_PPLIB_POWERPLAYTABLE::usNonClockInfoArrayOffset.
+// referenced from ATOM_PPLIB_STATE_INFO::ucNonClockStateIndex
+typedef struct _ATOM_PPLIB_NONCLOCK_INFO
+{
+      USHORT usClassification;
+      UCHAR  ucMinTemperature;
+      UCHAR  ucMaxTemperature;
+      ULONG  ulCapsAndSettings;
+      UCHAR  ucRequiredPower;
+      UCHAR  ucUnused1[3];
+} ATOM_PPLIB_NONCLOCK_INFO;
+
+// Contained in an array starting at the offset
+// in ATOM_PPLIB_POWERPLAYTABLE::usClockInfoArrayOffset.
+// referenced from ATOM_PPLIB_STATE::ucClockStateIndices
+typedef struct _ATOM_PPLIB_R600_CLOCK_INFO
+{
+      USHORT usEngineClockLow;
+      UCHAR ucEngineClockHigh;
+
+      USHORT usMemoryClockLow;
+      UCHAR ucMemoryClockHigh;
+
+      USHORT usVDDC;
+      USHORT usUnused1;
+      USHORT usUnused2;
+
+      ULONG ulFlags; // ATOM_PPLIB_R600_FLAGS_*
+
+} ATOM_PPLIB_R600_CLOCK_INFO;
+
+// ulFlags in ATOM_PPLIB_R600_CLOCK_INFO
+#define ATOM_PPLIB_R600_FLAGS_PCIEGEN2          1
+#define ATOM_PPLIB_R600_FLAGS_UVDSAFE           2
+#define ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE    4
+#define ATOM_PPLIB_R600_FLAGS_MEMORY_ODT_OFF    8
+#define ATOM_PPLIB_R600_FLAGS_MEMORY_DLL_OFF    16
+
+typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
+
+{
+      USHORT usLowEngineClockLow;         // Low Engine clock in MHz (the same way as on the R600).
+      UCHAR  ucLowEngineClockHigh;
+      USHORT usHighEngineClockLow;        // High Engine clock in MHz.
+      UCHAR  ucHighEngineClockHigh;
+      USHORT usMemoryClockLow;            // For now one of the ATOM_PPLIB_RS780_SPMCLK_XXXX constants.
+      UCHAR  ucMemoryClockHigh;           // Currentyl unused.
+      UCHAR  ucPadding;                   // For proper alignment and size.
+      USHORT usVDDC;                      // For the 780, use: None, Low, High, Variable
+      UCHAR  ucMaxHTLinkWidth;            // From SBIOS - {2, 4, 8, 16}
+      UCHAR  ucMinHTLinkWidth;            // From SBIOS - {2, 4, 8, 16}. Effective only if CDLW enabled. Minimum down stream width could be bigger as display BW requriement.
+      USHORT usHTLinkFreq;                // See definition ATOM_PPLIB_RS780_HTLINKFREQ_xxx or in MHz(>=200).
+      ULONG  ulFlags;
+} ATOM_PPLIB_RS780_CLOCK_INFO;
+
+#define ATOM_PPLIB_RS780_VOLTAGE_NONE       0
+#define ATOM_PPLIB_RS780_VOLTAGE_LOW        1
+#define ATOM_PPLIB_RS780_VOLTAGE_HIGH       2
+#define ATOM_PPLIB_RS780_VOLTAGE_VARIABLE   3
+
+#define ATOM_PPLIB_RS780_SPMCLK_NONE        0   // We cannot change the side port memory clock, leave it as it is.
+#define ATOM_PPLIB_RS780_SPMCLK_LOW         1
+#define ATOM_PPLIB_RS780_SPMCLK_HIGH        2
+
+#define ATOM_PPLIB_RS780_HTLINKFREQ_NONE       0
+#define ATOM_PPLIB_RS780_HTLINKFREQ_LOW        1
+#define ATOM_PPLIB_RS780_HTLINKFREQ_HIGH       2
+
 /**************************************************************************/
 
 /*  Following definitions are for compatiblity issue in different SW components. */
index 84e5df7..7172746 100644 (file)
@@ -2881,6 +2881,10 @@ int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track)
 
        for (i = 0; i < track->num_cb; i++) {
                if (track->cb[i].robj == NULL) {
+                       if (!(track->fastfill || track->color_channel_mask ||
+                             track->blend_read_enable)) {
+                               continue;
+                       }
                        DRM_ERROR("[drm] No buffer for color buffer %d !\n", i);
                        return -EINVAL;
                }
index 7188c37..b27a699 100644 (file)
@@ -67,13 +67,15 @@ struct r100_cs_track {
        unsigned                        immd_dwords;
        unsigned                        num_arrays;
        unsigned                        max_indx;
+       unsigned                        color_channel_mask;
        struct r100_cs_track_array      arrays[11];
        struct r100_cs_track_cb         cb[R300_MAX_CB];
        struct r100_cs_track_cb         zb;
        struct r100_cs_track_texture    textures[R300_TRACK_MAX_TEXTURE];
        bool                            z_enabled;
        bool                            separate_cube;
-
+       bool                            fastfill;
+       bool                            blend_read_enable;
 };
 
 int r100_cs_track_check(struct radeon_device *rdev, struct r100_cs_track *track);
index 83490c2..3f2cc9e 100644 (file)
@@ -887,6 +887,14 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].cpp = 1;
                        track->textures[i].compress_format = R100_TRACK_COMP_DXT1;
                        break;
+               case R300_TX_FORMAT_ATI2N:
+                       if (p->rdev->family < CHIP_R420) {
+                               DRM_ERROR("Invalid texture format %u\n",
+                                         (idx_value & 0x1F));
+                               return -EINVAL;
+                       }
+                       /* The same rules apply as for DXT3/5. */
+                       /* Pass through. */
                case R300_TX_FORMAT_DXT3:
                case R300_TX_FORMAT_DXT5:
                        track->textures[i].cpp = 1;
@@ -951,6 +959,16 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        track->textures[i].width_11 = tmp;
                        tmp = ((idx_value >> 16) & 1) << 11;
                        track->textures[i].height_11 = tmp;
+
+                       /* ATI1N */
+                       if (idx_value & (1 << 14)) {
+                               /* The same rules apply as for DXT1. */
+                               track->textures[i].compress_format =
+                                       R100_TRACK_COMP_DXT1;
+                       }
+               } else if (idx_value & (1 << 14)) {
+                       DRM_ERROR("Forbidden bit TXFORMAT_MSB\n");
+                       return -EINVAL;
                }
                break;
        case 0x4480:
@@ -992,6 +1010,18 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                }
                ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
                break;
+       case 0x4e0c:
+               /* RB3D_COLOR_CHANNEL_MASK */
+               track->color_channel_mask = idx_value;
+               break;
+       case 0x4d1c:
+               /* ZB_BW_CNTL */
+               track->fastfill = !!(idx_value & (1 << 2));
+               break;
+       case 0x4e04:
+               /* RB3D_BLENDCNTL */
+               track->blend_read_enable = !!(idx_value & (1 << 2));
+               break;
        case 0x4be8:
                /* valid register only on RV530 */
                if (p->rdev->family == CHIP_RV530)
index cb2e470..34bffa0 100644 (file)
@@ -990,7 +990,7 @@ static inline int r300_emit_r500fp(drm_radeon_private_t *dev_priv,
        int sz;
        int addr;
        int type;
-       int clamp;
+       int isclamp;
        int stride;
        RING_LOCALS;
 
@@ -999,10 +999,10 @@ static inline int r300_emit_r500fp(drm_radeon_private_t *dev_priv,
        addr = ((header.r500fp.adrhi_flags & 1) << 8) | header.r500fp.adrlo;
 
        type = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_TYPE);
-       clamp = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_CLAMP);
+       isclamp = !!(header.r500fp.adrhi_flags & R500FP_CONSTANT_CLAMP);
 
        addr |= (type << 16);
-       addr |= (clamp << 17);
+       addr |= (isclamp << 17);
 
        stride = type ? 4 : 6;
 
index 4b7afef..1735a2b 100644 (file)
 #      define R300_TX_FORMAT_FL_I32                0x1B
 #      define R300_TX_FORMAT_FL_I32A32             0x1C
 #      define R300_TX_FORMAT_FL_R32G32B32A32       0x1D
+#      define R300_TX_FORMAT_ATI2N                 0x1F
        /* alpha modes, convenience mostly */
        /* if you have alpha, pick constant appropriate to the
           number of channels (1 for I8, 2 for I8A8, 4 for R8G8B8A8, etc */
index 0d82076..44060b9 100644 (file)
@@ -170,7 +170,7 @@ static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p,
                          idx, relocs_chunk->length_dw);
                return -EINVAL;
        }
-       *cs_reloc = &p->relocs[0];
+       *cs_reloc = p->relocs;
        (*cs_reloc)->lobj.gpu_offset = (u64)relocs_chunk->kdata[idx + 3] << 32;
        (*cs_reloc)->lobj.gpu_offset |= relocs_chunk->kdata[idx + 0];
        return 0;
@@ -717,7 +717,7 @@ static int r600_cs_parser_relocs_legacy(struct radeon_cs_parser *p)
        if (p->chunk_relocs_idx == -1) {
                return 0;
        }
-       p->relocs = kcalloc(1, sizeof(struct radeon_cs_reloc), GFP_KERNEL);
+       p->relocs = kzalloc(sizeof(struct radeon_cs_reloc), GFP_KERNEL);
        if (p->relocs == NULL) {
                return -ENOMEM;
        }
index cd650fd..53b5560 100644 (file)
@@ -162,6 +162,7 @@ struct radeon_fence_driver {
        struct list_head                created;
        struct list_head                emited;
        struct list_head                signaled;
+       bool                            initialized;
 };
 
 struct radeon_fence {
@@ -202,8 +203,9 @@ struct radeon_surface_reg {
 struct radeon_mman {
        struct ttm_bo_global_ref        bo_global_ref;
        struct ttm_global_reference     mem_global_ref;
-       bool                            mem_global_referenced;
        struct ttm_bo_device            bdev;
+       bool                            mem_global_referenced;
+       bool                            initialized;
 };
 
 struct radeon_bo {
index 636116b..eb29217 100644 (file)
@@ -33,6 +33,7 @@
  */
 uint32_t radeon_legacy_get_engine_clock(struct radeon_device *rdev);
 void radeon_legacy_set_engine_clock(struct radeon_device *rdev, uint32_t eng_clock);
+uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev);
 void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable);
 
 uint32_t radeon_atom_get_engine_clock(struct radeon_device *rdev);
@@ -106,7 +107,7 @@ static struct radeon_asic r100_asic = {
        .copy = &r100_copy_blit,
        .get_engine_clock = &radeon_legacy_get_engine_clock,
        .set_engine_clock = &radeon_legacy_set_engine_clock,
-       .get_memory_clock = NULL,
+       .get_memory_clock = &radeon_legacy_get_memory_clock,
        .set_memory_clock = NULL,
        .set_pcie_lanes = NULL,
        .set_clock_gating = &radeon_legacy_set_clock_gating,
@@ -166,7 +167,7 @@ static struct radeon_asic r300_asic = {
        .copy = &r100_copy_blit,
        .get_engine_clock = &radeon_legacy_get_engine_clock,
        .set_engine_clock = &radeon_legacy_set_engine_clock,
-       .get_memory_clock = NULL,
+       .get_memory_clock = &radeon_legacy_get_memory_clock,
        .set_memory_clock = NULL,
        .set_pcie_lanes = &rv370_set_pcie_lanes,
        .set_clock_gating = &radeon_legacy_set_clock_gating,
@@ -259,7 +260,7 @@ static struct radeon_asic rs400_asic = {
        .copy = &r100_copy_blit,
        .get_engine_clock = &radeon_legacy_get_engine_clock,
        .set_engine_clock = &radeon_legacy_set_engine_clock,
-       .get_memory_clock = NULL,
+       .get_memory_clock = &radeon_legacy_get_memory_clock,
        .set_memory_clock = NULL,
        .set_pcie_lanes = NULL,
        .set_clock_gating = &radeon_legacy_set_clock_gating,
index 12a0c76..321044b 100644 (file)
@@ -745,8 +745,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
                else
                        radeon_add_legacy_encoder(dev,
                                                  radeon_get_encoder_id(dev,
-                                                                       (1 <<
-                                                                        i),
+                                                                       (1 << i),
                                                                        dac),
                                                  (1 << i));
        }
@@ -758,32 +757,30 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct
                                if (bios_connectors[j].valid && (i != j)) {
                                        if (bios_connectors[i].line_mux ==
                                            bios_connectors[j].line_mux) {
-                                               if (((bios_connectors[i].
-                                                     devices &
-                                                     (ATOM_DEVICE_DFP_SUPPORT))
-                                                    && (bios_connectors[j].
-                                                        devices &
-                                                        (ATOM_DEVICE_CRT_SUPPORT)))
-                                                   ||
-                                                   ((bios_connectors[j].
-                                                     devices &
-                                                     (ATOM_DEVICE_DFP_SUPPORT))
-                                                    && (bios_connectors[i].
-                                                        devices &
-                                                        (ATOM_DEVICE_CRT_SUPPORT)))) {
-                                                       bios_connectors[i].
-                                                           devices |=
-                                                           bios_connectors[j].
-                                                           devices;
-                                                       bios_connectors[i].
-                                                           connector_type =
-                                                           DRM_MODE_CONNECTOR_DVII;
-                                                       if (bios_connectors[j].devices &
-                                                           (ATOM_DEVICE_DFP_SUPPORT))
+                                               /* make sure not to combine LVDS */
+                                               if (bios_connectors[i].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+                                                       bios_connectors[i].line_mux = 53;
+                                                       bios_connectors[i].ddc_bus.valid = false;
+                                                       continue;
+                                               }
+                                               if (bios_connectors[j].devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+                                                       bios_connectors[j].line_mux = 53;
+                                                       bios_connectors[j].ddc_bus.valid = false;
+                                                       continue;
+                                               }
+                                               /* combine analog and digital for DVI-I */
+                                               if (((bios_connectors[i].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
+                                                    (bios_connectors[j].devices & (ATOM_DEVICE_CRT_SUPPORT))) ||
+                                                   ((bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT)) &&
+                                                    (bios_connectors[i].devices & (ATOM_DEVICE_CRT_SUPPORT)))) {
+                                                       bios_connectors[i].devices |=
+                                                               bios_connectors[j].devices;
+                                                       bios_connectors[i].connector_type =
+                                                               DRM_MODE_CONNECTOR_DVII;
+                                                       if (bios_connectors[j].devices & (ATOM_DEVICE_DFP_SUPPORT))
                                                                bios_connectors[i].hpd =
                                                                        bios_connectors[j].hpd;
-                                                       bios_connectors[j].
-                                                           valid = false;
+                                                       bios_connectors[j].valid = false;
                                                }
                                        }
                                }
@@ -1234,6 +1231,61 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
        return true;
 }
 
+enum radeon_tv_std
+radeon_atombios_get_tv_info(struct radeon_device *rdev)
+{
+       struct radeon_mode_info *mode_info = &rdev->mode_info;
+       int index = GetIndexIntoMasterTable(DATA, AnalogTV_Info);
+       uint16_t data_offset;
+       uint8_t frev, crev;
+       struct _ATOM_ANALOG_TV_INFO *tv_info;
+       enum radeon_tv_std tv_std = TV_STD_NTSC;
+
+       atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset);
+
+       tv_info = (struct _ATOM_ANALOG_TV_INFO *)(mode_info->atom_context->bios + data_offset);
+
+       switch (tv_info->ucTV_BootUpDefaultStandard) {
+       case ATOM_TV_NTSC:
+               tv_std = TV_STD_NTSC;
+               DRM_INFO("Default TV standard: NTSC\n");
+               break;
+       case ATOM_TV_NTSCJ:
+               tv_std = TV_STD_NTSC_J;
+               DRM_INFO("Default TV standard: NTSC-J\n");
+               break;
+       case ATOM_TV_PAL:
+               tv_std = TV_STD_PAL;
+               DRM_INFO("Default TV standard: PAL\n");
+               break;
+       case ATOM_TV_PALM:
+               tv_std = TV_STD_PAL_M;
+               DRM_INFO("Default TV standard: PAL-M\n");
+               break;
+       case ATOM_TV_PALN:
+               tv_std = TV_STD_PAL_N;
+               DRM_INFO("Default TV standard: PAL-N\n");
+               break;
+       case ATOM_TV_PALCN:
+               tv_std = TV_STD_PAL_CN;
+               DRM_INFO("Default TV standard: PAL-CN\n");
+               break;
+       case ATOM_TV_PAL60:
+               tv_std = TV_STD_PAL_60;
+               DRM_INFO("Default TV standard: PAL-60\n");
+               break;
+       case ATOM_TV_SECAM:
+               tv_std = TV_STD_SECAM;
+               DRM_INFO("Default TV standard: SECAM\n");
+               break;
+       default:
+               tv_std = TV_STD_NTSC;
+               DRM_INFO("Unknown TV standard; defaulting to NTSC\n");
+               break;
+       }
+       return tv_std;
+}
+
 struct radeon_encoder_tv_dac *
 radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
 {
@@ -1269,6 +1321,7 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
                dac = dac_info->ucDAC2_NTSC_DAC_Adjustment;
                tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
 
+               tv_dac->tv_std = radeon_atombios_get_tv_info(rdev);
        }
        return tv_dac;
 }
index b062109..812f24d 100644 (file)
@@ -62,7 +62,7 @@ uint32_t radeon_legacy_get_engine_clock(struct radeon_device *rdev)
 }
 
 /* 10 khz */
-static uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev)
+uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev)
 {
        struct radeon_pll *mpll = &rdev->clock.mpll;
        uint32_t fb_div, ref_div, post_div, mclk;
index c5021a3..fd94dbc 100644 (file)
@@ -634,11 +634,10 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
        return p_dac;
 }
 
-static enum radeon_tv_std
-radeon_combios_get_tv_info(struct radeon_encoder *encoder)
+enum radeon_tv_std
+radeon_combios_get_tv_info(struct radeon_device *rdev)
 {
-       struct drm_device *dev = encoder->base.dev;
-       struct radeon_device *rdev = dev->dev_private;
+       struct drm_device *dev = rdev->ddev;
        uint16_t tv_info;
        enum radeon_tv_std tv_std = TV_STD_NTSC;
 
@@ -779,7 +778,7 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct
                        tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
                        found = 1;
                }
-               tv_dac->tv_std = radeon_combios_get_tv_info(encoder);
+               tv_dac->tv_std = radeon_combios_get_tv_info(rdev);
        }
        if (!found) {
                /* then check CRT table */
index 5eece18..2016156 100644 (file)
@@ -208,6 +208,18 @@ static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encode
                drm_mode_set_name(mode);
 
                DRM_DEBUG("Adding native panel mode %s\n", mode->name);
+       } else if (native_mode->hdisplay != 0 &&
+                  native_mode->vdisplay != 0) {
+               /* mac laptops without an edid */
+               /* Note that this is not necessarily the exact panel mode,
+                * but an approximation based on the cvt formula.  For these
+                * systems we should ideally read the mode info out of the
+                * registers or add a mode table, but this works and is much
+                * simpler.
+                */
+               mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false);
+               mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
+               DRM_DEBUG("Adding cvt approximation of native panel mode %s\n", mode->name);
        }
        return mode;
 }
@@ -1171,7 +1183,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                      1);
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.tv_std_property,
-                                                     1);
+                                                     radeon_atombios_get_tv_info(rdev));
                }
                break;
        case DRM_MODE_CONNECTOR_LVDS:
@@ -1315,7 +1327,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
                                                      1);
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.tv_std_property,
-                                                     1);
+                                                     radeon_combios_get_tv_info(rdev));
                }
                break;
        case DRM_MODE_CONNECTOR_LVDS:
index 02bcdb1..7c68480 100644 (file)
@@ -391,6 +391,12 @@ int radeon_asic_init(struct radeon_device *rdev)
                /* FIXME: not supported yet */
                return -EINVAL;
        }
+
+       if (rdev->flags & RADEON_IS_IGP) {
+               rdev->asic->get_memory_clock = NULL;
+               rdev->asic->set_memory_clock = NULL;
+       }
+
        return 0;
 }
 
@@ -481,6 +487,7 @@ int radeon_atombios_init(struct radeon_device *rdev)
        atom_card_info->pll_write = cail_pll_write;
 
        rdev->mode_info.atom_context = atom_parse(atom_card_info, rdev->bios);
+       mutex_init(&rdev->mode_info.atom_context->mutex);
        radeon_atom_initialize_bios_scratch_regs(rdev->ddev);
        atom_allocate_fb_scratch(rdev->mode_info.atom_context);
        return 0;
@@ -539,9 +546,72 @@ void radeon_agp_disable(struct radeon_device *rdev)
        }
 }
 
-/*
- * Radeon device.
- */
+void radeon_check_arguments(struct radeon_device *rdev)
+{
+       /* vramlimit must be a power of two */
+       switch (radeon_vram_limit) {
+       case 0:
+       case 4:
+       case 8:
+       case 16:
+       case 32:
+       case 64:
+       case 128:
+       case 256:
+       case 512:
+       case 1024:
+       case 2048:
+       case 4096:
+               break;
+       default:
+               dev_warn(rdev->dev, "vram limit (%d) must be a power of 2\n",
+                               radeon_vram_limit);
+               radeon_vram_limit = 0;
+               break;
+       }
+       radeon_vram_limit = radeon_vram_limit << 20;
+       /* gtt size must be power of two and greater or equal to 32M */
+       switch (radeon_gart_size) {
+       case 4:
+       case 8:
+       case 16:
+               dev_warn(rdev->dev, "gart size (%d) too small forcing to 512M\n",
+                               radeon_gart_size);
+               radeon_gart_size = 512;
+               break;
+       case 32:
+       case 64:
+       case 128:
+       case 256:
+       case 512:
+       case 1024:
+       case 2048:
+       case 4096:
+               break;
+       default:
+               dev_warn(rdev->dev, "gart size (%d) must be a power of 2\n",
+                               radeon_gart_size);
+               radeon_gart_size = 512;
+               break;
+       }
+       rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
+       /* AGP mode can only be -1, 1, 2, 4, 8 */
+       switch (radeon_agpmode) {
+       case -1:
+       case 0:
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+               break;
+       default:
+               dev_warn(rdev->dev, "invalid AGP mode %d (valid mode: "
+                               "-1, 0, 1, 2, 4, 8)\n", radeon_agpmode);
+               radeon_agpmode = 0;
+               break;
+       }
+}
+
 int radeon_device_init(struct radeon_device *rdev,
                       struct drm_device *ddev,
                       struct pci_dev *pdev,
@@ -580,9 +650,9 @@ int radeon_device_init(struct radeon_device *rdev,
 
        /* Set asic functions */
        r = radeon_asic_init(rdev);
-       if (r) {
+       if (r)
                return r;
-       }
+       radeon_check_arguments(rdev);
 
        if (rdev->flags & RADEON_IS_AGP && radeon_agpmode == -1) {
                radeon_agp_disable(rdev);
index a133b83..91d72b7 100644 (file)
@@ -739,7 +739,7 @@ static struct drm_prop_enum_list radeon_tv_std_enum_list[] =
        { TV_STD_SECAM, "secam" },
 };
 
-int radeon_modeset_create_props(struct radeon_device *rdev)
+static int radeon_modeset_create_props(struct radeon_device *rdev)
 {
        int i, sz;
 
index dbd56ef..8ba3de7 100644 (file)
@@ -196,7 +196,7 @@ static struct drm_driver driver_old = {
                 .owner = THIS_MODULE,
                 .open = drm_open,
                 .release = drm_release,
-                .ioctl = drm_ioctl,
+                .unlocked_ioctl = drm_ioctl,
                 .mmap = drm_mmap,
                 .poll = drm_poll,
                 .fasync = drm_fasync,
@@ -284,7 +284,7 @@ static struct drm_driver kms_driver = {
                 .owner = THIS_MODULE,
                 .open = drm_open,
                 .release = drm_release,
-                .ioctl = drm_ioctl,
+                .unlocked_ioctl = drm_ioctl,
                 .mmap = radeon_mmap,
                 .poll = drm_poll,
                 .fasync = drm_fasync,
index 0d1d908..ccba95f 100644 (file)
@@ -233,6 +233,8 @@ static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
                if (!ASIC_IS_AVIVO(rdev)) {
                        adjusted_mode->hdisplay = mode->hdisplay;
                        adjusted_mode->vdisplay = mode->vdisplay;
+                       adjusted_mode->crtc_hdisplay = mode->hdisplay;
+                       adjusted_mode->crtc_vdisplay = mode->vdisplay;
                }
                adjusted_mode->base.id = mode_id;
        }
@@ -495,9 +497,9 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
                                args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
                        args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
                        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
-                               if (dig->lvds_misc & (1 << 0))
+                               if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL)
                                        args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
-                               if (dig->lvds_misc & (1 << 1))
+                               if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
                                        args.v1.ucMisc |= (1 << 1);
                        } else {
                                if (dig_connector->linkb)
@@ -524,18 +526,18 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
                        args.v2.ucTemporal = 0;
                        args.v2.ucFRC = 0;
                        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
-                               if (dig->lvds_misc & (1 << 0))
+                               if (dig->lvds_misc & ATOM_PANEL_MISC_DUAL)
                                        args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
-                               if (dig->lvds_misc & (1 << 5)) {
+                               if (dig->lvds_misc & ATOM_PANEL_MISC_SPATIAL) {
                                        args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
-                                       if (dig->lvds_misc & (1 << 1))
+                                       if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
                                                args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
                                }
-                               if (dig->lvds_misc & (1 << 6)) {
+                               if (dig->lvds_misc & ATOM_PANEL_MISC_TEMPORAL) {
                                        args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
-                                       if (dig->lvds_misc & (1 << 1))
+                                       if (dig->lvds_misc & ATOM_PANEL_MISC_888RGB)
                                                args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
-                                       if (((dig->lvds_misc >> 2) & 0x3) == 2)
+                                       if (((dig->lvds_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2)
                                                args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
                                }
                        } else {
index cb4cd97..4cdd8b4 100644 (file)
@@ -324,7 +324,7 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
        write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
        r = radeon_scratch_get(rdev, &rdev->fence_drv.scratch_reg);
        if (r) {
-               DRM_ERROR("Fence failed to get a scratch register.");
+               dev_err(rdev->dev, "fence failed to get scratch register\n");
                write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
                return r;
        }
@@ -335,9 +335,10 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
        INIT_LIST_HEAD(&rdev->fence_drv.signaled);
        rdev->fence_drv.count_timeout = 0;
        init_waitqueue_head(&rdev->fence_drv.queue);
+       rdev->fence_drv.initialized = true;
        write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
        if (radeon_debugfs_fence_init(rdev)) {
-               DRM_ERROR("Failed to register debugfs file for fence !\n");
+               dev_err(rdev->dev, "fence debugfs file creation failed\n");
        }
        return 0;
 }
@@ -346,11 +347,13 @@ void radeon_fence_driver_fini(struct radeon_device *rdev)
 {
        unsigned long irq_flags;
 
+       if (!rdev->fence_drv.initialized)
+               return;
        wake_up_all(&rdev->fence_drv.queue);
        write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
        radeon_scratch_free(rdev, rdev->fence_drv.scratch_reg);
        write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
-       DRM_INFO("radeon: fence finalized\n");
+       rdev->fence_drv.initialized = false;
 }
 
 
index a1bf11d..48b7cea 100644 (file)
@@ -92,8 +92,7 @@ static int compat_radeon_cp_init(struct file *file, unsigned int cmd,
                          &init->gart_textures_offset))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_RADEON_CP_INIT, (unsigned long)init);
+       return drm_ioctl(file, DRM_IOCTL_RADEON_CP_INIT, (unsigned long)init);
 }
 
 typedef struct drm_radeon_clear32 {
@@ -125,8 +124,7 @@ static int compat_radeon_cp_clear(struct file *file, unsigned int cmd,
                          &clr->depth_boxes))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_RADEON_CLEAR, (unsigned long)clr);
+       return drm_ioctl(file, DRM_IOCTL_RADEON_CLEAR, (unsigned long)clr);
 }
 
 typedef struct drm_radeon_stipple32 {
@@ -149,8 +147,7 @@ static int compat_radeon_cp_stipple(struct file *file, unsigned int cmd,
                          &request->mask))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_RADEON_STIPPLE, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_RADEON_STIPPLE, (unsigned long)request);
 }
 
 typedef struct drm_radeon_tex_image32 {
@@ -204,8 +201,7 @@ static int compat_radeon_cp_texture(struct file *file, unsigned int cmd,
                          &image->data))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_RADEON_TEXTURE, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_RADEON_TEXTURE, (unsigned long)request);
 }
 
 typedef struct drm_radeon_vertex2_32 {
@@ -238,8 +234,7 @@ static int compat_radeon_cp_vertex2(struct file *file, unsigned int cmd,
                          &request->prim))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_RADEON_VERTEX2, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_RADEON_VERTEX2, (unsigned long)request);
 }
 
 typedef struct drm_radeon_cmd_buffer32 {
@@ -268,8 +263,7 @@ static int compat_radeon_cp_cmdbuf(struct file *file, unsigned int cmd,
                          &request->boxes))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_RADEON_CMDBUF, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_RADEON_CMDBUF, (unsigned long)request);
 }
 
 typedef struct drm_radeon_getparam32 {
@@ -293,8 +287,7 @@ static int compat_radeon_cp_getparam(struct file *file, unsigned int cmd,
                          &request->value))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_RADEON_GETPARAM, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_RADEON_GETPARAM, (unsigned long)request);
 }
 
 typedef struct drm_radeon_mem_alloc32 {
@@ -322,8 +315,7 @@ static int compat_radeon_mem_alloc(struct file *file, unsigned int cmd,
                          &request->region_offset))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_RADEON_ALLOC, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_RADEON_ALLOC, (unsigned long)request);
 }
 
 typedef struct drm_radeon_irq_emit32 {
@@ -345,8 +337,7 @@ static int compat_radeon_irq_emit(struct file *file, unsigned int cmd,
                          &request->irq_seq))
                return -EFAULT;
 
-       return drm_ioctl(file->f_path.dentry->d_inode, file,
-                        DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long)request);
+       return drm_ioctl(file, DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long)request);
 }
 
 /* The two 64-bit arches where alignof(u64)==4 in 32-bit code */
@@ -372,8 +363,7 @@ static int compat_radeon_cp_setparam(struct file *file, unsigned int cmd,
                          &request->value))
                return -EFAULT;
 
-       return drm_ioctl(file->f_dentry->d_inode, file,
-                        DRM_IOCTL_RADEON_SETPARAM, (unsigned long) request);
+       return drm_ioctl(file, DRM_IOCTL_RADEON_SETPARAM, (unsigned long) request);
 }
 #else
 #define compat_radeon_cp_setparam NULL
@@ -413,12 +403,10 @@ long radeon_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(radeon_compat_ioctls))
                fn = radeon_compat_ioctls[nr - DRM_COMMAND_BASE];
 
-       lock_kernel();          /* XXX for now */
        if (fn != NULL)
                ret = (*fn) (filp, cmd, arg);
        else
-               ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
-       unlock_kernel();
+               ret = drm_ioctl(filp, cmd, arg);
 
        return ret;
 }
@@ -431,9 +419,7 @@ long radeon_kms_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long
        if (nr < DRM_COMMAND_BASE)
                return drm_compat_ioctl(filp, cmd, arg);
 
-       lock_kernel();          /* XXX for now */
-       ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
-       unlock_kernel();
+       ret = drm_ioctl(filp, cmd, arg);
 
        return ret;
 }
index b82ede9..cc27485 100644 (file)
@@ -43,8 +43,7 @@ static void radeon_overscan_setup(struct drm_crtc *crtc,
 }
 
 static void radeon_legacy_rmx_mode_set(struct drm_crtc *crtc,
-                                      struct drm_display_mode *mode,
-                                      struct drm_display_mode *adjusted_mode)
+                                      struct drm_display_mode *mode)
 {
        struct drm_device *dev = crtc->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -1059,7 +1058,7 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc,
        radeon_set_pll(crtc, adjusted_mode);
        radeon_overscan_setup(crtc, adjusted_mode);
        if (radeon_crtc->crtc_id == 0) {
-               radeon_legacy_rmx_mode_set(crtc, mode, adjusted_mode);
+               radeon_legacy_rmx_mode_set(crtc, adjusted_mode);
        } else {
                if (radeon_crtc->rmx_type != RMX_OFF) {
                        /* FIXME: only first crtc has rmx what should we
index df00515..981508f 100644 (file)
@@ -207,6 +207,8 @@ static bool radeon_legacy_mode_fixup(struct drm_encoder *encoder,
                *adjusted_mode = *native_mode;
                adjusted_mode->hdisplay = mode->hdisplay;
                adjusted_mode->vdisplay = mode->vdisplay;
+               adjusted_mode->crtc_hdisplay = mode->hdisplay;
+               adjusted_mode->crtc_vdisplay = mode->vdisplay;
                adjusted_mode->base.id = mode_id;
        }
 
index 3dcbe13..402369d 100644 (file)
@@ -88,6 +88,7 @@ enum radeon_tv_std {
        TV_STD_SCART_PAL,
        TV_STD_SECAM,
        TV_STD_PAL_CN,
+       TV_STD_PAL_N,
 };
 
 /* radeon gpio-based i2c
@@ -395,6 +396,11 @@ struct radeon_framebuffer {
        struct drm_gem_object *obj;
 };
 
+extern enum radeon_tv_std
+radeon_combios_get_tv_info(struct radeon_device *rdev);
+extern enum radeon_tv_std
+radeon_atombios_get_tv_info(struct radeon_device *rdev);
+
 extern void radeon_connector_hotplug(struct drm_connector *connector);
 extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
 extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
index 391c973..9f5e2f9 100644 (file)
@@ -42,8 +42,8 @@ void radeon_test_moves(struct radeon_device *rdev)
        /* Number of tests =
         * (Total GTT - IB pool - writeback page - ring buffer) / test size
         */
-       n = (rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - RADEON_GPU_PAGE_SIZE -
-            rdev->cp.ring_size) / size;
+       n = ((u32)(rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - RADEON_GPU_PAGE_SIZE -
+            rdev->cp.ring_size)) / size;
 
        gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL);
        if (!gtt_obj) {
index d7fd160..3b0c07b 100644 (file)
@@ -494,6 +494,7 @@ int radeon_ttm_init(struct radeon_device *rdev)
                DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
                return r;
        }
+       rdev->mman.initialized = true;
        r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_VRAM,
                                rdev->mc.real_vram_size >> PAGE_SHIFT);
        if (r) {
@@ -541,6 +542,8 @@ void radeon_ttm_fini(struct radeon_device *rdev)
 {
        int r;
 
+       if (!rdev->mman.initialized)
+               return;
        if (rdev->stollen_vga_memory) {
                r = radeon_bo_reserve(rdev->stollen_vga_memory, false);
                if (r == 0) {
@@ -554,6 +557,7 @@ void radeon_ttm_fini(struct radeon_device *rdev)
        ttm_bo_device_release(&rdev->mman.bdev);
        radeon_gart_fini(rdev);
        radeon_ttm_global_fini(rdev);
+       rdev->mman.initialized = false;
        DRM_INFO("radeon: ttm finalized\n");
 }
 
index eee52aa..021de44 100644 (file)
@@ -50,7 +50,7 @@ static struct drm_driver driver = {
                 .owner = THIS_MODULE,
                 .open = drm_open,
                 .release = drm_release,
-                .ioctl = drm_ioctl,
+                .unlocked_ioctl = drm_ioctl,
                 .mmap = drm_mmap,
                 .poll = drm_poll,
                 .fasync = drm_fasync,
index e725cc0..4fd1f06 100644 (file)
@@ -80,7 +80,7 @@ static struct drm_driver driver = {
                 .owner = THIS_MODULE,
                 .open = drm_open,
                 .release = drm_release,
-                .ioctl = drm_ioctl,
+                .unlocked_ioctl = drm_ioctl,
                 .mmap = drm_mmap,
                 .poll = drm_poll,
                 .fasync = drm_fasync,
index 012ff2e..ec5a43e 100644 (file)
@@ -48,7 +48,7 @@ static struct drm_driver driver = {
                 .owner = THIS_MODULE,
                 .open = drm_open,
                 .release = drm_release,
-                .ioctl = drm_ioctl,
+                .unlocked_ioctl = drm_ioctl,
                 .mmap = drm_mmap,
                 .poll = drm_poll,
                 .fasync = drm_fasync,
index bc2f518..7a1b210 100644 (file)
@@ -58,7 +58,7 @@ static struct drm_driver driver = {
                .owner = THIS_MODULE,
                .open = drm_open,
                .release = drm_release,
-               .ioctl = drm_ioctl,
+               .unlocked_ioctl = drm_ioctl,
                .mmap = drm_mmap,
                .poll = drm_poll,
                .fasync = drm_fasync,
index 7b48bb3..1db1ef3 100644 (file)
  */
 
 static struct drm_ioctl_desc vmw_ioctls[] = {
-       VMW_IOCTL_DEF(DRM_IOCTL_VMW_GET_PARAM, vmw_getparam_ioctl, 0),
+       VMW_IOCTL_DEF(DRM_IOCTL_VMW_GET_PARAM, vmw_getparam_ioctl,
+                     DRM_AUTH | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl,
-                     0),
+                     DRM_AUTH | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl,
-                     0),
+                     DRM_AUTH | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_CURSOR_BYPASS,
-                     vmw_kms_cursor_bypass_ioctl, 0),
+                     vmw_kms_cursor_bypass_ioctl,
+                     DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED),
 
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_CONTROL_STREAM, vmw_overlay_ioctl,
-                     0),
+                     DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_CLAIM_STREAM, vmw_stream_claim_ioctl,
-                     0),
+                     DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_STREAM, vmw_stream_unref_ioctl,
-                     0),
+                     DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED),
 
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_CREATE_CONTEXT, vmw_context_define_ioctl,
-                     0),
+                     DRM_AUTH | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl,
-                     0),
+                     DRM_AUTH | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_CREATE_SURFACE, vmw_surface_define_ioctl,
-                     0),
+                     DRM_AUTH | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl,
-                     0),
+                     DRM_AUTH | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_REF_SURFACE, vmw_surface_reference_ioctl,
-                     0),
+                     DRM_AUTH | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_EXECBUF, vmw_execbuf_ioctl,
-                     0),
+                     DRM_AUTH | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl,
-                     0),
+                     DRM_AUTH | DRM_ROOT_ONLY | DRM_MASTER | DRM_UNLOCKED),
        VMW_IOCTL_DEF(DRM_IOCTL_VMW_FENCE_WAIT, vmw_fence_wait_ioctl,
-                     0)
+                     DRM_AUTH | DRM_UNLOCKED)
 };
 
 static struct pci_device_id vmw_pci_id_list[] = {
@@ -460,11 +462,9 @@ static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
        struct drm_file *file_priv = filp->private_data;
        struct drm_device *dev = file_priv->minor->dev;
        unsigned int nr = DRM_IOCTL_NR(cmd);
-       long ret;
 
        /*
-        * The driver private ioctls and TTM ioctls should be
-        * thread-safe.
+        * Do extra checking on driver private ioctls.
         */
 
        if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END)
@@ -477,18 +477,9 @@ static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
                                  nr - DRM_COMMAND_BASE);
                        return -EINVAL;
                }
-               return drm_ioctl(filp->f_path.dentry->d_inode,
-                                filp, cmd, arg);
        }
 
-       /*
-        * Not all old drm ioctls are thread-safe.
-        */
-
-       lock_kernel();
-       ret = drm_ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg);
-       unlock_kernel();
-       return ret;
+       return drm_ioctl(filp, cmd, arg);
 }
 
 static int vmw_firstopen(struct drm_device *dev)
index 43546d0..e61bd85 100644 (file)
@@ -123,6 +123,7 @@ struct vmw_sw_context{
        uint32_t last_cid;
        bool cid_valid;
        uint32_t last_sid;
+       uint32_t sid_translation;
        bool sid_valid;
        struct ttm_object_file *tfile;
        struct list_head validate_nodes;
@@ -317,9 +318,10 @@ extern void vmw_surface_res_free(struct vmw_resource *res);
 extern int vmw_surface_init(struct vmw_private *dev_priv,
                            struct vmw_surface *srf,
                            void (*res_free) (struct vmw_resource *res));
-extern int vmw_user_surface_lookup(struct vmw_private *dev_priv,
-                                  struct ttm_object_file *tfile,
-                                  int sid, struct vmw_surface **out);
+extern int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv,
+                                         struct ttm_object_file *tfile,
+                                         uint32_t handle,
+                                         struct vmw_surface **out);
 extern int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
                                     struct drm_file *file_priv);
 extern int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
@@ -328,7 +330,7 @@ extern int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
                                       struct drm_file *file_priv);
 extern int vmw_surface_check(struct vmw_private *dev_priv,
                             struct ttm_object_file *tfile,
-                            int id);
+                            uint32_t handle, int *id);
 extern void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo);
 extern int vmw_dmabuf_init(struct vmw_private *dev_priv,
                           struct vmw_dma_buffer *vmw_bo,
index 7a39f3e..2e92da5 100644 (file)
@@ -73,21 +73,32 @@ static int vmw_cmd_cid_check(struct vmw_private *dev_priv,
 
 static int vmw_cmd_sid_check(struct vmw_private *dev_priv,
                             struct vmw_sw_context *sw_context,
-                            uint32_t sid)
+                            uint32_t *sid)
 {
-       if (unlikely((!sw_context->sid_valid || sid != sw_context->last_sid) &&
-                    sid != SVGA3D_INVALID_ID)) {
-               int ret = vmw_surface_check(dev_priv, sw_context->tfile, sid);
+       if (*sid == SVGA3D_INVALID_ID)
+               return 0;
+
+       if (unlikely((!sw_context->sid_valid  ||
+                     *sid != sw_context->last_sid))) {
+               int real_id;
+               int ret = vmw_surface_check(dev_priv, sw_context->tfile,
+                                           *sid, &real_id);
 
                if (unlikely(ret != 0)) {
-                       DRM_ERROR("Could ot find or use surface %u\n",
-                                 (unsigned) sid);
+                       DRM_ERROR("Could ot find or use surface 0x%08x "
+                                 "address 0x%08lx\n",
+                                 (unsigned int) *sid,
+                                 (unsigned long) sid);
                        return ret;
                }
 
-               sw_context->last_sid = sid;
+               sw_context->last_sid = *sid;
                sw_context->sid_valid = true;
-       }
+               *sid = real_id;
+               sw_context->sid_translation = real_id;
+       } else
+               *sid = sw_context->sid_translation;
+
        return 0;
 }
 
@@ -107,7 +118,8 @@ static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,
                return ret;
 
        cmd = container_of(header, struct vmw_sid_cmd, header);
-       return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.target.sid);
+       ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.target.sid);
+       return ret;
 }
 
 static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv,
@@ -121,10 +133,10 @@ static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv,
        int ret;
 
        cmd = container_of(header, struct vmw_sid_cmd, header);
-       ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.src.sid);
+       ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.src.sid);
        if (unlikely(ret != 0))
                return ret;
-       return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.dest.sid);
+       return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.dest.sid);
 }
 
 static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv,
@@ -138,10 +150,10 @@ static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv,
        int ret;
 
        cmd = container_of(header, struct vmw_sid_cmd, header);
-       ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.src.sid);
+       ret = vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.src.sid);
        if (unlikely(ret != 0))
                return ret;
-       return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.dest.sid);
+       return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.dest.sid);
 }
 
 static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv,
@@ -154,7 +166,7 @@ static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv,
        } *cmd;
 
        cmd = container_of(header, struct vmw_sid_cmd, header);
-       return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.srcImage.sid);
+       return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.srcImage.sid);
 }
 
 static int vmw_cmd_present_check(struct vmw_private *dev_priv,
@@ -167,7 +179,7 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv,
        } *cmd;
 
        cmd = container_of(header, struct vmw_sid_cmd, header);
-       return vmw_cmd_sid_check(dev_priv, sw_context, cmd->body.sid);
+       return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.sid);
 }
 
 static int vmw_cmd_dma(struct vmw_private *dev_priv,
@@ -187,12 +199,7 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
        uint32_t cur_validate_node;
        struct ttm_validate_buffer *val_buf;
 
-
        cmd = container_of(header, struct vmw_dma_cmd, header);
-       ret = vmw_cmd_sid_check(dev_priv, sw_context, cmd->dma.host.sid);
-       if (unlikely(ret != 0))
-               return ret;
-
        handle = cmd->dma.guest.ptr.gmrId;
        ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo);
        if (unlikely(ret != 0)) {
@@ -228,14 +235,23 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
                ++sw_context->cur_val_buf;
        }
 
-       ret = vmw_user_surface_lookup(dev_priv, sw_context->tfile,
-                                     cmd->dma.host.sid, &srf);
+       ret = vmw_user_surface_lookup_handle(dev_priv, sw_context->tfile,
+                                            cmd->dma.host.sid, &srf);
        if (ret) {
                DRM_ERROR("could not find surface\n");
                goto out_no_reloc;
        }
 
+       /**
+        * Patch command stream with device SID.
+        */
+
+       cmd->dma.host.sid = srf->res.id;
        vmw_kms_cursor_snoop(srf, sw_context->tfile, bo, header);
+       /**
+        * FIXME: May deadlock here when called from the
+        * command parsing code.
+        */
        vmw_surface_unreference(&srf);
 
 out_no_reloc:
@@ -243,6 +259,90 @@ out_no_reloc:
        return ret;
 }
 
+static int vmw_cmd_draw(struct vmw_private *dev_priv,
+                       struct vmw_sw_context *sw_context,
+                       SVGA3dCmdHeader *header)
+{
+       struct vmw_draw_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDrawPrimitives body;
+       } *cmd;
+       SVGA3dVertexDecl *decl = (SVGA3dVertexDecl *)(
+               (unsigned long)header + sizeof(*cmd));
+       SVGA3dPrimitiveRange *range;
+       uint32_t i;
+       uint32_t maxnum;
+       int ret;
+
+       ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+       if (unlikely(ret != 0))
+               return ret;
+
+       cmd = container_of(header, struct vmw_draw_cmd, header);
+       maxnum = (header->size - sizeof(cmd->body)) / sizeof(*decl);
+
+       if (unlikely(cmd->body.numVertexDecls > maxnum)) {
+               DRM_ERROR("Illegal number of vertex declarations.\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < cmd->body.numVertexDecls; ++i, ++decl) {
+               ret = vmw_cmd_sid_check(dev_priv, sw_context,
+                                       &decl->array.surfaceId);
+               if (unlikely(ret != 0))
+                       return ret;
+       }
+
+       maxnum = (header->size - sizeof(cmd->body) -
+                 cmd->body.numVertexDecls * sizeof(*decl)) / sizeof(*range);
+       if (unlikely(cmd->body.numRanges > maxnum)) {
+               DRM_ERROR("Illegal number of index ranges.\n");
+               return -EINVAL;
+       }
+
+       range = (SVGA3dPrimitiveRange *) decl;
+       for (i = 0; i < cmd->body.numRanges; ++i, ++range) {
+               ret = vmw_cmd_sid_check(dev_priv, sw_context,
+                                       &range->indexArray.surfaceId);
+               if (unlikely(ret != 0))
+                       return ret;
+       }
+       return 0;
+}
+
+
+static int vmw_cmd_tex_state(struct vmw_private *dev_priv,
+                            struct vmw_sw_context *sw_context,
+                            SVGA3dCmdHeader *header)
+{
+       struct vmw_tex_state_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSetTextureState state;
+       };
+
+       SVGA3dTextureState *last_state = (SVGA3dTextureState *)
+         ((unsigned long) header + header->size + sizeof(header));
+       SVGA3dTextureState *cur_state = (SVGA3dTextureState *)
+               ((unsigned long) header + sizeof(struct vmw_tex_state_cmd));
+       int ret;
+
+       ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+       if (unlikely(ret != 0))
+               return ret;
+
+       for (; cur_state < last_state; ++cur_state) {
+               if (likely(cur_state->name != SVGA3D_TS_BIND_TEXTURE))
+                       continue;
+
+               ret = vmw_cmd_sid_check(dev_priv, sw_context,
+                                       &cur_state->value);
+               if (unlikely(ret != 0))
+                       return ret;
+       }
+
+       return 0;
+}
+
 
 typedef int (*vmw_cmd_func) (struct vmw_private *,
                             struct vmw_sw_context *,
@@ -264,7 +364,7 @@ static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = {
        VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check),
        VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERTARGET,
                    &vmw_cmd_set_render_target_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_tex_state),
        VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check),
        VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check),
        VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check),
@@ -276,7 +376,7 @@ static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = {
        VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check),
        VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_cid_check),
        VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw),
        VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check),
        VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_cid_check),
        VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_cid_check),
@@ -291,6 +391,7 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
                         void *buf, uint32_t *size)
 {
        uint32_t cmd_id;
+       uint32_t size_remaining = *size;
        SVGA3dCmdHeader *header = (SVGA3dCmdHeader *) buf;
        int ret;
 
@@ -304,6 +405,9 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
        *size = le32_to_cpu(header->size) + sizeof(SVGA3dCmdHeader);
 
        cmd_id -= SVGA_3D_CMD_BASE;
+       if (unlikely(*size > size_remaining))
+               goto out_err;
+
        if (unlikely(cmd_id >= SVGA_3D_CMD_MAX - SVGA_3D_CMD_BASE))
                goto out_err;
 
@@ -326,6 +430,7 @@ static int vmw_cmd_check_all(struct vmw_private *dev_priv,
        int ret;
 
        while (cur_size > 0) {
+               size = cur_size;
                ret = vmw_cmd_check(dev_priv, sw_context, buf, &size);
                if (unlikely(ret != 0))
                        return ret;
@@ -386,7 +491,7 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
                return 0;
 
        ret = vmw_gmr_bind(dev_priv, bo);
-       if (likely(ret == 0 || ret == -ERESTART))
+       if (likely(ret == 0 || ret == -ERESTARTSYS))
                return ret;
 
 
@@ -429,7 +534,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
 
        ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
        if (unlikely(ret != 0)) {
-               ret = -ERESTART;
+               ret = -ERESTARTSYS;
                goto out_no_cmd_mutex;
        }
 
index 76b0693..01feb48 100644 (file)
@@ -191,7 +191,7 @@ static int vmw_fifo_wait_noirq(struct vmw_private *dev_priv,
                }
                schedule_timeout(1);
                if (interruptible && signal_pending(current)) {
-                       ret = -ERESTART;
+                       ret = -ERESTARTSYS;
                        break;
                }
        }
@@ -237,9 +237,7 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
                    (dev_priv->fifo_queue,
                     !vmw_fifo_is_full(dev_priv, bytes), timeout);
 
-       if (unlikely(ret == -ERESTARTSYS))
-               ret = -ERESTART;
-       else if (unlikely(ret == 0))
+       if (unlikely(ret == 0))
                ret = -EBUSY;
        else if (likely(ret > 0))
                ret = 0;
index 9e0f030..d40086f 100644 (file)
@@ -155,7 +155,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
                                            TASK_UNINTERRUPTIBLE);
                }
                if (interruptible && signal_pending(current)) {
-                       ret = -ERESTART;
+                       ret = -ERESTARTSYS;
                        break;
                }
        }
@@ -218,9 +218,7 @@ int vmw_wait_fence(struct vmw_private *dev_priv,
                     vmw_fence_signaled(dev_priv, sequence),
                     timeout);
 
-       if (unlikely(ret == -ERESTARTSYS))
-               ret = -ERESTART;
-       else if (unlikely(ret == 0))
+       if (unlikely(ret == 0))
                ret = -EBUSY;
        else if (likely(ret > 0))
                ret = 0;
index e9403be..b1af76e 100644 (file)
@@ -106,8 +106,8 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
        int ret;
 
        if (handle) {
-               ret = vmw_user_surface_lookup(dev_priv, tfile,
-                                             handle, &surface);
+               ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
+                                                    handle, &surface);
                if (!ret) {
                        if (!surface->snooper.image) {
                                DRM_ERROR("surface not suitable for cursor\n");
@@ -704,8 +704,8 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev,
        struct vmw_dma_buffer *bo = NULL;
        int ret;
 
-       ret = vmw_user_surface_lookup(dev_priv, tfile,
-                                     mode_cmd->handle, &surface);
+       ret = vmw_user_surface_lookup_handle(dev_priv, tfile,
+                                            mode_cmd->handle, &surface);
        if (ret)
                goto try_dmabuf;
 
index a1ceed0..c012d59 100644 (file)
@@ -488,28 +488,44 @@ static void vmw_user_surface_free(struct vmw_resource *res)
        kfree(user_srf);
 }
 
-int vmw_user_surface_lookup(struct vmw_private *dev_priv,
-                           struct ttm_object_file *tfile,
-                           int sid, struct vmw_surface **out)
+int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv,
+                                  struct ttm_object_file *tfile,
+                                  uint32_t handle, struct vmw_surface **out)
 {
        struct vmw_resource *res;
        struct vmw_surface *srf;
        struct vmw_user_surface *user_srf;
+       struct ttm_base_object *base;
+       int ret = -EINVAL;
 
-       res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, sid);
-       if (unlikely(res == NULL))
+       base = ttm_base_object_lookup(tfile, handle);
+       if (unlikely(base == NULL))
                return -EINVAL;
 
-       if (res->res_free != &vmw_user_surface_free)
-               return -EINVAL;
+       if (unlikely(base->object_type != VMW_RES_SURFACE))
+               goto out_bad_resource;
 
-       srf = container_of(res, struct vmw_surface, res);
-       user_srf = container_of(srf, struct vmw_user_surface, srf);
-       if (user_srf->base.tfile != tfile && !user_srf->base.shareable)
-               return -EPERM;
+       user_srf = container_of(base, struct vmw_user_surface, base);
+       srf = &user_srf->srf;
+       res = &srf->res;
+
+       read_lock(&dev_priv->resource_lock);
+
+       if (!res->avail || res->res_free != &vmw_user_surface_free) {
+               read_unlock(&dev_priv->resource_lock);
+               goto out_bad_resource;
+       }
+
+       kref_get(&res->kref);
+       read_unlock(&dev_priv->resource_lock);
 
        *out = srf;
-       return 0;
+       ret = 0;
+
+out_bad_resource:
+       ttm_base_object_unref(&base);
+
+       return ret;
 }
 
 static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
@@ -526,35 +542,10 @@ static void vmw_user_surface_base_release(struct ttm_base_object **p_base)
 int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
                              struct drm_file *file_priv)
 {
-       struct vmw_private *dev_priv = vmw_priv(dev);
-       struct vmw_resource *res;
-       struct vmw_surface *srf;
-       struct vmw_user_surface *user_srf;
        struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data;
        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
-       int ret = 0;
-
-       res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, arg->sid);
-       if (unlikely(res == NULL))
-               return -EINVAL;
-
-       if (res->res_free != &vmw_user_surface_free) {
-               ret = -EINVAL;
-               goto out;
-       }
 
-       srf = container_of(res, struct vmw_surface, res);
-       user_srf = container_of(srf, struct vmw_user_surface, srf);
-       if (user_srf->base.tfile != tfile && !user_srf->base.shareable) {
-               ret = -EPERM;
-               goto out;
-       }
-
-       ttm_ref_object_base_unref(tfile, user_srf->base.hash.key,
-                                 TTM_REF_USAGE);
-out:
-       vmw_resource_unreference(&res);
-       return ret;
+       return ttm_ref_object_base_unref(tfile, arg->sid, TTM_REF_USAGE);
 }
 
 int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
@@ -649,7 +640,10 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
        }
        srf->snooper.crtc = NULL;
 
-       rep->sid = res->id;
+       rep->sid = user_srf->base.hash.key;
+       if (rep->sid == SVGA3D_INVALID_ID)
+               DRM_ERROR("Created bad Surface ID.\n");
+
        vmw_resource_unreference(&res);
        return 0;
 out_err1:
@@ -662,39 +656,33 @@ out_err0:
 int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *file_priv)
 {
-       struct vmw_private *dev_priv = vmw_priv(dev);
        union drm_vmw_surface_reference_arg *arg =
            (union drm_vmw_surface_reference_arg *)data;
        struct drm_vmw_surface_arg *req = &arg->req;
        struct drm_vmw_surface_create_req *rep = &arg->rep;
        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
-       struct vmw_resource *res;
        struct vmw_surface *srf;
        struct vmw_user_surface *user_srf;
        struct drm_vmw_size __user *user_sizes;
-       int ret;
+       struct ttm_base_object *base;
+       int ret = -EINVAL;
 
-       res = vmw_resource_lookup(dev_priv, &dev_priv->surface_idr, req->sid);
-       if (unlikely(res == NULL))
+       base = ttm_base_object_lookup(tfile, req->sid);
+       if (unlikely(base == NULL)) {
+               DRM_ERROR("Could not find surface to reference.\n");
                return -EINVAL;
-
-       if (res->res_free != &vmw_user_surface_free) {
-               ret = -EINVAL;
-               goto out;
        }
 
-       srf = container_of(res, struct vmw_surface, res);
-       user_srf = container_of(srf, struct vmw_user_surface, srf);
-       if (user_srf->base.tfile != tfile && !user_srf->base.shareable) {
-               DRM_ERROR("Tried to reference none shareable surface\n");
-               ret = -EPERM;
-               goto out;
-       }
+       if (unlikely(base->object_type != VMW_RES_SURFACE))
+               goto out_bad_resource;
+
+       user_srf = container_of(base, struct vmw_user_surface, base);
+       srf = &user_srf->srf;
 
        ret = ttm_ref_object_add(tfile, &user_srf->base, TTM_REF_USAGE, NULL);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Could not add a reference to a surface.\n");
-               goto out;
+               goto out_no_reference;
        }
 
        rep->flags = srf->flags;
@@ -706,40 +694,43 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
        if (user_sizes)
                ret = copy_to_user(user_sizes, srf->sizes,
                                   srf->num_sizes * sizeof(*srf->sizes));
-       if (unlikely(ret != 0)) {
+       if (unlikely(ret != 0))
                DRM_ERROR("copy_to_user failed %p %u\n",
                          user_sizes, srf->num_sizes);
-               /**
-                * FIXME: Unreference surface here?
-                */
-               goto out;
-       }
-out:
-       vmw_resource_unreference(&res);
+out_bad_resource:
+out_no_reference:
+       ttm_base_object_unref(&base);
+
        return ret;
 }
 
 int vmw_surface_check(struct vmw_private *dev_priv,
                      struct ttm_object_file *tfile,
-                     int id)
+                     uint32_t handle, int *id)
 {
-       struct vmw_resource *res;
-       int ret = 0;
+       struct ttm_base_object *base;
+       struct vmw_user_surface *user_srf;
 
-       read_lock(&dev_priv->resource_lock);
-       res = idr_find(&dev_priv->surface_idr, id);
-       if (res && res->avail) {
-               struct vmw_surface *srf =
-                       container_of(res, struct vmw_surface, res);
-               struct vmw_user_surface *usrf =
-                       container_of(srf, struct vmw_user_surface, srf);
+       int ret = -EPERM;
 
-               if (usrf->base.tfile != tfile && !usrf->base.shareable)
-                       ret = -EPERM;
-       } else
-               ret = -EINVAL;
-       read_unlock(&dev_priv->resource_lock);
+       base = ttm_base_object_lookup(tfile, handle);
+       if (unlikely(base == NULL))
+               return -EINVAL;
+
+       if (unlikely(base->object_type != VMW_RES_SURFACE))
+               goto out_bad_surface;
 
+       user_srf = container_of(base, struct vmw_user_surface, base);
+       *id = user_srf->srf.res.id;
+       ret = 0;
+
+out_bad_surface:
+       /**
+        * FIXME: May deadlock here when called from the
+        * command parsing code.
+        */
+
+       ttm_base_object_unref(&base);
        return ret;
 }
 
index bfd03bf..f3d440c 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <linux/list.h>
 #include <linux/mutex.h>
+#include <linux/kfifo.h>
 
 #include "t3_cpl.h"
 #include "t3cdev.h"
@@ -75,13 +76,13 @@ struct cxio_hal_ctrl_qp {
 };
 
 struct cxio_hal_resource {
-       struct kfifo *tpt_fifo;
+       struct kfifo tpt_fifo;
        spinlock_t tpt_fifo_lock;
-       struct kfifo *qpid_fifo;
+       struct kfifo qpid_fifo;
        spinlock_t qpid_fifo_lock;
-       struct kfifo *cqid_fifo;
+       struct kfifo cqid_fifo;
        spinlock_t cqid_fifo_lock;
-       struct kfifo *pdid_fifo;
+       struct kfifo pdid_fifo;
        spinlock_t pdid_fifo_lock;
 };
 
index bd233c0..31f9201 100644 (file)
 #include "cxio_resource.h"
 #include "cxio_hal.h"
 
-static struct kfifo *rhdl_fifo;
+static struct kfifo rhdl_fifo;
 static spinlock_t rhdl_fifo_lock;
 
 #define RANDOM_SIZE 16
 
-static int __cxio_init_resource_fifo(struct kfifo **fifo,
+static int __cxio_init_resource_fifo(struct kfifo *fifo,
                                   spinlock_t *fifo_lock,
                                   u32 nr, u32 skip_low,
                                   u32 skip_high,
@@ -55,12 +55,11 @@ static int __cxio_init_resource_fifo(struct kfifo **fifo,
        u32 rarray[16];
        spin_lock_init(fifo_lock);
 
-       *fifo = kfifo_alloc(nr * sizeof(u32), GFP_KERNEL, fifo_lock);
-       if (IS_ERR(*fifo))
+       if (kfifo_alloc(fifo, nr * sizeof(u32), GFP_KERNEL))
                return -ENOMEM;
 
        for (i = 0; i < skip_low + skip_high; i++)
-               __kfifo_put(*fifo, (unsigned char *) &entry, sizeof(u32));
+               kfifo_in(fifo, (unsigned char *) &entry, sizeof(u32));
        if (random) {
                j = 0;
                random_bytes = random32();
@@ -72,33 +71,35 @@ static int __cxio_init_resource_fifo(struct kfifo **fifo,
                                random_bytes = random32();
                        }
                        idx = (random_bytes >> (j * 2)) & 0xF;
-                       __kfifo_put(*fifo,
+                       kfifo_in(fifo,
                                (unsigned char *) &rarray[idx],
                                sizeof(u32));
                        rarray[idx] = i;
                        j++;
                }
                for (i = 0; i < RANDOM_SIZE; i++)
-                       __kfifo_put(*fifo,
+                       kfifo_in(fifo,
                                (unsigned char *) &rarray[i],
                                sizeof(u32));
        } else
                for (i = skip_low; i < nr - skip_high; i++)
-                       __kfifo_put(*fifo, (unsigned char *) &i, sizeof(u32));
+                       kfifo_in(fifo, (unsigned char *) &i, sizeof(u32));
 
        for (i = 0; i < skip_low + skip_high; i++)
-               kfifo_get(*fifo, (unsigned char *) &entry, sizeof(u32));
+               if (kfifo_out_locked(fifo, (unsigned char *) &entry,
+                               sizeof(u32), fifo_lock) != sizeof(u32))
+                                       break;
        return 0;
 }
 
-static int cxio_init_resource_fifo(struct kfifo **fifo, spinlock_t * fifo_lock,
+static int cxio_init_resource_fifo(struct kfifo *fifo, spinlock_t * fifo_lock,
                                   u32 nr, u32 skip_low, u32 skip_high)
 {
        return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
                                          skip_high, 0));
 }
 
-static int cxio_init_resource_fifo_random(struct kfifo **fifo,
+static int cxio_init_resource_fifo_random(struct kfifo *fifo,
                                   spinlock_t * fifo_lock,
                                   u32 nr, u32 skip_low, u32 skip_high)
 {
@@ -113,15 +114,13 @@ static int cxio_init_qpid_fifo(struct cxio_rdev *rdev_p)
 
        spin_lock_init(&rdev_p->rscp->qpid_fifo_lock);
 
-       rdev_p->rscp->qpid_fifo = kfifo_alloc(T3_MAX_NUM_QP * sizeof(u32),
-                                             GFP_KERNEL,
-                                             &rdev_p->rscp->qpid_fifo_lock);
-       if (IS_ERR(rdev_p->rscp->qpid_fifo))
+       if (kfifo_alloc(&rdev_p->rscp->qpid_fifo, T3_MAX_NUM_QP * sizeof(u32),
+                                             GFP_KERNEL))
                return -ENOMEM;
 
        for (i = 16; i < T3_MAX_NUM_QP; i++)
                if (!(i & rdev_p->qpmask))
-                       __kfifo_put(rdev_p->rscp->qpid_fifo,
+                       kfifo_in(&rdev_p->rscp->qpid_fifo,
                                    (unsigned char *) &i, sizeof(u32));
        return 0;
 }
@@ -134,7 +133,7 @@ int cxio_hal_init_rhdl_resource(u32 nr_rhdl)
 
 void cxio_hal_destroy_rhdl_resource(void)
 {
-       kfifo_free(rhdl_fifo);
+       kfifo_free(&rhdl_fifo);
 }
 
 /* nr_* must be power of 2 */
@@ -167,11 +166,11 @@ int cxio_hal_init_resource(struct cxio_rdev *rdev_p,
                goto pdid_err;
        return 0;
 pdid_err:
-       kfifo_free(rscp->cqid_fifo);
+       kfifo_free(&rscp->cqid_fifo);
 cqid_err:
-       kfifo_free(rscp->qpid_fifo);
+       kfifo_free(&rscp->qpid_fifo);
 qpid_err:
-       kfifo_free(rscp->tpt_fifo);
+       kfifo_free(&rscp->tpt_fifo);
 tpt_err:
        return -ENOMEM;
 }
@@ -179,33 +178,37 @@ tpt_err:
 /*
  * returns 0 if no resource available
  */
-static u32 cxio_hal_get_resource(struct kfifo *fifo)
+static u32 cxio_hal_get_resource(struct kfifo *fifo, spinlock_t * lock)
 {
        u32 entry;
-       if (kfifo_get(fifo, (unsigned char *) &entry, sizeof(u32)))
+       if (kfifo_out_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock))
                return entry;
        else
                return 0;       /* fifo emptry */
 }
 
-static void cxio_hal_put_resource(struct kfifo *fifo, u32 entry)
+static void cxio_hal_put_resource(struct kfifo *fifo, spinlock_t * lock,
+               u32 entry)
 {
-       BUG_ON(kfifo_put(fifo, (unsigned char *) &entry, sizeof(u32)) == 0);
+       BUG_ON(
+       kfifo_in_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock)
+       == 0);
 }
 
 u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp)
 {
-       return cxio_hal_get_resource(rscp->tpt_fifo);
+       return cxio_hal_get_resource(&rscp->tpt_fifo, &rscp->tpt_fifo_lock);
 }
 
 void cxio_hal_put_stag(struct cxio_hal_resource *rscp, u32 stag)
 {
-       cxio_hal_put_resource(rscp->tpt_fifo, stag);
+       cxio_hal_put_resource(&rscp->tpt_fifo, &rscp->tpt_fifo_lock, stag);
 }
 
 u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp)
 {
-       u32 qpid = cxio_hal_get_resource(rscp->qpid_fifo);
+       u32 qpid = cxio_hal_get_resource(&rscp->qpid_fifo,
+                       &rscp->qpid_fifo_lock);
        PDBG("%s qpid 0x%x\n", __func__, qpid);
        return qpid;
 }
@@ -213,35 +216,35 @@ u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp)
 void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid)
 {
        PDBG("%s qpid 0x%x\n", __func__, qpid);
-       cxio_hal_put_resource(rscp->qpid_fifo, qpid);
+       cxio_hal_put_resource(&rscp->qpid_fifo, &rscp->qpid_fifo_lock, qpid);
 }
 
 u32 cxio_hal_get_cqid(struct cxio_hal_resource *rscp)
 {
-       return cxio_hal_get_resource(rscp->cqid_fifo);
+       return cxio_hal_get_resource(&rscp->cqid_fifo, &rscp->cqid_fifo_lock);
 }
 
 void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid)
 {
-       cxio_hal_put_resource(rscp->cqid_fifo, cqid);
+       cxio_hal_put_resource(&rscp->cqid_fifo, &rscp->cqid_fifo_lock, cqid);
 }
 
 u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp)
 {
-       return cxio_hal_get_resource(rscp->pdid_fifo);
+       return cxio_hal_get_resource(&rscp->pdid_fifo, &rscp->pdid_fifo_lock);
 }
 
 void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid)
 {
-       cxio_hal_put_resource(rscp->pdid_fifo, pdid);
+       cxio_hal_put_resource(&rscp->pdid_fifo, &rscp->pdid_fifo_lock, pdid);
 }
 
 void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp)
 {
-       kfifo_free(rscp->tpt_fifo);
-       kfifo_free(rscp->cqid_fifo);
-       kfifo_free(rscp->qpid_fifo);
-       kfifo_free(rscp->pdid_fifo);
+       kfifo_free(&rscp->tpt_fifo);
+       kfifo_free(&rscp->cqid_fifo);
+       kfifo_free(&rscp->qpid_fifo);
+       kfifo_free(&rscp->pdid_fifo);
        kfree(rscp);
 }
 
index 3ccc8af..2bf57a4 100644 (file)
@@ -124,15 +124,12 @@ struct cx23888_ir_state {
        atomic_t rxclk_divider;
        atomic_t rx_invert;
 
-       struct kfifo *rx_kfifo;
+       struct kfifo rx_kfifo;
        spinlock_t rx_kfifo_lock;
 
        struct v4l2_subdev_ir_parameters tx_params;
        struct mutex tx_params_lock;
        atomic_t txclk_divider;
-
-       struct kfifo *tx_kfifo;
-       spinlock_t tx_kfifo_lock;
 };
 
 static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd)
@@ -522,6 +519,7 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
 {
        struct cx23888_ir_state *state = to_state(sd);
        struct cx23885_dev *dev = state->dev;
+       unsigned long flags;
 
        u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG);
        u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG);
@@ -594,8 +592,9 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
                        if (i == 0)
                                break;
                        j = i * sizeof(u32);
-                       k = kfifo_put(state->rx_kfifo,
-                                     (unsigned char *) rx_data, j);
+                       k = kfifo_in_locked(&state->rx_kfifo,
+                                     (unsigned char *) rx_data, j,
+                                     &state->rx_kfifo_lock);
                        if (k != j)
                                kror++; /* rx_kfifo over run */
                }
@@ -631,8 +630,11 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
                cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl);
                *handled = true;
        }
-       if (kfifo_len(state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2)
+
+       spin_lock_irqsave(&state->rx_kfifo_lock, flags);
+       if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2)
                events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
+       spin_unlock_irqrestore(&state->rx_kfifo_lock, flags);
 
        if (events)
                v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events);
@@ -657,7 +659,7 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
                return 0;
        }
 
-       n = kfifo_get(state->rx_kfifo, buf, n);
+       n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock);
 
        n /= sizeof(u32);
        *num = n * sizeof(u32);
@@ -785,7 +787,12 @@ static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd,
        o->interrupt_enable = p->interrupt_enable;
        o->enable = p->enable;
        if (p->enable) {
-               kfifo_reset(state->rx_kfifo);
+               unsigned long flags;
+
+               spin_lock_irqsave(&state->rx_kfifo_lock, flags);
+               kfifo_reset(&state->rx_kfifo);
+               /* reset tx_fifo too if there is one... */
+               spin_unlock_irqrestore(&state->rx_kfifo_lock, flags);
                if (p->interrupt_enable)
                        irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE);
                control_rx_enable(dev, p->enable);
@@ -892,7 +899,6 @@ static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd,
        o->interrupt_enable = p->interrupt_enable;
        o->enable = p->enable;
        if (p->enable) {
-               kfifo_reset(state->tx_kfifo);
                if (p->interrupt_enable)
                        irqenable_tx(dev, IRQEN_TSE);
                control_tx_enable(dev, p->enable);
@@ -1168,18 +1174,8 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
                return -ENOMEM;
 
        spin_lock_init(&state->rx_kfifo_lock);
-       state->rx_kfifo = kfifo_alloc(CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL,
-                                     &state->rx_kfifo_lock);
-       if (state->rx_kfifo == NULL)
-               return -ENOMEM;
-
-       spin_lock_init(&state->tx_kfifo_lock);
-       state->tx_kfifo = kfifo_alloc(CX23888_IR_TX_KFIFO_SIZE, GFP_KERNEL,
-                                     &state->tx_kfifo_lock);
-       if (state->tx_kfifo == NULL) {
-               kfifo_free(state->rx_kfifo);
+       if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL))
                return -ENOMEM;
-       }
 
        state->dev = dev;
        state->id = V4L2_IDENT_CX23888_IR;
@@ -1211,8 +1207,7 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
                       sizeof(struct v4l2_subdev_ir_parameters));
                v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
        } else {
-               kfifo_free(state->rx_kfifo);
-               kfifo_free(state->tx_kfifo);
+               kfifo_free(&state->rx_kfifo);
        }
        return ret;
 }
@@ -1231,8 +1226,7 @@ int cx23888_ir_remove(struct cx23885_dev *dev)
 
        state = to_state(sd);
        v4l2_device_unregister_subdev(sd);
-       kfifo_free(state->rx_kfifo);
-       kfifo_free(state->tx_kfifo);
+       kfifo_free(&state->rx_kfifo);
        kfree(state);
        /* Nothing more to free() as state held the actual v4l2_subdev object */
        return 0;
index 6ffa64c..b421858 100644 (file)
@@ -800,8 +800,8 @@ again:
                return IRQ_HANDLED;
 
        if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) {
-               if (kfifo_get(meye.grabq, (unsigned char *)&reqnr,
-                             sizeof(int)) != sizeof(int)) {
+               if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr,
+                             sizeof(int), &meye.grabq_lock) != sizeof(int)) {
                        mchip_free_frame();
                        return IRQ_HANDLED;
                }
@@ -811,7 +811,8 @@ again:
                meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
                do_gettimeofday(&meye.grab_buffer[reqnr].timestamp);
                meye.grab_buffer[reqnr].sequence = sequence++;
-               kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int));
+               kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr,
+                               sizeof(int), &meye.doneq_lock);
                wake_up_interruptible(&meye.proc_list);
        } else {
                int size;
@@ -820,8 +821,8 @@ again:
                        mchip_free_frame();
                        goto again;
                }
-               if (kfifo_get(meye.grabq, (unsigned char *)&reqnr,
-                             sizeof(int)) != sizeof(int)) {
+               if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr,
+                             sizeof(int), &meye.grabq_lock) != sizeof(int)) {
                        mchip_free_frame();
                        goto again;
                }
@@ -831,7 +832,8 @@ again:
                meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
                do_gettimeofday(&meye.grab_buffer[reqnr].timestamp);
                meye.grab_buffer[reqnr].sequence = sequence++;
-               kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int));
+               kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr,
+                               sizeof(int), &meye.doneq_lock);
                wake_up_interruptible(&meye.proc_list);
        }
        mchip_free_frame();
@@ -859,8 +861,8 @@ static int meye_open(struct file *file)
 
        for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
                meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
-       kfifo_reset(meye.grabq);
-       kfifo_reset(meye.doneq);
+       kfifo_reset(&meye.grabq);
+       kfifo_reset(&meye.doneq);
        return 0;
 }
 
@@ -933,7 +935,8 @@ static int meyeioc_qbuf_capt(int *nb)
                mchip_cont_compression_start();
 
        meye.grab_buffer[*nb].state = MEYE_BUF_USING;
-       kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int));
+       kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int),
+                        &meye.grabq_lock);
        mutex_unlock(&meye.lock);
 
        return 0;
@@ -965,7 +968,9 @@ static int meyeioc_sync(struct file *file, void *fh, int *i)
                /* fall through */
        case MEYE_BUF_DONE:
                meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
-               kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
+               if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused,
+                               sizeof(int), &meye.doneq_lock) != sizeof(int))
+                                       break;
        }
        *i = meye.grab_buffer[*i].size;
        mutex_unlock(&meye.lock);
@@ -1452,7 +1457,8 @@ static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
        buf->flags |= V4L2_BUF_FLAG_QUEUED;
        buf->flags &= ~V4L2_BUF_FLAG_DONE;
        meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
-       kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int));
+       kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index,
+                       sizeof(int), &meye.grabq_lock);
        mutex_unlock(&meye.lock);
 
        return 0;
@@ -1467,19 +1473,19 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 
        mutex_lock(&meye.lock);
 
-       if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
+       if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
                mutex_unlock(&meye.lock);
                return -EAGAIN;
        }
 
        if (wait_event_interruptible(meye.proc_list,
-                                    kfifo_len(meye.doneq) != 0) < 0) {
+                                    kfifo_len(&meye.doneq) != 0) < 0) {
                mutex_unlock(&meye.lock);
                return -EINTR;
        }
 
-       if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
-                      sizeof(int))) {
+       if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr,
+                      sizeof(int), &meye.doneq_lock)) {
                mutex_unlock(&meye.lock);
                return -EBUSY;
        }
@@ -1529,8 +1535,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
 {
        mutex_lock(&meye.lock);
        mchip_hic_stop();
-       kfifo_reset(meye.grabq);
-       kfifo_reset(meye.doneq);
+       kfifo_reset(&meye.grabq);
+       kfifo_reset(&meye.doneq);
 
        for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
                meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
@@ -1572,7 +1578,7 @@ static unsigned int meye_poll(struct file *file, poll_table *wait)
 
        mutex_lock(&meye.lock);
        poll_wait(file, &meye.proc_list, wait);
-       if (kfifo_len(meye.doneq))
+       if (kfifo_len(&meye.doneq))
                res = POLLIN | POLLRDNORM;
        mutex_unlock(&meye.lock);
        return res;
@@ -1745,16 +1751,14 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
        }
 
        spin_lock_init(&meye.grabq_lock);
-       meye.grabq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL,
-                                &meye.grabq_lock);
-       if (IS_ERR(meye.grabq)) {
+       if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS,
+                               GFP_KERNEL)) {
                printk(KERN_ERR "meye: fifo allocation failed\n");
                goto outkfifoalloc1;
        }
        spin_lock_init(&meye.doneq_lock);
-       meye.doneq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL,
-                                &meye.doneq_lock);
-       if (IS_ERR(meye.doneq)) {
+       if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS,
+                               GFP_KERNEL)) {
                printk(KERN_ERR "meye: fifo allocation failed\n");
                goto outkfifoalloc2;
        }
@@ -1868,9 +1872,9 @@ outregions:
 outenabledev:
        sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
 outsonypienable:
-       kfifo_free(meye.doneq);
+       kfifo_free(&meye.doneq);
 outkfifoalloc2:
-       kfifo_free(meye.grabq);
+       kfifo_free(&meye.grabq);
 outkfifoalloc1:
        vfree(meye.grab_temp);
 outvmalloc:
@@ -1901,8 +1905,8 @@ static void __devexit meye_remove(struct pci_dev *pcidev)
 
        sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
 
-       kfifo_free(meye.doneq);
-       kfifo_free(meye.grabq);
+       kfifo_free(&meye.doneq);
+       kfifo_free(&meye.grabq);
 
        vfree(meye.grab_temp);
 
index 5f70a10..1321ad5 100644 (file)
@@ -303,9 +303,9 @@ struct meye {
        struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS];
        int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */
        struct mutex lock;              /* mutex for open/mmap... */
-       struct kfifo *grabq;            /* queue for buffers to be grabbed */
+       struct kfifo grabq;             /* queue for buffers to be grabbed */
        spinlock_t grabq_lock;          /* lock protecting the queue */
-       struct kfifo *doneq;            /* queue for grabbed buffers */
+       struct kfifo doneq;             /* queue for grabbed buffers */
        spinlock_t doneq_lock;          /* lock protecting the queue */
        wait_queue_head_t proc_list;    /* wait queue */
        struct video_device *video_dev; /* video device parameters */
index b9b371b..42611be 100644 (file)
@@ -1365,7 +1365,7 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
        priv->dnld_sent = DNLD_RES_RECEIVED;
 
        /* If nothing to do, go back to sleep (?) */
-       if (!__kfifo_len(priv->event_fifo) && !priv->resp_len[priv->resp_idx])
+       if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])
                priv->psstate = PS_STATE_SLEEP;
 
        spin_unlock_irqrestore(&priv->driver_lock, flags);
@@ -1439,7 +1439,7 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv)
        }
 
        /* Pending events or command responses? */
-       if (__kfifo_len(priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
+       if (kfifo_len(&priv->event_fifo) || priv->resp_len[priv->resp_idx]) {
                allowed = 0;
                lbs_deb_host("pending events or command responses\n");
        }
index 6a8d2b2..05bb298 100644 (file)
@@ -10,7 +10,7 @@
 #include "scan.h"
 #include "assoc.h"
 
-
+#include <linux/kfifo.h>
 
 /** sleep_params */
 struct sleep_params {
@@ -120,7 +120,7 @@ struct lbs_private {
        u32 resp_len[2];
 
        /* Events sent from hardware to driver */
-       struct kfifo *event_fifo;
+       struct kfifo event_fifo;
 
        /** thread to service interrupts */
        struct task_struct *main_thread;
index db38a5a..c2975c8 100644 (file)
@@ -459,7 +459,7 @@ static int lbs_thread(void *data)
                else if (!list_empty(&priv->cmdpendingq) &&
                                        !(priv->wakeup_dev_required))
                        shouldsleep = 0;        /* We have a command to send */
-               else if (__kfifo_len(priv->event_fifo))
+               else if (kfifo_len(&priv->event_fifo))
                        shouldsleep = 0;        /* We have an event to process */
                else
                        shouldsleep = 1;        /* No command */
@@ -511,10 +511,13 @@ static int lbs_thread(void *data)
 
                /* Process hardware events, e.g. card removed, link lost */
                spin_lock_irq(&priv->driver_lock);
-               while (__kfifo_len(priv->event_fifo)) {
+               while (kfifo_len(&priv->event_fifo)) {
                        u32 event;
-                       __kfifo_get(priv->event_fifo, (unsigned char *) &event,
-                               sizeof(event));
+
+                       if (kfifo_out(&priv->event_fifo,
+                               (unsigned char *) &event, sizeof(event)) !=
+                               sizeof(event))
+                                       break;
                        spin_unlock_irq(&priv->driver_lock);
                        lbs_process_event(priv, event);
                        spin_lock_irq(&priv->driver_lock);
@@ -883,10 +886,9 @@ static int lbs_init_adapter(struct lbs_private *priv)
        priv->resp_len[0] = priv->resp_len[1] = 0;
 
        /* Create the event FIFO */
-       priv->event_fifo = kfifo_alloc(sizeof(u32) * 16, GFP_KERNEL, NULL);
-       if (IS_ERR(priv->event_fifo)) {
+       ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL);
+       if (ret) {
                lbs_pr_err("Out of memory allocating event FIFO buffer\n");
-               ret = -ENOMEM;
                goto out;
        }
 
@@ -901,8 +903,7 @@ static void lbs_free_adapter(struct lbs_private *priv)
        lbs_deb_enter(LBS_DEB_MAIN);
 
        lbs_free_cmd_buffer(priv);
-       if (priv->event_fifo)
-               kfifo_free(priv->event_fifo);
+       kfifo_free(&priv->event_fifo);
        del_timer(&priv->command_timer);
        del_timer(&priv->auto_deepsleep_timer);
        kfree(priv->networks);
@@ -1177,7 +1178,7 @@ void lbs_queue_event(struct lbs_private *priv, u32 event)
        if (priv->psstate == PS_STATE_SLEEP)
                priv->psstate = PS_STATE_AWAKE;
 
-       __kfifo_put(priv->event_fifo, (unsigned char *) &event, sizeof(u32));
+       kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32));
 
        wake_up_interruptible(&priv->waitq);
 
index bcd4ba8..b66029b 100644 (file)
@@ -164,7 +164,7 @@ struct fujitsu_hotkey_t {
        struct input_dev *input;
        char phys[32];
        struct platform_device *pf_device;
-       struct kfifo *fifo;
+       struct kfifo fifo;
        spinlock_t fifo_lock;
        int rfkill_supported;
        int rfkill_state;
@@ -824,12 +824,10 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
 
        /* kfifo */
        spin_lock_init(&fujitsu_hotkey->fifo_lock);
-       fujitsu_hotkey->fifo =
-           kfifo_alloc(RINGBUFFERSIZE * sizeof(int), GFP_KERNEL,
-                       &fujitsu_hotkey->fifo_lock);
-       if (IS_ERR(fujitsu_hotkey->fifo)) {
+       error = kfifo_alloc(&fujitsu_hotkey->fifo, RINGBUFFERSIZE * sizeof(int),
+                       GFP_KERNEL);
+       if (error) {
                printk(KERN_ERR "kfifo_alloc failed\n");
-               error = PTR_ERR(fujitsu_hotkey->fifo);
                goto err_stop;
        }
 
@@ -934,7 +932,7 @@ err_unregister_input_dev:
 err_free_input_dev:
        input_free_device(input);
 err_free_fifo:
-       kfifo_free(fujitsu_hotkey->fifo);
+       kfifo_free(&fujitsu_hotkey->fifo);
 err_stop:
        return result;
 }
@@ -956,7 +954,7 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type)
 
        input_free_device(input);
 
-       kfifo_free(fujitsu_hotkey->fifo);
+       kfifo_free(&fujitsu_hotkey->fifo);
 
        fujitsu_hotkey->acpi_handle = NULL;
 
@@ -1008,9 +1006,10 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
                                vdbg_printk(FUJLAPTOP_DBG_TRACE,
                                        "Push keycode into ringbuffer [%d]\n",
                                        keycode);
-                               status = kfifo_put(fujitsu_hotkey->fifo,
+                               status = kfifo_in_locked(&fujitsu_hotkey->fifo,
                                                   (unsigned char *)&keycode,
-                                                  sizeof(keycode));
+                                                  sizeof(keycode),
+                                                  &fujitsu_hotkey->fifo_lock);
                                if (status != sizeof(keycode)) {
                                        vdbg_printk(FUJLAPTOP_DBG_WARN,
                                            "Could not push keycode [0x%x]\n",
@@ -1021,11 +1020,12 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
                                }
                        } else if (keycode == 0) {
                                while ((status =
-                                       kfifo_get
-                                       (fujitsu_hotkey->fifo, (unsigned char *)
-                                        &keycode_r,
-                                        sizeof
-                                        (keycode_r))) == sizeof(keycode_r)) {
+                                       kfifo_out_locked(
+                                        &fujitsu_hotkey->fifo,
+                                        (unsigned char *) &keycode_r,
+                                        sizeof(keycode_r),
+                                        &fujitsu_hotkey->fifo_lock))
+                                        == sizeof(keycode_r)) {
                                        input_report_key(input, keycode_r, 0);
                                        input_sync(input);
                                        vdbg_printk(FUJLAPTOP_DBG_TRACE,
index 7a2cc8a..2896ca4 100644 (file)
@@ -142,7 +142,7 @@ struct sony_laptop_input_s {
        atomic_t                users;
        struct input_dev        *jog_dev;
        struct input_dev        *key_dev;
-       struct kfifo            *fifo;
+       struct kfifo            fifo;
        spinlock_t              fifo_lock;
        struct workqueue_struct *wq;
 };
@@ -300,8 +300,9 @@ static void do_sony_laptop_release_key(struct work_struct *work)
 {
        struct sony_laptop_keypress kp;
 
-       while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,
-                        sizeof(kp)) == sizeof(kp)) {
+       while (kfifo_out_locked(&sony_laptop_input.fifo, (unsigned char *)&kp,
+                       sizeof(kp), &sony_laptop_input.fifo_lock)
+                       == sizeof(kp)) {
                msleep(10);
                input_report_key(kp.dev, kp.key, 0);
                input_sync(kp.dev);
@@ -362,8 +363,9 @@ static void sony_laptop_report_input_event(u8 event)
                /* we emit the scancode so we can always remap the key */
                input_event(kp.dev, EV_MSC, MSC_SCAN, event);
                input_sync(kp.dev);
-               kfifo_put(sony_laptop_input.fifo,
-                         (unsigned char *)&kp, sizeof(kp));
+               kfifo_in_locked(&sony_laptop_input.fifo,
+                         (unsigned char *)&kp, sizeof(kp),
+                         &sony_laptop_input.fifo_lock);
 
                if (!work_pending(&sony_laptop_release_key_work))
                        queue_work(sony_laptop_input.wq,
@@ -385,12 +387,10 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
 
        /* kfifo */
        spin_lock_init(&sony_laptop_input.fifo_lock);
-       sony_laptop_input.fifo =
-               kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
-                           &sony_laptop_input.fifo_lock);
-       if (IS_ERR(sony_laptop_input.fifo)) {
+       error =
+        kfifo_alloc(&sony_laptop_input.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
+       if (error) {
                printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
-               error = PTR_ERR(sony_laptop_input.fifo);
                goto err_dec_users;
        }
 
@@ -474,7 +474,7 @@ err_destroy_wq:
        destroy_workqueue(sony_laptop_input.wq);
 
 err_free_kfifo:
-       kfifo_free(sony_laptop_input.fifo);
+       kfifo_free(&sony_laptop_input.fifo);
 
 err_dec_users:
        atomic_dec(&sony_laptop_input.users);
@@ -500,7 +500,7 @@ static void sony_laptop_remove_input(void)
        }
 
        destroy_workqueue(sony_laptop_input.wq);
-       kfifo_free(sony_laptop_input.fifo);
+       kfifo_free(&sony_laptop_input.fifo);
 }
 
 /*********** Platform Device ***********/
@@ -2079,7 +2079,7 @@ static struct attribute_group spic_attribute_group = {
 
 struct sonypi_compat_s {
        struct fasync_struct    *fifo_async;
-       struct kfifo            *fifo;
+       struct kfifo            fifo;
        spinlock_t              fifo_lock;
        wait_queue_head_t       fifo_proc_list;
        atomic_t                open_count;
@@ -2104,12 +2104,12 @@ static int sonypi_misc_open(struct inode *inode, struct file *file)
        /* Flush input queue on first open */
        unsigned long flags;
 
-       spin_lock_irqsave(sonypi_compat.fifo->lock, flags);
+       spin_lock_irqsave(&sonypi_compat.fifo_lock, flags);
 
        if (atomic_inc_return(&sonypi_compat.open_count) == 1)
-               __kfifo_reset(sonypi_compat.fifo);
+               kfifo_reset(&sonypi_compat.fifo);
 
-       spin_unlock_irqrestore(sonypi_compat.fifo->lock, flags);
+       spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags);
 
        return 0;
 }
@@ -2120,17 +2120,18 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
        ssize_t ret;
        unsigned char c;
 
-       if ((kfifo_len(sonypi_compat.fifo) == 0) &&
+       if ((kfifo_len(&sonypi_compat.fifo) == 0) &&
            (file->f_flags & O_NONBLOCK))
                return -EAGAIN;
 
        ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
-                                      kfifo_len(sonypi_compat.fifo) != 0);
+                                      kfifo_len(&sonypi_compat.fifo) != 0);
        if (ret)
                return ret;
 
        while (ret < count &&
-              (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) {
+              (kfifo_out_locked(&sonypi_compat.fifo, &c, sizeof(c),
+                         &sonypi_compat.fifo_lock) == sizeof(c))) {
                if (put_user(c, buf++))
                        return -EFAULT;
                ret++;
@@ -2147,7 +2148,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
 static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
 {
        poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
-       if (kfifo_len(sonypi_compat.fifo))
+       if (kfifo_len(&sonypi_compat.fifo))
                return POLLIN | POLLRDNORM;
        return 0;
 }
@@ -2309,7 +2310,8 @@ static struct miscdevice sonypi_misc_device = {
 
 static void sonypi_compat_report_event(u8 event)
 {
-       kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event));
+       kfifo_in_locked(&sonypi_compat.fifo, (unsigned char *)&event,
+                       sizeof(event), &sonypi_compat.fifo_lock);
        kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
        wake_up_interruptible(&sonypi_compat.fifo_proc_list);
 }
@@ -2319,11 +2321,11 @@ static int sonypi_compat_init(void)
        int error;
 
        spin_lock_init(&sonypi_compat.fifo_lock);
-       sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
-                                        &sonypi_compat.fifo_lock);
-       if (IS_ERR(sonypi_compat.fifo)) {
+       error =
+        kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
+       if (error) {
                printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
-               return PTR_ERR(sonypi_compat.fifo);
+               return error;
        }
 
        init_waitqueue_head(&sonypi_compat.fifo_proc_list);
@@ -2342,14 +2344,14 @@ static int sonypi_compat_init(void)
        return 0;
 
 err_free_kfifo:
-       kfifo_free(sonypi_compat.fifo);
+       kfifo_free(&sonypi_compat.fifo);
        return error;
 }
 
 static void sonypi_compat_exit(void)
 {
        misc_deregister(&sonypi_misc_device);
-       kfifo_free(sonypi_compat.fifo);
+       kfifo_free(&sonypi_compat.fifo);
 }
 #else
 static int sonypi_compat_init(void) { return 0; }
index b7689f3..c28a712 100644 (file)
@@ -517,7 +517,7 @@ static void iscsi_free_task(struct iscsi_task *task)
        if (conn->login_task == task)
                return;
 
-       __kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*));
+       kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
 
        if (sc) {
                task->sc = NULL;
@@ -737,7 +737,7 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
                BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
 
-               if (!__kfifo_get(session->cmdpool.queue,
+               if (!kfifo_out(&session->cmdpool.queue,
                                 (void*)&task, sizeof(void*)))
                        return NULL;
        }
@@ -1567,7 +1567,7 @@ static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn,
 {
        struct iscsi_task *task;
 
-       if (!__kfifo_get(conn->session->cmdpool.queue,
+       if (!kfifo_out(&conn->session->cmdpool.queue,
                         (void *) &task, sizeof(void *)))
                return NULL;
 
@@ -2461,12 +2461,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
        if (q->pool == NULL)
                return -ENOMEM;
 
-       q->queue = kfifo_init((void*)q->pool, max * sizeof(void*),
-                             GFP_KERNEL, NULL);
-       if (IS_ERR(q->queue)) {
-               q->queue = NULL;
-               goto enomem;
-       }
+       kfifo_init(&q->queue, (void*)q->pool, max * sizeof(void*));
 
        for (i = 0; i < max; i++) {
                q->pool[i] = kzalloc(item_size, GFP_KERNEL);
@@ -2474,7 +2469,7 @@ iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size)
                        q->max = i;
                        goto enomem;
                }
-               __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*));
+               kfifo_in(&q->queue, (void*)&q->pool[i], sizeof(void*));
        }
 
        if (items) {
@@ -2497,7 +2492,6 @@ void iscsi_pool_free(struct iscsi_pool *q)
        for (i = 0; i < q->max; i++)
                kfree(q->pool[i]);
        kfree(q->pool);
-       kfree(q->queue);
 }
 EXPORT_SYMBOL_GPL(iscsi_pool_free);
 
@@ -2825,7 +2819,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
 
        /* allocate login_task used for the login/text sequences */
        spin_lock_bh(&session->lock);
-       if (!__kfifo_get(session->cmdpool.queue,
+       if (!kfifo_out(&session->cmdpool.queue,
                          (void*)&conn->login_task,
                         sizeof(void*))) {
                spin_unlock_bh(&session->lock);
@@ -2845,7 +2839,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
        return cls_conn;
 
 login_task_data_alloc_fail:
-       __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
+       kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
                    sizeof(void*));
 login_task_alloc_fail:
        iscsi_destroy_conn(cls_conn);
@@ -2908,7 +2902,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
        free_pages((unsigned long) conn->data,
                   get_order(ISCSI_DEF_MAX_RECV_SEG_LEN));
        kfree(conn->persistent_address);
-       __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task,
+       kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task,
                    sizeof(void*));
        if (session->leadconn == conn)
                session->leadconn = NULL;
index ca25ee5..db6856c 100644 (file)
@@ -445,15 +445,15 @@ void iscsi_tcp_cleanup_task(struct iscsi_task *task)
                return;
 
        /* flush task's r2t queues */
-       while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
-               __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+       while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) {
+               kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
                            sizeof(void*));
                ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n");
        }
 
        r2t = tcp_task->r2t;
        if (r2t != NULL) {
-               __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+               kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
                            sizeof(void*));
                tcp_task->r2t = NULL;
        }
@@ -541,7 +541,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
                return 0;
        }
 
-       rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
+       rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*));
        if (!rc) {
                iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. "
                                  "Target has sent more R2Ts than it "
@@ -554,7 +554,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
        if (r2t->data_length == 0) {
                iscsi_conn_printk(KERN_ERR, conn,
                                  "invalid R2T with zero data len\n");
-               __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+               kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
                            sizeof(void*));
                return ISCSI_ERR_DATALEN;
        }
@@ -570,7 +570,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
                                  "invalid R2T with data len %u at offset %u "
                                  "and total length %d\n", r2t->data_length,
                                  r2t->data_offset, scsi_out(task->sc)->length);
-               __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t,
+               kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t,
                            sizeof(void*));
                return ISCSI_ERR_DATALEN;
        }
@@ -580,7 +580,7 @@ static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task)
        r2t->sent = 0;
 
        tcp_task->exp_datasn = r2tsn + 1;
-       __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
+       kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*));
        conn->r2t_pdus_cnt++;
 
        iscsi_requeue_task(task);
@@ -951,7 +951,7 @@ int iscsi_tcp_task_init(struct iscsi_task *task)
                return conn->session->tt->init_pdu(task, 0, task->data_count);
        }
 
-       BUG_ON(__kfifo_len(tcp_task->r2tqueue));
+       BUG_ON(kfifo_len(&tcp_task->r2tqueue));
        tcp_task->exp_datasn = 0;
 
        /* Prepare PDU, optionally w/ immediate data */
@@ -982,7 +982,7 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
                        if (r2t->data_length <= r2t->sent) {
                                ISCSI_DBG_TCP(task->conn,
                                              "  done with r2t %p\n", r2t);
-                               __kfifo_put(tcp_task->r2tpool.queue,
+                               kfifo_in(&tcp_task->r2tpool.queue,
                                            (void *)&tcp_task->r2t,
                                            sizeof(void *));
                                tcp_task->r2t = r2t = NULL;
@@ -990,8 +990,13 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
                }
 
                if (r2t == NULL) {
-                       __kfifo_get(tcp_task->r2tqueue,
-                                   (void *)&tcp_task->r2t, sizeof(void *));
+                       if (kfifo_out(&tcp_task->r2tqueue,
+                           (void *)&tcp_task->r2t, sizeof(void *)) !=
+                           sizeof(void *)) {
+                               WARN_ONCE(1, "unexpected fifo state");
+                               r2t = NULL;
+                       }
+
                        r2t = tcp_task->r2t;
                }
                spin_unlock_bh(&session->lock);
@@ -1127,9 +1132,8 @@ int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session)
                }
 
                /* R2T xmit queue */
-               tcp_task->r2tqueue = kfifo_alloc(
-                     session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL);
-               if (tcp_task->r2tqueue == ERR_PTR(-ENOMEM)) {
+               if (kfifo_alloc(&tcp_task->r2tqueue,
+                     session->max_r2t * 4 * sizeof(void*), GFP_KERNEL)) {
                        iscsi_pool_free(&tcp_task->r2tpool);
                        goto r2t_alloc_fail;
                }
@@ -1142,7 +1146,7 @@ r2t_alloc_fail:
                struct iscsi_task *task = session->cmds[i];
                struct iscsi_tcp_task *tcp_task = task->dd_data;
 
-               kfifo_free(tcp_task->r2tqueue);
+               kfifo_free(&tcp_task->r2tqueue);
                iscsi_pool_free(&tcp_task->r2tpool);
        }
        return -ENOMEM;
@@ -1157,7 +1161,7 @@ void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
                struct iscsi_task *task = session->cmds[i];
                struct iscsi_tcp_task *tcp_task = task->dd_data;
 
-               kfifo_free(tcp_task->r2tqueue);
+               kfifo_free(&tcp_task->r2tqueue);
                iscsi_pool_free(&tcp_task->r2tpool);
        }
 }
index 9ad38e8..ab19b3b 100644 (file)
@@ -58,19 +58,15 @@ static int srp_iu_pool_alloc(struct srp_queue *q, size_t max,
                goto free_pool;
 
        spin_lock_init(&q->lock);
-       q->queue = kfifo_init((void *) q->pool, max * sizeof(void *),
-                             GFP_KERNEL, &q->lock);
-       if (IS_ERR(q->queue))
-               goto free_item;
+       kfifo_init(&q->queue, (void *) q->pool, max * sizeof(void *));
 
        for (i = 0, iue = q->items; i < max; i++) {
-               __kfifo_put(q->queue, (void *) &iue, sizeof(void *));
+               kfifo_in(&q->queue, (void *) &iue, sizeof(void *));
                iue->sbuf = ring[i];
                iue++;
        }
        return 0;
 
-free_item:
        kfree(q->items);
 free_pool:
        kfree(q->pool);
@@ -167,7 +163,11 @@ struct iu_entry *srp_iu_get(struct srp_target *target)
 {
        struct iu_entry *iue = NULL;
 
-       kfifo_get(target->iu_queue.queue, (void *) &iue, sizeof(void *));
+       if (kfifo_out_locked(&target->iu_queue.queue, (void *) &iue,
+               sizeof(void *), &target->iu_queue.lock) != sizeof(void *)) {
+                       WARN_ONCE(1, "unexpected fifo state");
+                       return NULL;
+       }
        if (!iue)
                return iue;
        iue->target = target;
@@ -179,7 +179,8 @@ EXPORT_SYMBOL_GPL(srp_iu_get);
 
 void srp_iu_put(struct iu_entry *iue)
 {
-       kfifo_put(iue->target->iu_queue.queue, (void *) &iue, sizeof(void *));
+       kfifo_in_locked(&iue->target->iu_queue.queue, (void *) &iue,
+                       sizeof(void *), &iue->target->iu_queue.lock);
 }
 EXPORT_SYMBOL_GPL(srp_iu_put);
 
index 6c5b261..aacd25b 100644 (file)
@@ -722,8 +722,6 @@ static int pohmelfs_remove_entry(struct inode *dir, struct dentry *dentry)
                if (inode->i_nlink)
                        inode_dec_link_count(inode);
        }
-       dprintk("%s: inode: %p, lock: %ld, unhashed: %d.\n",
-               __func__, pi, inode->i_state & I_LOCK, hlist_unhashed(&inode->i_hash));
 
        return err;
 }
index 00a2985..ff43747 100644 (file)
@@ -37,7 +37,7 @@ static void recycle_frame(struct fhci_usb *usb, struct packet *pkt)
        pkt->info = 0;
        pkt->priv_data = NULL;
 
-       cq_put(usb->ep0->empty_frame_Q, pkt);
+       cq_put(&usb->ep0->empty_frame_Q, pkt);
 }
 
 /* confirm submitted packet */
@@ -57,7 +57,7 @@ void fhci_transaction_confirm(struct fhci_usb *usb, struct packet *pkt)
                if ((td->data + td->actual_len) && trans_len)
                        memcpy(td->data + td->actual_len, pkt->data,
                               trans_len);
-               cq_put(usb->ep0->dummy_packets_Q, pkt->data);
+               cq_put(&usb->ep0->dummy_packets_Q, pkt->data);
        }
 
        recycle_frame(usb, pkt);
@@ -213,7 +213,7 @@ static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td)
        }
 
        /* update frame object fields before transmitting */
-       pkt = cq_get(usb->ep0->empty_frame_Q);
+       pkt = cq_get(&usb->ep0->empty_frame_Q);
        if (!pkt) {
                fhci_dbg(usb->fhci, "there is no empty frame\n");
                return -1;
@@ -222,7 +222,7 @@ static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td)
 
        pkt->info = 0;
        if (data == NULL) {
-               data = cq_get(usb->ep0->dummy_packets_Q);
+               data = cq_get(&usb->ep0->dummy_packets_Q);
                BUG_ON(!data);
                pkt->info = PKT_DUMMY_PACKET;
        }
@@ -246,7 +246,7 @@ static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td)
                list_del_init(&td->frame_lh);
                td->status = USB_TD_OK;
                if (pkt->info & PKT_DUMMY_PACKET)
-                       cq_put(usb->ep0->dummy_packets_Q, pkt->data);
+                       cq_put(&usb->ep0->dummy_packets_Q, pkt->data);
                recycle_frame(usb, pkt);
                usb->actual_frame->total_bytes -= (len + PROTOCOL_OVERHEAD);
                fhci_err(usb->fhci, "host transaction failed\n");
index b403322..d224ab4 100644 (file)
@@ -106,33 +106,33 @@ void fhci_ep0_free(struct fhci_usb *usb)
                        cpm_muram_free(cpm_muram_offset(ep->td_base));
 
                if (ep->conf_frame_Q) {
-                       size = cq_howmany(ep->conf_frame_Q);
+                       size = cq_howmany(&ep->conf_frame_Q);
                        for (; size; size--) {
-                               struct packet *pkt = cq_get(ep->conf_frame_Q);
+                               struct packet *pkt = cq_get(&ep->conf_frame_Q);
 
                                kfree(pkt);
                        }
-                       cq_delete(ep->conf_frame_Q);
+                       cq_delete(&ep->conf_frame_Q);
                }
 
                if (ep->empty_frame_Q) {
-                       size = cq_howmany(ep->empty_frame_Q);
+                       size = cq_howmany(&ep->empty_frame_Q);
                        for (; size; size--) {
-                               struct packet *pkt = cq_get(ep->empty_frame_Q);
+                               struct packet *pkt = cq_get(&ep->empty_frame_Q);
 
                                kfree(pkt);
                        }
-                       cq_delete(ep->empty_frame_Q);
+                       cq_delete(&ep->empty_frame_Q);
                }
 
                if (ep->dummy_packets_Q) {
-                       size = cq_howmany(ep->dummy_packets_Q);
+                       size = cq_howmany(&ep->dummy_packets_Q);
                        for (; size; size--) {
-                               u8 *buff = cq_get(ep->dummy_packets_Q);
+                               u8 *buff = cq_get(&ep->dummy_packets_Q);
 
                                kfree(buff);
                        }
-                       cq_delete(ep->dummy_packets_Q);
+                       cq_delete(&ep->dummy_packets_Q);
                }
 
                kfree(ep);
@@ -175,10 +175,9 @@ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem,
        ep->td_base = cpm_muram_addr(ep_offset);
 
        /* zero all queue pointers */
-       ep->conf_frame_Q = cq_new(ring_len + 2);
-       ep->empty_frame_Q = cq_new(ring_len + 2);
-       ep->dummy_packets_Q = cq_new(ring_len + 2);
-       if (!ep->conf_frame_Q || !ep->empty_frame_Q || !ep->dummy_packets_Q) {
+       if (cq_new(&ep->conf_frame_Q, ring_len + 2) ||
+           cq_new(&ep->empty_frame_Q, ring_len + 2) ||
+           cq_new(&ep->dummy_packets_Q, ring_len + 2)) {
                err_for = "frame_queues";
                goto err;
        }
@@ -199,8 +198,8 @@ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem,
                        err_for = "buffer";
                        goto err;
                }
-               cq_put(ep->empty_frame_Q, pkt);
-               cq_put(ep->dummy_packets_Q, buff);
+               cq_put(&ep->empty_frame_Q, pkt);
+               cq_put(&ep->dummy_packets_Q, buff);
        }
 
        /* we put the endpoint parameter RAM right behind the TD ring */
@@ -319,7 +318,7 @@ static void fhci_td_transaction_confirm(struct fhci_usb *usb)
                if ((buf == DUMMY2_BD_BUFFER) && !(td_status & ~TD_W))
                        continue;
 
-               pkt = cq_get(ep->conf_frame_Q);
+               pkt = cq_get(&ep->conf_frame_Q);
                if (!pkt)
                        fhci_err(usb->fhci, "no frame to confirm\n");
 
@@ -460,9 +459,9 @@ u32 fhci_host_transaction(struct fhci_usb *usb,
                out_be16(&td->length, pkt->len);
 
        /* put the frame to the confirmation queue */
-       cq_put(ep->conf_frame_Q, pkt);
+       cq_put(&ep->conf_frame_Q, pkt);
 
-       if (cq_howmany(ep->conf_frame_Q) == 1)
+       if (cq_howmany(&ep->conf_frame_Q) == 1)
                out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO);
 
        return 0;
index 7116284..72dae1c 100644 (file)
@@ -423,9 +423,9 @@ struct endpoint {
        struct usb_td __iomem *td_base; /* first TD in the ring */
        struct usb_td __iomem *conf_td; /* next TD for confirm after transac */
        struct usb_td __iomem *empty_td;/* next TD for new transaction req. */
-       struct kfifo *empty_frame_Q;  /* Empty frames list to use */
-       struct kfifo *conf_frame_Q;   /* frames passed to TDs,waiting for tx */
-       struct kfifo *dummy_packets_Q;/* dummy packets for the CRC overun */
+       struct kfifo empty_frame_Q;  /* Empty frames list to use */
+       struct kfifo conf_frame_Q;   /* frames passed to TDs,waiting for tx */
+       struct kfifo dummy_packets_Q;/* dummy packets for the CRC overun */
 
        bool already_pushed_dummy_bd;
 };
@@ -493,9 +493,9 @@ static inline struct usb_hcd *fhci_to_hcd(struct fhci_hcd *fhci)
 }
 
 /* fifo of pointers */
-static inline struct kfifo *cq_new(int size)
+static inline int cq_new(struct kfifo *fifo, int size)
 {
-       return kfifo_alloc(size * sizeof(void *), GFP_KERNEL, NULL);
+       return kfifo_alloc(fifo, size * sizeof(void *), GFP_KERNEL);
 }
 
 static inline void cq_delete(struct kfifo *kfifo)
@@ -505,19 +505,19 @@ static inline void cq_delete(struct kfifo *kfifo)
 
 static inline unsigned int cq_howmany(struct kfifo *kfifo)
 {
-       return __kfifo_len(kfifo) / sizeof(void *);
+       return kfifo_len(kfifo) / sizeof(void *);
 }
 
 static inline int cq_put(struct kfifo *kfifo, void *p)
 {
-       return __kfifo_put(kfifo, (void *)&p, sizeof(p));
+       return kfifo_in(kfifo, (void *)&p, sizeof(p));
 }
 
 static inline void *cq_get(struct kfifo *kfifo)
 {
        void *p = NULL;
 
-       __kfifo_get(kfifo, (void *)&p, sizeof(p));
+       kfifo_out(kfifo, (void *)&p, sizeof(p));
        return p;
 }
 
index bbe005c..f1ea3a3 100644 (file)
@@ -276,7 +276,7 @@ static int usb_serial_generic_write_start(struct usb_serial_port *port)
        if (port->write_urb_busy)
                start_io = false;
        else {
-               start_io = (__kfifo_len(port->write_fifo) != 0);
+               start_io = (kfifo_len(&port->write_fifo) != 0);
                port->write_urb_busy = start_io;
        }
        spin_unlock_irqrestore(&port->lock, flags);
@@ -285,7 +285,7 @@ static int usb_serial_generic_write_start(struct usb_serial_port *port)
                return 0;
 
        data = port->write_urb->transfer_buffer;
-       count = kfifo_get(port->write_fifo, data, port->bulk_out_size);
+       count = kfifo_out_locked(&port->write_fifo, data, port->bulk_out_size, &port->lock);
        usb_serial_debug_data(debug, &port->dev, __func__, count, data);
 
        /* set up our urb */
@@ -345,7 +345,7 @@ int usb_serial_generic_write(struct tty_struct *tty,
                return usb_serial_multi_urb_write(tty, port,
                                                  buf, count);
 
-       count = kfifo_put(port->write_fifo, buf, count);
+       count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock);
        result = usb_serial_generic_write_start(port);
 
        if (result >= 0)
@@ -370,7 +370,7 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
                                (serial->type->max_in_flight_urbs -
                                 port->urbs_in_flight);
        } else if (serial->num_bulk_out)
-               room = port->write_fifo->size - __kfifo_len(port->write_fifo);
+               room = kfifo_avail(&port->write_fifo);
        spin_unlock_irqrestore(&port->lock, flags);
 
        dbg("%s - returns %d", __func__, room);
@@ -391,7 +391,7 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
                chars = port->tx_bytes_flight;
                spin_unlock_irqrestore(&port->lock, flags);
        } else if (serial->num_bulk_out)
-               chars = kfifo_len(port->write_fifo);
+               chars = kfifo_len(&port->write_fifo);
 
        dbg("%s - returns %d", __func__, chars);
        return chars;
@@ -507,7 +507,7 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
                if (status) {
                        dbg("%s - nonzero multi-urb write bulk status "
                                "received: %d", __func__, status);
-                       kfifo_reset(port->write_fifo);
+                       kfifo_reset_out(&port->write_fifo);
                } else
                        usb_serial_generic_write_start(port);
        }
index 4543f35..33c85f7 100644 (file)
@@ -595,8 +595,7 @@ static void port_release(struct device *dev)
        usb_free_urb(port->write_urb);
        usb_free_urb(port->interrupt_in_urb);
        usb_free_urb(port->interrupt_out_urb);
-       if (!IS_ERR(port->write_fifo) && port->write_fifo)
-               kfifo_free(port->write_fifo);
+       kfifo_free(&port->write_fifo);
        kfree(port->bulk_in_buffer);
        kfree(port->bulk_out_buffer);
        kfree(port->interrupt_in_buffer);
@@ -939,9 +938,7 @@ int usb_serial_probe(struct usb_interface *interface,
                        dev_err(&interface->dev, "No free urbs available\n");
                        goto probe_error;
                }
-               port->write_fifo = kfifo_alloc(PAGE_SIZE, GFP_KERNEL,
-                       &port->lock);
-               if (IS_ERR(port->write_fifo))
+               if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
                        goto probe_error;
                buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
                port->bulk_out_size = buffer_size;
index 2c99459..9f0bf13 100644 (file)
@@ -121,13 +121,13 @@ struct file *anon_inode_getfile(const char *name,
        d_instantiate(path.dentry, anon_inode_inode);
 
        error = -ENFILE;
-       file = alloc_file(&path, FMODE_READ | FMODE_WRITE, fops);
+       file = alloc_file(&path, OPEN_FMODE(flags), fops);
        if (!file)
                goto err_dput;
        file->f_mapping = anon_inode_inode->i_mapping;
 
        file->f_pos = 0;
-       file->f_flags = O_RDWR | (flags & O_NONBLOCK);
+       file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
        file->f_version = 0;
        file->private_data = priv;
 
index 14cbc83..332dd00 100644 (file)
@@ -1600,8 +1600,6 @@ static long do_ioctl_trans(int fd, unsigned int cmd,
        case KDSKBMETA:
        case KDSKBLED:
        case KDSETLED:
-       /* SG stuff */
-       case SG_SET_TRANSFORM:
        /* AUTOFS */
        case AUTOFS_IOC_READY:
        case AUTOFS_IOC_FAIL:
index 8b47e42..d26402f 100644 (file)
@@ -339,7 +339,7 @@ struct file *eventfd_file_create(unsigned int count, int flags)
        ctx->flags = flags;
 
        file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx,
-                                 flags & EFD_SHARED_FCNTL_FLAGS);
+                                 O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS));
        if (IS_ERR(file))
                eventfd_free_ctx(ctx);
 
index 366c503..bd056a5 100644 (file)
@@ -1206,7 +1206,7 @@ SYSCALL_DEFINE1(epoll_create1, int, flags)
         * a file structure and a free file descriptor.
         */
        error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep,
-                                flags & O_CLOEXEC);
+                                O_RDWR | (flags & O_CLOEXEC));
        if (error < 0)
                ep_free(ep);
 
index ad14227..455e6e6 100644 (file)
@@ -970,7 +970,7 @@ static int ext3_get_block(struct inode *inode, sector_t iblock,
                if (max_blocks > DIO_MAX_BLOCKS)
                        max_blocks = DIO_MAX_BLOCKS;
                handle = ext3_journal_start(inode, DIO_CREDITS +
-                               2 * EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb));
+                               EXT3_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb));
                if (IS_ERR(handle)) {
                        ret = PTR_ERR(handle);
                        goto out;
@@ -3146,8 +3146,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
 
                /* (user+group)*(old+new) structure, inode write (sb,
                 * inode block, ? - but truncate inode update has it) */
-               handle = ext3_journal_start(inode, 2*(EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)+
-                                       EXT3_QUOTA_DEL_BLOCKS(inode->i_sb))+3);
+               handle = ext3_journal_start(inode, EXT3_MAXQUOTAS_INIT_BLOCKS(inode->i_sb)+
+                                       EXT3_MAXQUOTAS_DEL_BLOCKS(inode->i_sb)+3);
                if (IS_ERR(handle)) {
                        error = PTR_ERR(handle);
                        goto err_out;
@@ -3239,7 +3239,7 @@ static int ext3_writepage_trans_blocks(struct inode *inode)
 #ifdef CONFIG_QUOTA
        /* We know that structure was already allocated during vfs_dq_init so
         * we will be updating only the data blocks + inodes */
-       ret += 2*EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb);
+       ret += EXT3_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb);
 #endif
 
        return ret;
index aad6400..7b0e44f 100644 (file)
@@ -1699,7 +1699,7 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode,
 retry:
        handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
-                                       2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
+                                       EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -1733,7 +1733,7 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry,
 retry:
        handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
-                                       2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
+                                       EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -1769,7 +1769,7 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 retry:
        handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
-                                       2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
+                                       EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -1920,7 +1920,7 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode)
        struct ext3_iloc iloc;
        int err = 0, rc;
 
-       lock_super(sb);
+       mutex_lock(&EXT3_SB(sb)->s_orphan_lock);
        if (!list_empty(&EXT3_I(inode)->i_orphan))
                goto out_unlock;
 
@@ -1929,9 +1929,13 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode)
 
        /* @@@ FIXME: Observation from aviro:
         * I think I can trigger J_ASSERT in ext3_orphan_add().  We block
-        * here (on lock_super()), so race with ext3_link() which might bump
+        * here (on s_orphan_lock), so race with ext3_link() which might bump
         * ->i_nlink. For, say it, character device. Not a regular file,
         * not a directory, not a symlink and ->i_nlink > 0.
+        *
+        * tytso, 4/25/2009: I'm not sure how that could happen;
+        * shouldn't the fs core protect us from these sort of
+        * unlink()/link() races?
         */
        J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
                S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);
@@ -1968,7 +1972,7 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode)
        jbd_debug(4, "orphan inode %lu will point to %d\n",
                        inode->i_ino, NEXT_ORPHAN(inode));
 out_unlock:
-       unlock_super(sb);
+       mutex_unlock(&EXT3_SB(sb)->s_orphan_lock);
        ext3_std_error(inode->i_sb, err);
        return err;
 }
@@ -1986,11 +1990,9 @@ int ext3_orphan_del(handle_t *handle, struct inode *inode)
        struct ext3_iloc iloc;
        int err = 0;
 
-       lock_super(inode->i_sb);
-       if (list_empty(&ei->i_orphan)) {
-               unlock_super(inode->i_sb);
-               return 0;
-       }
+       mutex_lock(&EXT3_SB(inode->i_sb)->s_orphan_lock);
+       if (list_empty(&ei->i_orphan))
+               goto out;
 
        ino_next = NEXT_ORPHAN(inode);
        prev = ei->i_orphan.prev;
@@ -2040,7 +2042,7 @@ int ext3_orphan_del(handle_t *handle, struct inode *inode)
 out_err:
        ext3_std_error(inode->i_sb, err);
 out:
-       unlock_super(inode->i_sb);
+       mutex_unlock(&EXT3_SB(inode->i_sb)->s_orphan_lock);
        return err;
 
 out_brelse:
@@ -2175,7 +2177,7 @@ static int ext3_symlink (struct inode * dir,
 retry:
        handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
-                                       2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
+                                       EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
index 5f83b61..54351ac 100644 (file)
@@ -209,7 +209,7 @@ static int setup_new_group_blocks(struct super_block *sb,
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
-       lock_super(sb);
+       mutex_lock(&sbi->s_resize_lock);
        if (input->group != sbi->s_groups_count) {
                err = -EBUSY;
                goto exit_journal;
@@ -324,7 +324,7 @@ exit_bh:
        brelse(bh);
 
 exit_journal:
-       unlock_super(sb);
+       mutex_unlock(&sbi->s_resize_lock);
        if ((err2 = ext3_journal_stop(handle)) && !err)
                err = err2;
 
@@ -662,11 +662,12 @@ exit_free:
  * important part is that the new block and inode counts are in the backup
  * superblocks, and the location of the new group metadata in the GDT backups.
  *
- * We do not need lock_super() for this, because these blocks are not
- * otherwise touched by the filesystem code when it is mounted.  We don't
- * need to worry about last changing from sbi->s_groups_count, because the
- * worst that can happen is that we do not copy the full number of backups
- * at this time.  The resize which changed s_groups_count will backup again.
+ * We do not need take the s_resize_lock for this, because these
+ * blocks are not otherwise touched by the filesystem code when it is
+ * mounted.  We don't need to worry about last changing from
+ * sbi->s_groups_count, because the worst that can happen is that we
+ * do not copy the full number of backups at this time.  The resize
+ * which changed s_groups_count will backup again.
  */
 static void update_backups(struct super_block *sb,
                           int blk_off, char *data, int size)
@@ -825,7 +826,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
                goto exit_put;
        }
 
-       lock_super(sb);
+       mutex_lock(&sbi->s_resize_lock);
        if (input->group != sbi->s_groups_count) {
                ext3_warning(sb, __func__,
                             "multiple resizers run on filesystem!");
@@ -856,7 +857,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
        /*
         * OK, now we've set up the new group.  Time to make it active.
         *
-        * Current kernels don't lock all allocations via lock_super(),
+        * We do not lock all allocations via s_resize_lock
         * so we have to be safe wrt. concurrent accesses the group
         * data.  So we need to be careful to set all of the relevant
         * group descriptor data etc. *before* we enable the group.
@@ -900,12 +901,12 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
         *
         * The precise rules we use are:
         *
-        * * Writers of s_groups_count *must* hold lock_super
+        * * Writers of s_groups_count *must* hold s_resize_lock
         * AND
         * * Writers must perform a smp_wmb() after updating all dependent
         *   data and before modifying the groups count
         *
-        * * Readers must hold lock_super() over the access
+        * * Readers must hold s_resize_lock over the access
         * OR
         * * Readers must perform an smp_rmb() after reading the groups count
         *   and before reading any dependent data.
@@ -936,7 +937,7 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
        ext3_journal_dirty_metadata(handle, sbi->s_sbh);
 
 exit_journal:
-       unlock_super(sb);
+       mutex_unlock(&sbi->s_resize_lock);
        if ((err2 = ext3_journal_stop(handle)) && !err)
                err = err2;
        if (!err) {
@@ -973,7 +974,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
 
        /* We don't need to worry about locking wrt other resizers just
         * yet: we're going to revalidate es->s_blocks_count after
-        * taking lock_super() below. */
+        * taking the s_resize_lock below. */
        o_blocks_count = le32_to_cpu(es->s_blocks_count);
        o_groups_count = EXT3_SB(sb)->s_groups_count;
 
@@ -1045,11 +1046,11 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
                goto exit_put;
        }
 
-       lock_super(sb);
+       mutex_lock(&EXT3_SB(sb)->s_resize_lock);
        if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) {
                ext3_warning(sb, __func__,
                             "multiple resizers run on filesystem!");
-               unlock_super(sb);
+               mutex_unlock(&EXT3_SB(sb)->s_resize_lock);
                ext3_journal_stop(handle);
                err = -EBUSY;
                goto exit_put;
@@ -1059,13 +1060,13 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
                                                 EXT3_SB(sb)->s_sbh))) {
                ext3_warning(sb, __func__,
                             "error %d on journal write access", err);
-               unlock_super(sb);
+               mutex_unlock(&EXT3_SB(sb)->s_resize_lock);
                ext3_journal_stop(handle);
                goto exit_put;
        }
        es->s_blocks_count = cpu_to_le32(o_blocks_count + add);
        ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh);
-       unlock_super(sb);
+       mutex_unlock(&EXT3_SB(sb)->s_resize_lock);
        ext3_debug("freeing blocks %lu through "E3FSBLK"\n", o_blocks_count,
                   o_blocks_count + add);
        ext3_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks);
index 7ad1e8c..afa2b56 100644 (file)
@@ -1928,6 +1928,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        sb->dq_op = &ext3_quota_operations;
 #endif
        INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
+       mutex_init(&sbi->s_orphan_lock);
+       mutex_init(&sbi->s_resize_lock);
 
        sb->s_root = NULL;
 
@@ -2014,14 +2016,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        }
 
        ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
-       /*
-        * akpm: core read_super() calls in here with the superblock locked.
-        * That deadlocks, because orphan cleanup needs to lock the superblock
-        * in numerous places.  Here we just pop the lock - it's relatively
-        * harmless, because we are now ready to accept write_super() requests,
-        * and aviro says that's the only reason for hanging onto the
-        * superblock lock.
-        */
+
        EXT3_SB(sb)->s_mount_state |= EXT3_ORPHAN_FS;
        ext3_orphan_cleanup(sb, es);
        EXT3_SB(sb)->s_mount_state &= ~EXT3_ORPHAN_FS;
@@ -2403,13 +2398,11 @@ static void ext3_mark_recovery_complete(struct super_block * sb,
        if (journal_flush(journal) < 0)
                goto out;
 
-       lock_super(sb);
        if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) &&
            sb->s_flags & MS_RDONLY) {
                EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
                ext3_commit_super(sb, es, 1);
        }
-       unlock_super(sb);
 
 out:
        journal_unlock_updates(journal);
@@ -2601,13 +2594,7 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
                            (sbi->s_mount_state & EXT3_VALID_FS))
                                es->s_state = cpu_to_le16(sbi->s_mount_state);
 
-                       /*
-                        * We have to unlock super so that we can wait for
-                        * transactions.
-                        */
-                       unlock_super(sb);
                        ext3_mark_recovery_complete(sb, es);
-                       lock_super(sb);
                } else {
                        __le32 ret;
                        if ((ret = EXT3_HAS_RO_COMPAT_FEATURE(sb,
index ab31e65..56f9271 100644 (file)
@@ -704,6 +704,10 @@ struct ext4_inode_info {
        __u16 i_extra_isize;
 
        spinlock_t i_block_reservation_lock;
+#ifdef CONFIG_QUOTA
+       /* quota space reservation, managed internally by quota code */
+       qsize_t i_reserved_quota;
+#endif
 
        /* completed async DIOs that might need unwritten extents handling */
        struct list_head i_aio_dio_complete_list;
@@ -1435,7 +1439,7 @@ extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
 extern int ext4_block_truncate_page(handle_t *handle,
                struct address_space *mapping, loff_t from);
 extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
-extern qsize_t ext4_get_reserved_space(struct inode *inode);
+extern qsize_t *ext4_get_reserved_space(struct inode *inode);
 extern int flush_aio_dio_completed_IO(struct inode *inode);
 /* ioctl.c */
 extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
index 5352db1..ab80796 100644 (file)
@@ -1003,17 +1003,12 @@ out:
        return err;
 }
 
-qsize_t ext4_get_reserved_space(struct inode *inode)
+#ifdef CONFIG_QUOTA
+qsize_t *ext4_get_reserved_space(struct inode *inode)
 {
-       unsigned long long total;
-
-       spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
-       total = EXT4_I(inode)->i_reserved_data_blocks +
-               EXT4_I(inode)->i_reserved_meta_blocks;
-       spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
-
-       return (total << inode->i_blkbits);
+       return &EXT4_I(inode)->i_reserved_quota;
 }
+#endif
 /*
  * Calculate the number of metadata blocks need to reserve
  * to allocate @blocks for non extent file based file
@@ -1051,7 +1046,7 @@ static int ext4_calc_metadata_amount(struct inode *inode, int blocks)
 static void ext4_da_update_reserve_space(struct inode *inode, int used)
 {
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
-       int total, mdb, mdb_free;
+       int total, mdb, mdb_free, mdb_claim = 0;
 
        spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
        /* recalculate the number of metablocks still need to be reserved */
@@ -1064,7 +1059,9 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
 
        if (mdb_free) {
                /* Account for allocated meta_blocks */
-               mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks;
+               mdb_claim = EXT4_I(inode)->i_allocated_meta_blocks;
+               BUG_ON(mdb_free < mdb_claim);
+               mdb_free -= mdb_claim;
 
                /* update fs dirty blocks counter */
                percpu_counter_sub(&sbi->s_dirtyblocks_counter, mdb_free);
@@ -1075,8 +1072,11 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
        /* update per-inode reservations */
        BUG_ON(used  > EXT4_I(inode)->i_reserved_data_blocks);
        EXT4_I(inode)->i_reserved_data_blocks -= used;
+       percpu_counter_sub(&sbi->s_dirtyblocks_counter, used + mdb_claim);
        spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
 
+       vfs_dq_claim_block(inode, used + mdb_claim);
+
        /*
         * free those over-booking quota for metadata blocks
         */
@@ -1816,19 +1816,17 @@ repeat:
 
        md_needed = mdblocks - EXT4_I(inode)->i_reserved_meta_blocks;
        total = md_needed + nrblocks;
+       spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
 
        /*
         * Make quota reservation here to prevent quota overflow
         * later. Real quota accounting is done at pages writeout
         * time.
         */
-       if (vfs_dq_reserve_block(inode, total)) {
-               spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
+       if (vfs_dq_reserve_block(inode, total))
                return -EDQUOT;
-       }
 
        if (ext4_claim_free_blocks(sbi, total)) {
-               spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
                vfs_dq_release_reservation_block(inode, total);
                if (ext4_should_retry_alloc(inode->i_sb, &retries)) {
                        yield();
@@ -1836,10 +1834,11 @@ repeat:
                }
                return -ENOSPC;
        }
+       spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
        EXT4_I(inode)->i_reserved_data_blocks += nrblocks;
-       EXT4_I(inode)->i_reserved_meta_blocks = mdblocks;
-
+       EXT4_I(inode)->i_reserved_meta_blocks += md_needed;
        spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
+
        return 0;       /* success */
 }
 
@@ -4794,6 +4793,9 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
                        ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32;
        inode->i_size = ext4_isize(raw_inode);
        ei->i_disksize = inode->i_size;
+#ifdef CONFIG_QUOTA
+       ei->i_reserved_quota = 0;
+#endif
        inode->i_generation = le32_to_cpu(raw_inode->i_generation);
        ei->i_block_group = iloc.block_group;
        ei->i_last_alloc_group = ~0;
index b1fd3da..d34afad 100644 (file)
@@ -2755,12 +2755,6 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
        if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED))
                /* release all the reserved blocks if non delalloc */
                percpu_counter_sub(&sbi->s_dirtyblocks_counter, reserv_blks);
-       else {
-               percpu_counter_sub(&sbi->s_dirtyblocks_counter,
-                                               ac->ac_b_ex.fe_len);
-               /* convert reserved quota blocks to real quota blocks */
-               vfs_dq_claim_block(ac->ac_inode, ac->ac_b_ex.fe_len);
-       }
 
        if (sbi->s_log_groups_per_flex) {
                ext4_group_t flex_group = ext4_flex_group(sbi,
index 827bde1..6ed9aa9 100644 (file)
@@ -704,6 +704,9 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei->i_allocated_meta_blocks = 0;
        ei->i_delalloc_reserved_flag = 0;
        spin_lock_init(&(ei->i_block_reservation_lock));
+#ifdef CONFIG_QUOTA
+       ei->i_reserved_quota = 0;
+#endif
        INIT_LIST_HEAD(&ei->i_aio_dio_complete_list);
        ei->cur_aio_dio = NULL;
        ei->i_sync_tid = 0;
@@ -1014,7 +1017,9 @@ static const struct dquot_operations ext4_quota_operations = {
        .reserve_space  = dquot_reserve_space,
        .claim_space    = dquot_claim_space,
        .release_rsv    = dquot_release_reserved_space,
+#ifdef CONFIG_QUOTA
        .get_reserved_space = ext4_get_reserved_space,
+#endif
        .alloc_inode    = dquot_alloc_inode,
        .free_space     = dquot_free_space,
        .free_inode     = dquot_free_inode,
index 0afacf6..69652c5 100644 (file)
@@ -186,10 +186,8 @@ struct file *alloc_file(struct path *path, fmode_t mode,
         * that we can do debugging checks at __fput()
         */
        if ((mode & FMODE_WRITE) && !special_file(path->dentry->d_inode->i_mode)) {
-               int error = 0;
                file_take_write(file);
-               error = mnt_clone_write(path->mnt);
-               WARN_ON(error);
+               WARN_ON(mnt_clone_write(path->mnt));
        }
        ima_counts_get(file);
        return file;
index f67cd14..e96a166 100644 (file)
@@ -85,3 +85,10 @@ extern struct file *get_empty_filp(void);
  * super.c
  */
 extern int do_remount_sb(struct super_block *, int, void *, int);
+
+/*
+ * open.c
+ */
+struct nameidata;
+extern struct file *nameidata_to_filp(struct nameidata *);
+extern void release_open_intent(struct nameidata *);
index 4160afa..bd224ee 100644 (file)
@@ -1913,7 +1913,7 @@ static void __init jbd_create_debugfs_entry(void)
 {
        jbd_debugfs_dir = debugfs_create_dir("jbd", NULL);
        if (jbd_debugfs_dir)
-               jbd_debug = debugfs_create_u8("jbd-debug", S_IRUGO,
+               jbd_debug = debugfs_create_u8("jbd-debug", S_IRUGO | S_IWUSR,
                                               jbd_debugfs_dir,
                                               &journal_enable_debug);
 }
index b7ca3a9..17af879 100644 (file)
@@ -2115,7 +2115,8 @@ static void __init jbd2_create_debugfs_entry(void)
 {
        jbd2_debugfs_dir = debugfs_create_dir("jbd2", NULL);
        if (jbd2_debugfs_dir)
-               jbd2_debug = debugfs_create_u8(JBD2_DEBUG_NAME, S_IRUGO,
+               jbd2_debug = debugfs_create_u8(JBD2_DEBUG_NAME,
+                                              S_IRUGO | S_IWUSR,
                                               jbd2_debugfs_dir,
                                               &jbd2_journal_enable_debug);
 }
index 2234c73..d929a82 100644 (file)
@@ -524,7 +524,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
         * Page cache is indexed by long.
         * I would use MAX_LFS_FILESIZE, but it's only half as big
         */
-       sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, sb->s_maxbytes);
+       sb->s_maxbytes = min(((u64) PAGE_CACHE_SIZE << 32) - 1, (u64)sb->s_maxbytes);
 #endif
        sb->s_time_gran = 1;
        return 0;
index dad4b80..68921d9 100644 (file)
@@ -37,8 +37,6 @@
 
 #include "internal.h"
 
-#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
-
 /* [Feb-1997 T. Schoebel-Theuer]
  * Fundamental changes in the pathname lookup mechanisms (namei)
  * were necessary because of omirr.  The reason is that omirr needs
@@ -1640,6 +1638,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
                if (filp == NULL)
                        return ERR_PTR(-ENFILE);
                nd.intent.open.file = filp;
+               filp->f_flags = open_flag;
                nd.intent.open.flags = flag;
                nd.intent.open.create_mode = 0;
                error = do_path_lookup(dfd, pathname,
@@ -1685,6 +1684,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
        if (filp == NULL)
                goto exit_parent;
        nd.intent.open.file = filp;
+       filp->f_flags = open_flag;
        nd.intent.open.flags = flag;
        nd.intent.open.create_mode = mode;
        dir = nd.path.dentry;
@@ -1725,7 +1725,7 @@ do_last:
                        mnt_drop_write(nd.path.mnt);
                        goto exit;
                }
-               filp = nameidata_to_filp(&nd, open_flag);
+               filp = nameidata_to_filp(&nd);
                mnt_drop_write(nd.path.mnt);
                if (nd.root.mnt)
                        path_put(&nd.root);
@@ -1789,7 +1789,7 @@ ok:
                        mnt_drop_write(nd.path.mnt);
                goto exit;
        }
-       filp = nameidata_to_filp(&nd, open_flag);
+       filp = nameidata_to_filp(&nd);
        if (!IS_ERR(filp)) {
                error = ima_path_check(&filp->f_path, filp->f_mode &
                               (MAY_READ | MAY_WRITE | MAY_EXEC));
index ca69241..040cef7 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -821,15 +821,14 @@ static inline int __get_file_write_access(struct inode *inode,
 }
 
 static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
-                                       int flags, struct file *f,
+                                       struct file *f,
                                        int (*open)(struct inode *, struct file *),
                                        const struct cred *cred)
 {
        struct inode *inode;
        int error;
 
-       f->f_flags = flags;
-       f->f_mode = (__force fmode_t)((flags+1) & O_ACCMODE) | FMODE_LSEEK |
+       f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
                                FMODE_PREAD | FMODE_PWRITE;
        inode = dentry->d_inode;
        if (f->f_mode & FMODE_WRITE) {
@@ -930,7 +929,6 @@ struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry
        if (IS_ERR(dentry))
                goto out_err;
        nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt),
-                                            nd->intent.open.flags - 1,
                                             nd->intent.open.file,
                                             open, cred);
 out:
@@ -949,7 +947,7 @@ EXPORT_SYMBOL_GPL(lookup_instantiate_filp);
  *
  * Note that this function destroys the original nameidata
  */
-struct file *nameidata_to_filp(struct nameidata *nd, int flags)
+struct file *nameidata_to_filp(struct nameidata *nd)
 {
        const struct cred *cred = current_cred();
        struct file *filp;
@@ -958,7 +956,7 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags)
        filp = nd->intent.open.file;
        /* Has the filesystem initialised the file for us? */
        if (filp->f_path.dentry == NULL)
-               filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp,
+               filp = __dentry_open(nd->path.dentry, nd->path.mnt, filp,
                                     NULL, cred);
        else
                path_put(&nd->path);
@@ -997,7 +995,8 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags,
                return ERR_PTR(error);
        }
 
-       return __dentry_open(dentry, mnt, flags, f, NULL, cred);
+       f->f_flags = flags;
+       return __dentry_open(dentry, mnt, f, NULL, cred);
 }
 EXPORT_SYMBOL(dentry_open);
 
index cd6bb9a..dea86ab 100644 (file)
@@ -323,6 +323,30 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
 }
 EXPORT_SYMBOL(dquot_mark_dquot_dirty);
 
+/* Dirtify all the dquots - this can block when journalling */
+static inline int mark_all_dquot_dirty(struct dquot * const *dquot)
+{
+       int ret, err, cnt;
+
+       ret = err = 0;
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+               if (dquot[cnt])
+                       /* Even in case of error we have to continue */
+                       ret = mark_dquot_dirty(dquot[cnt]);
+               if (!err)
+                       err = ret;
+       }
+       return err;
+}
+
+static inline void dqput_all(struct dquot **dquot)
+{
+       unsigned int cnt;
+
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+               dqput(dquot[cnt]);
+}
+
 /* This function needs dq_list_lock */
 static inline int clear_dquot_dirty(struct dquot *dquot)
 {
@@ -1268,8 +1292,7 @@ int dquot_initialize(struct inode *inode, int type)
 out_err:
        up_write(&sb_dqopt(sb)->dqptr_sem);
        /* Drop unused references */
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               dqput(got[cnt]);
+       dqput_all(got);
        return ret;
 }
 EXPORT_SYMBOL(dquot_initialize);
@@ -1288,9 +1311,7 @@ int dquot_drop(struct inode *inode)
                inode->i_dquot[cnt] = NULL;
        }
        up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
-
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               dqput(put[cnt]);
+       dqput_all(put);
        return 0;
 }
 EXPORT_SYMBOL(dquot_drop);
@@ -1319,6 +1340,67 @@ void vfs_dq_drop(struct inode *inode)
 EXPORT_SYMBOL(vfs_dq_drop);
 
 /*
+ * inode_reserved_space is managed internally by quota, and protected by
+ * i_lock similar to i_blocks+i_bytes.
+ */
+static qsize_t *inode_reserved_space(struct inode * inode)
+{
+       /* Filesystem must explicitly define it's own method in order to use
+        * quota reservation interface */
+       BUG_ON(!inode->i_sb->dq_op->get_reserved_space);
+       return inode->i_sb->dq_op->get_reserved_space(inode);
+}
+
+static void inode_add_rsv_space(struct inode *inode, qsize_t number)
+{
+       spin_lock(&inode->i_lock);
+       *inode_reserved_space(inode) += number;
+       spin_unlock(&inode->i_lock);
+}
+
+
+static void inode_claim_rsv_space(struct inode *inode, qsize_t number)
+{
+       spin_lock(&inode->i_lock);
+       *inode_reserved_space(inode) -= number;
+       __inode_add_bytes(inode, number);
+       spin_unlock(&inode->i_lock);
+}
+
+static void inode_sub_rsv_space(struct inode *inode, qsize_t number)
+{
+       spin_lock(&inode->i_lock);
+       *inode_reserved_space(inode) -= number;
+       spin_unlock(&inode->i_lock);
+}
+
+static qsize_t inode_get_rsv_space(struct inode *inode)
+{
+       qsize_t ret;
+       spin_lock(&inode->i_lock);
+       ret = *inode_reserved_space(inode);
+       spin_unlock(&inode->i_lock);
+       return ret;
+}
+
+static void inode_incr_space(struct inode *inode, qsize_t number,
+                               int reserve)
+{
+       if (reserve)
+               inode_add_rsv_space(inode, number);
+       else
+               inode_add_bytes(inode, number);
+}
+
+static void inode_decr_space(struct inode *inode, qsize_t number, int reserve)
+{
+       if (reserve)
+               inode_sub_rsv_space(inode, number);
+       else
+               inode_sub_bytes(inode, number);
+}
+
+/*
  * Following four functions update i_blocks+i_bytes fields and
  * quota information (together with appropriate checks)
  * NOTE: We absolutely rely on the fact that caller dirties
@@ -1336,6 +1418,21 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number,
        int cnt, ret = QUOTA_OK;
        char warntype[MAXQUOTAS];
 
+       /*
+        * First test before acquiring mutex - solves deadlocks when we
+        * re-enter the quota code and are already holding the mutex
+        */
+       if (IS_NOQUOTA(inode)) {
+               inode_incr_space(inode, number, reserve);
+               goto out;
+       }
+
+       down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+       if (IS_NOQUOTA(inode)) {
+               inode_incr_space(inode, number, reserve);
+               goto out_unlock;
+       }
+
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
                warntype[cnt] = QUOTA_NL_NOWARN;
 
@@ -1346,7 +1443,8 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number,
                if (check_bdq(inode->i_dquot[cnt], number, warn, warntype+cnt)
                    == NO_QUOTA) {
                        ret = NO_QUOTA;
-                       goto out_unlock;
+                       spin_unlock(&dq_data_lock);
+                       goto out_flush_warn;
                }
        }
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1357,64 +1455,29 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number,
                else
                        dquot_incr_space(inode->i_dquot[cnt], number);
        }
-       if (!reserve)
-               inode_add_bytes(inode, number);
-out_unlock:
+       inode_incr_space(inode, number, reserve);
        spin_unlock(&dq_data_lock);
+
+       if (reserve)
+               goto out_flush_warn;
+       mark_all_dquot_dirty(inode->i_dquot);
+out_flush_warn:
        flush_warnings(inode->i_dquot, warntype);
+out_unlock:
+       up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
+out:
        return ret;
 }
 
 int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
 {
-       int cnt, ret = QUOTA_OK;
-
-       /*
-        * First test before acquiring mutex - solves deadlocks when we
-        * re-enter the quota code and are already holding the mutex
-        */
-       if (IS_NOQUOTA(inode)) {
-               inode_add_bytes(inode, number);
-               goto out;
-       }
-
-       down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       if (IS_NOQUOTA(inode)) {
-               inode_add_bytes(inode, number);
-               goto out_unlock;
-       }
-
-       ret = __dquot_alloc_space(inode, number, warn, 0);
-       if (ret == NO_QUOTA)
-               goto out_unlock;
-
-       /* Dirtify all the dquots - this can block when journalling */
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               if (inode->i_dquot[cnt])
-                       mark_dquot_dirty(inode->i_dquot[cnt]);
-out_unlock:
-       up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-out:
-       return ret;
+       return __dquot_alloc_space(inode, number, warn, 0);
 }
 EXPORT_SYMBOL(dquot_alloc_space);
 
 int dquot_reserve_space(struct inode *inode, qsize_t number, int warn)
 {
-       int ret = QUOTA_OK;
-
-       if (IS_NOQUOTA(inode))
-               goto out;
-
-       down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       if (IS_NOQUOTA(inode))
-               goto out_unlock;
-
-       ret = __dquot_alloc_space(inode, number, warn, 1);
-out_unlock:
-       up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-out:
-       return ret;
+       return __dquot_alloc_space(inode, number, warn, 1);
 }
 EXPORT_SYMBOL(dquot_reserve_space);
 
@@ -1455,10 +1518,7 @@ int dquot_alloc_inode(const struct inode *inode, qsize_t number)
 warn_put_all:
        spin_unlock(&dq_data_lock);
        if (ret == QUOTA_OK)
-               /* Dirtify all the dquots - this can block when journalling */
-               for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-                       if (inode->i_dquot[cnt])
-                               mark_dquot_dirty(inode->i_dquot[cnt]);
+               mark_all_dquot_dirty(inode->i_dquot);
        flush_warnings(inode->i_dquot, warntype);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
        return ret;
@@ -1471,14 +1531,14 @@ int dquot_claim_space(struct inode *inode, qsize_t number)
        int ret = QUOTA_OK;
 
        if (IS_NOQUOTA(inode)) {
-               inode_add_bytes(inode, number);
+               inode_claim_rsv_space(inode, number);
                goto out;
        }
 
        down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
        if (IS_NOQUOTA(inode))  {
                up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-               inode_add_bytes(inode, number);
+               inode_claim_rsv_space(inode, number);
                goto out;
        }
 
@@ -1490,12 +1550,9 @@ int dquot_claim_space(struct inode *inode, qsize_t number)
                                                        number);
        }
        /* Update inode bytes */
-       inode_add_bytes(inode, number);
+       inode_claim_rsv_space(inode, number);
        spin_unlock(&dq_data_lock);
-       /* Dirtify all the dquots - this can block when journalling */
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               if (inode->i_dquot[cnt])
-                       mark_dquot_dirty(inode->i_dquot[cnt]);
+       mark_all_dquot_dirty(inode->i_dquot);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
 out:
        return ret;
@@ -1503,38 +1560,9 @@ out:
 EXPORT_SYMBOL(dquot_claim_space);
 
 /*
- * Release reserved quota space
- */
-void dquot_release_reserved_space(struct inode *inode, qsize_t number)
-{
-       int cnt;
-
-       if (IS_NOQUOTA(inode))
-               goto out;
-
-       down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-       if (IS_NOQUOTA(inode))
-               goto out_unlock;
-
-       spin_lock(&dq_data_lock);
-       /* Release reserved dquots */
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (inode->i_dquot[cnt])
-                       dquot_free_reserved_space(inode->i_dquot[cnt], number);
-       }
-       spin_unlock(&dq_data_lock);
-
-out_unlock:
-       up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
-out:
-       return;
-}
-EXPORT_SYMBOL(dquot_release_reserved_space);
-
-/*
  * This operation can block, but only after everything is updated
  */
-int dquot_free_space(struct inode *inode, qsize_t number)
+int __dquot_free_space(struct inode *inode, qsize_t number, int reserve)
 {
        unsigned int cnt;
        char warntype[MAXQUOTAS];
@@ -1543,7 +1571,7 @@ int dquot_free_space(struct inode *inode, qsize_t number)
          * re-enter the quota code and are already holding the mutex */
        if (IS_NOQUOTA(inode)) {
 out_sub:
-               inode_sub_bytes(inode, number);
+               inode_decr_space(inode, number, reserve);
                return QUOTA_OK;
        }
 
@@ -1558,21 +1586,40 @@ out_sub:
                if (!inode->i_dquot[cnt])
                        continue;
                warntype[cnt] = info_bdq_free(inode->i_dquot[cnt], number);
-               dquot_decr_space(inode->i_dquot[cnt], number);
+               if (reserve)
+                       dquot_free_reserved_space(inode->i_dquot[cnt], number);
+               else
+                       dquot_decr_space(inode->i_dquot[cnt], number);
        }
-       inode_sub_bytes(inode, number);
+       inode_decr_space(inode, number, reserve);
        spin_unlock(&dq_data_lock);
-       /* Dirtify all the dquots - this can block when journalling */
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               if (inode->i_dquot[cnt])
-                       mark_dquot_dirty(inode->i_dquot[cnt]);
+
+       if (reserve)
+               goto out_unlock;
+       mark_all_dquot_dirty(inode->i_dquot);
+out_unlock:
        flush_warnings(inode->i_dquot, warntype);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
        return QUOTA_OK;
 }
+
+int dquot_free_space(struct inode *inode, qsize_t number)
+{
+       return  __dquot_free_space(inode, number, 0);
+}
 EXPORT_SYMBOL(dquot_free_space);
 
 /*
+ * Release reserved quota space
+ */
+void dquot_release_reserved_space(struct inode *inode, qsize_t number)
+{
+       __dquot_free_space(inode, number, 1);
+
+}
+EXPORT_SYMBOL(dquot_release_reserved_space);
+
+/*
  * This operation can block, but only after everything is updated
  */
 int dquot_free_inode(const struct inode *inode, qsize_t number)
@@ -1599,10 +1646,7 @@ int dquot_free_inode(const struct inode *inode, qsize_t number)
                dquot_decr_inodes(inode->i_dquot[cnt], number);
        }
        spin_unlock(&dq_data_lock);
-       /* Dirtify all the dquots - this can block when journalling */
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-               if (inode->i_dquot[cnt])
-                       mark_dquot_dirty(inode->i_dquot[cnt]);
+       mark_all_dquot_dirty(inode->i_dquot);
        flush_warnings(inode->i_dquot, warntype);
        up_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
        return QUOTA_OK;
@@ -1610,19 +1654,6 @@ int dquot_free_inode(const struct inode *inode, qsize_t number)
 EXPORT_SYMBOL(dquot_free_inode);
 
 /*
- * call back function, get reserved quota space from underlying fs
- */
-qsize_t dquot_get_reserved_space(struct inode *inode)
-{
-       qsize_t reserved_space = 0;
-
-       if (sb_any_quota_active(inode->i_sb) &&
-           inode->i_sb->dq_op->get_reserved_space)
-               reserved_space = inode->i_sb->dq_op->get_reserved_space(inode);
-       return reserved_space;
-}
-
-/*
  * Transfer the number of inode and blocks from one diskquota to an other.
  *
  * This operation can block, but only after everything is updated
@@ -1665,7 +1696,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
        }
        spin_lock(&dq_data_lock);
        cur_space = inode_get_bytes(inode);
-       rsv_space = dquot_get_reserved_space(inode);
+       rsv_space = inode_get_rsv_space(inode);
        space = cur_space + rsv_space;
        /* Build the transfer_from list and check the limits */
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1709,25 +1740,18 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
        spin_unlock(&dq_data_lock);
        up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
 
-       /* Dirtify all the dquots - this can block when journalling */
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               if (transfer_from[cnt])
-                       mark_dquot_dirty(transfer_from[cnt]);
-               if (transfer_to[cnt]) {
-                       mark_dquot_dirty(transfer_to[cnt]);
-                       /* The reference we got is transferred to the inode */
-                       transfer_to[cnt] = NULL;
-               }
-       }
+       mark_all_dquot_dirty(transfer_from);
+       mark_all_dquot_dirty(transfer_to);
+       /* The reference we got is transferred to the inode */
+       for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+               transfer_to[cnt] = NULL;
 warn_put_all:
        flush_warnings(transfer_to, warntype_to);
        flush_warnings(transfer_from, warntype_from_inodes);
        flush_warnings(transfer_from, warntype_from_space);
 put_all:
-       for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-               dqput(transfer_from[cnt]);
-               dqput(transfer_to[cnt]);
-       }
+       dqput_all(transfer_from);
+       dqput_all(transfer_to);
        return ret;
 over_quota:
        spin_unlock(&dq_data_lock);
index 3dfc23e..e3da02f 100644 (file)
@@ -97,8 +97,11 @@ static int v2_read_file_info(struct super_block *sb, int type)
        unsigned int version;
 
        if (!v2_read_header(sb, type, &dqhead))
-               return 0;
+               return -1;
        version = le32_to_cpu(dqhead.dqh_version);
+       if ((info->dqi_fmt_id == QFMT_VFS_V0 && version != 0) ||
+           (info->dqi_fmt_id == QFMT_VFS_V1 && version != 1))
+               return -1;
 
        size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
               sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
@@ -120,8 +123,8 @@ static int v2_read_file_info(struct super_block *sb, int type)
                info->dqi_maxilimit = 0xffffffff;
        } else {
                /* used space is stored as unsigned 64-bit value */
-               info->dqi_maxblimit = 0xffffffffffffffff;       /* 2^64-1 */
-               info->dqi_maxilimit = 0xffffffffffffffff;
+               info->dqi_maxblimit = 0xffffffffffffffffULL;    /* 2^64-1 */
+               info->dqi_maxilimit = 0xffffffffffffffffULL;
        }
        info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
        info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
index b07565c..1dabe4e 100644 (file)
@@ -236,7 +236,7 @@ SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask,
                 * anon_inode_getfd() will install the fd.
                 */
                ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx,
-                                      flags & (O_CLOEXEC | O_NONBLOCK));
+                                      O_RDWR | (flags & (O_CLOEXEC | O_NONBLOCK)));
                if (ufd < 0)
                        kfree(ctx);
        } else {
index 075694e..c4ecd52 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -401,9 +401,9 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, char __user *, filename,
 }
 #endif /* __ARCH_WANT_STAT64 */
 
-void inode_add_bytes(struct inode *inode, loff_t bytes)
+/* Caller is here responsible for sufficient locking (ie. inode->i_lock) */
+void __inode_add_bytes(struct inode *inode, loff_t bytes)
 {
-       spin_lock(&inode->i_lock);
        inode->i_blocks += bytes >> 9;
        bytes &= 511;
        inode->i_bytes += bytes;
@@ -411,6 +411,12 @@ void inode_add_bytes(struct inode *inode, loff_t bytes)
                inode->i_blocks++;
                inode->i_bytes -= 512;
        }
+}
+
+void inode_add_bytes(struct inode *inode, loff_t bytes)
+{
+       spin_lock(&inode->i_lock);
+       __inode_add_bytes(inode, bytes);
        spin_unlock(&inode->i_lock);
 }
 
index b042bd7..1bfc95a 100644 (file)
@@ -200,7 +200,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
        hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
 
        ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
-                              flags & TFD_SHARED_FCNTL_FLAGS);
+                              O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS));
        if (ufd < 0)
                kfree(ctx);
 
index 19ef8eb..71dafb6 100644 (file)
@@ -296,6 +296,7 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
 #define        DRM_MASTER      0x2
 #define DRM_ROOT_ONLY  0x4
 #define DRM_CONTROL_ALLOW 0x8
+#define DRM_UNLOCKED   0x10
 
 struct drm_ioctl_desc {
        unsigned int cmd;
@@ -1128,8 +1129,8 @@ static inline int drm_mtrr_del(int handle, unsigned long offset,
                                /* Driver support (drm_drv.h) */
 extern int drm_init(struct drm_driver *driver);
 extern void drm_exit(struct drm_driver *driver);
-extern int drm_ioctl(struct inode *inode, struct file *filp,
-                    unsigned int cmd, unsigned long arg);
+extern long drm_ioctl(struct file *filp,
+                     unsigned int cmd, unsigned long arg);
 extern long drm_compat_ioctl(struct file *filp,
                             unsigned int cmd, unsigned long arg);
 extern int drm_lastclose(struct drm_device *dev);
index f07f34d..258088a 100644 (file)
@@ -72,6 +72,8 @@ struct ext3_sb_info {
        struct inode * s_journal_inode;
        struct journal_s * s_journal;
        struct list_head s_orphan;
+       struct mutex s_orphan_lock;
+       struct mutex s_resize_lock;
        unsigned long s_commit_interval;
        struct block_device *journal_bdev;
 #ifdef CONFIG_JBD_DEBUG
index cf82d51..d7b5ddc 100644 (file)
 
 #define EXT3_DATA_TRANS_BLOCKS(sb)     (EXT3_SINGLEDATA_TRANS_BLOCKS + \
                                         EXT3_XATTR_TRANS_BLOCKS - 2 + \
-                                        2*EXT3_QUOTA_TRANS_BLOCKS(sb))
+                                        EXT3_MAXQUOTAS_TRANS_BLOCKS(sb))
 
 /* Delete operations potentially hit one directory's namespace plus an
  * entire inode, plus arbitrary amounts of bitmap/indirection data.  Be
  * generous.  We can grow the delete transaction later if necessary. */
 
-#define EXT3_DELETE_TRANS_BLOCKS(sb)   (2 * EXT3_DATA_TRANS_BLOCKS(sb) + 64)
+#define EXT3_DELETE_TRANS_BLOCKS(sb)   (EXT3_MAXQUOTAS_TRANS_BLOCKS(sb) + 64)
 
 /* Define an arbitrary limit for the amount of data we will anticipate
  * writing to any given transaction.  For unbounded transactions such as
@@ -86,6 +86,9 @@
 #define EXT3_QUOTA_INIT_BLOCKS(sb) 0
 #define EXT3_QUOTA_DEL_BLOCKS(sb) 0
 #endif
+#define EXT3_MAXQUOTAS_TRANS_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_TRANS_BLOCKS(sb))
+#define EXT3_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_INIT_BLOCKS(sb))
+#define EXT3_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT3_QUOTA_DEL_BLOCKS(sb))
 
 int
 ext3_mark_iloc_dirty(handle_t *handle,
index cca1919..9147ca8 100644 (file)
@@ -1624,8 +1624,6 @@ struct super_operations {
  *                     on the bit address once it is done.
  *
  * Q: What is the difference between I_WILL_FREE and I_FREEING?
- * Q: igrab() only checks on (I_FREEING|I_WILL_FREE).  Should it also check on
- *    I_CLEAR?  If not, why?
  */
 #define I_DIRTY_SYNC           1
 #define I_DIRTY_DATASYNC       2
@@ -2299,6 +2297,7 @@ extern const struct inode_operations page_symlink_inode_operations;
 extern int generic_readlink(struct dentry *, char __user *, int);
 extern void generic_fillattr(struct inode *, struct kstat *);
 extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+void __inode_add_bytes(struct inode *inode, loff_t bytes);
 void inode_add_bytes(struct inode *inode, loff_t bytes);
 void inode_sub_bytes(struct inode *inode, loff_t bytes);
 loff_t inode_get_bytes(struct inode *inode);
@@ -2464,5 +2463,8 @@ int proc_nr_files(struct ctl_table *table, int write,
 
 int __init get_filesystem_list(char *buf);
 
+#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
+#define OPEN_FMODE(flag) ((__force fmode_t)((flag + 1) & O_ACCMODE))
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_FS_H */
index ad6bdf5..486e8ad 100644 (file)
@@ -1,6 +1,7 @@
 /*
- * A simple kernel FIFO implementation.
+ * A generic kernel FIFO implementation.
  *
+ * Copyright (C) 2009 Stefani Seibold <stefani@seibold.net>
  * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
+
+/*
+ * Howto porting drivers to the new generic fifo API:
+ *
+ * - Modify the declaration of the "struct kfifo *" object into a
+ *   in-place "struct kfifo" object
+ * - Init the in-place object with kfifo_alloc() or kfifo_init()
+ *   Note: The address of the in-place "struct kfifo" object must be
+ *   passed as the first argument to this functions
+ * - Replace the use of __kfifo_put into kfifo_in and __kfifo_get
+ *   into kfifo_out
+ * - Replace the use of kfifo_put into kfifo_in_locked and kfifo_get
+ *   into kfifo_out_locked
+ *   Note: the spinlock pointer formerly passed to kfifo_init/kfifo_alloc
+ *   must be passed now to the kfifo_in_locked and kfifo_out_locked
+ *   as the last parameter.
+ * - All formerly name __kfifo_* functions has been renamed into kfifo_*
+ */
+
 #ifndef _LINUX_KFIFO_H
 #define _LINUX_KFIFO_H
 
@@ -29,124 +49,563 @@ struct kfifo {
        unsigned int size;      /* the size of the allocated buffer */
        unsigned int in;        /* data is added at offset (in % size) */
        unsigned int out;       /* data is extracted from off. (out % size) */
-       spinlock_t *lock;       /* protects concurrent modifications */
 };
 
-extern struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
-                               gfp_t gfp_mask, spinlock_t *lock);
-extern struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask,
-                                spinlock_t *lock);
+/*
+ * Macros for declaration and initialization of the kfifo datatype
+ */
+
+/* helper macro */
+#define __kfifo_initializer(s, b) \
+       (struct kfifo) { \
+               .size   = s, \
+               .in     = 0, \
+               .out    = 0, \
+               .buffer = b \
+       }
+
+/**
+ * DECLARE_KFIFO - macro to declare a kfifo and the associated buffer
+ * @name: name of the declared kfifo datatype
+ * @size: size of the fifo buffer
+ *
+ * Note: the macro can be used inside struct or union declaration
+ * Note: the macro creates two objects:
+ *  A kfifo object with the given name and a buffer for the kfifo
+ *  object named name##kfifo_buffer
+ */
+#define DECLARE_KFIFO(name, size) \
+union { \
+       struct kfifo name; \
+       unsigned char name##kfifo_buffer[size + sizeof(struct kfifo)]; \
+}
+
+/**
+ * INIT_KFIFO - Initialize a kfifo declared by DECLARED_KFIFO
+ * @name: name of the declared kfifo datatype
+ * @size: size of the fifo buffer
+ */
+#define INIT_KFIFO(name) \
+       name = __kfifo_initializer(sizeof(name##kfifo_buffer) - \
+                               sizeof(struct kfifo), name##kfifo_buffer)
+
+/**
+ * DEFINE_KFIFO - macro to define and initialize a kfifo
+ * @name: name of the declared kfifo datatype
+ * @size: size of the fifo buffer
+ *
+ * Note: the macro can be used for global and local kfifo data type variables
+ * Note: the macro creates two objects:
+ *  A kfifo object with the given name and a buffer for the kfifo
+ *  object named name##kfifo_buffer
+ */
+#define DEFINE_KFIFO(name, size) \
+       unsigned char name##kfifo_buffer[size]; \
+       struct kfifo name = __kfifo_initializer(size, name##kfifo_buffer)
+
+#undef __kfifo_initializer
+
+extern void kfifo_init(struct kfifo *fifo, unsigned char *buffer,
+                       unsigned int size);
+extern __must_check int kfifo_alloc(struct kfifo *fifo, unsigned int size,
+                       gfp_t gfp_mask);
 extern void kfifo_free(struct kfifo *fifo);
-extern unsigned int __kfifo_put(struct kfifo *fifo,
-                               const unsigned char *buffer, unsigned int len);
-extern unsigned int __kfifo_get(struct kfifo *fifo,
-                               unsigned char *buffer, unsigned int len);
+extern unsigned int kfifo_in(struct kfifo *fifo,
+                               const unsigned char *from, unsigned int len);
+extern __must_check unsigned int kfifo_out(struct kfifo *fifo,
+                               unsigned char *to, unsigned int len);
 
 /**
- * __kfifo_reset - removes the entire FIFO contents, no locking version
+ * kfifo_reset - removes the entire FIFO contents
  * @fifo: the fifo to be emptied.
  */
-static inline void __kfifo_reset(struct kfifo *fifo)
+static inline void kfifo_reset(struct kfifo *fifo)
 {
        fifo->in = fifo->out = 0;
 }
 
 /**
- * kfifo_reset - removes the entire FIFO contents
+ * kfifo_reset_out - skip FIFO contents
  * @fifo: the fifo to be emptied.
  */
-static inline void kfifo_reset(struct kfifo *fifo)
+static inline void kfifo_reset_out(struct kfifo *fifo)
 {
-       unsigned long flags;
+       smp_mb();
+       fifo->out = fifo->in;
+}
 
-       spin_lock_irqsave(fifo->lock, flags);
+/**
+ * kfifo_size - returns the size of the fifo in bytes
+ * @fifo: the fifo to be used.
+ */
+static inline __must_check unsigned int kfifo_size(struct kfifo *fifo)
+{
+       return fifo->size;
+}
 
-       __kfifo_reset(fifo);
+/**
+ * kfifo_len - returns the number of used bytes in the FIFO
+ * @fifo: the fifo to be used.
+ */
+static inline unsigned int kfifo_len(struct kfifo *fifo)
+{
+       register unsigned int   out;
 
-       spin_unlock_irqrestore(fifo->lock, flags);
+       out = fifo->out;
+       smp_rmb();
+       return fifo->in - out;
 }
 
 /**
- * kfifo_put - puts some data into the FIFO
+ * kfifo_is_empty - returns true if the fifo is empty
  * @fifo: the fifo to be used.
- * @buffer: the data to be added.
- * @len: the length of the data to be added.
+ */
+static inline __must_check int kfifo_is_empty(struct kfifo *fifo)
+{
+       return fifo->in == fifo->out;
+}
+
+/**
+ * kfifo_is_full - returns true if the fifo is full
+ * @fifo: the fifo to be used.
+ */
+static inline __must_check int kfifo_is_full(struct kfifo *fifo)
+{
+       return kfifo_len(fifo) == kfifo_size(fifo);
+}
+
+/**
+ * kfifo_avail - returns the number of bytes available in the FIFO
+ * @fifo: the fifo to be used.
+ */
+static inline __must_check unsigned int kfifo_avail(struct kfifo *fifo)
+{
+       return kfifo_size(fifo) - kfifo_len(fifo);
+}
+
+/**
+ * kfifo_in_locked - puts some data into the FIFO using a spinlock for locking
+ * @fifo: the fifo to be used.
+ * @from: the data to be added.
+ * @n: the length of the data to be added.
+ * @lock: pointer to the spinlock to use for locking.
  *
- * This function copies at most @len bytes from the @buffer into
+ * This function copies at most @len bytes from the @from buffer into
  * the FIFO depending on the free space, and returns the number of
  * bytes copied.
  */
-static inline unsigned int kfifo_put(struct kfifo *fifo,
-                               const unsigned char *buffer, unsigned int len)
+static inline unsigned int kfifo_in_locked(struct kfifo *fifo,
+               const unsigned char *from, unsigned int n, spinlock_t *lock)
 {
        unsigned long flags;
        unsigned int ret;
 
-       spin_lock_irqsave(fifo->lock, flags);
+       spin_lock_irqsave(lock, flags);
 
-       ret = __kfifo_put(fifo, buffer, len);
+       ret = kfifo_in(fifo, from, n);
 
-       spin_unlock_irqrestore(fifo->lock, flags);
+       spin_unlock_irqrestore(lock, flags);
 
        return ret;
 }
 
 /**
- * kfifo_get - gets some data from the FIFO
+ * kfifo_out_locked - gets some data from the FIFO using a spinlock for locking
  * @fifo: the fifo to be used.
- * @buffer: where the data must be copied.
- * @len: the size of the destination buffer.
+ * @to: where the data must be copied.
+ * @n: the size of the destination buffer.
+ * @lock: pointer to the spinlock to use for locking.
  *
  * This function copies at most @len bytes from the FIFO into the
- * @buffer and returns the number of copied bytes.
+ * @to buffer and returns the number of copied bytes.
  */
-static inline unsigned int kfifo_get(struct kfifo *fifo,
-                                    unsigned char *buffer, unsigned int len)
+static inline __must_check unsigned int kfifo_out_locked(struct kfifo *fifo,
+       unsigned char *to, unsigned int n, spinlock_t *lock)
 {
        unsigned long flags;
        unsigned int ret;
 
-       spin_lock_irqsave(fifo->lock, flags);
+       spin_lock_irqsave(lock, flags);
 
-       ret = __kfifo_get(fifo, buffer, len);
+       ret = kfifo_out(fifo, to, n);
 
        /*
         * optimization: if the FIFO is empty, set the indices to 0
         * so we don't wrap the next time
         */
-       if (fifo->in == fifo->out)
-               fifo->in = fifo->out = 0;
+       if (kfifo_is_empty(fifo))
+               kfifo_reset(fifo);
+
+       spin_unlock_irqrestore(lock, flags);
+
+       return ret;
+}
+
+extern void kfifo_skip(struct kfifo *fifo, unsigned int len);
+
+extern __must_check unsigned int kfifo_from_user(struct kfifo *fifo,
+       const void __user *from, unsigned int n);
+
+extern __must_check unsigned int kfifo_to_user(struct kfifo *fifo,
+       void __user *to, unsigned int n);
+
+/**
+ * __kfifo_add_out internal helper function for updating the out offset
+ */
+static inline void __kfifo_add_out(struct kfifo *fifo,
+                               unsigned int off)
+{
+       smp_mb();
+       fifo->out += off;
+}
+
+/**
+ * __kfifo_add_in internal helper function for updating the in offset
+ */
+static inline void __kfifo_add_in(struct kfifo *fifo,
+                               unsigned int off)
+{
+       smp_wmb();
+       fifo->in += off;
+}
+
+/**
+ * __kfifo_off internal helper function for calculating the index of a
+ * given offeset
+ */
+static inline unsigned int __kfifo_off(struct kfifo *fifo, unsigned int off)
+{
+       return off & (fifo->size - 1);
+}
+
+/**
+ * __kfifo_peek_n internal helper function for determinate the length of
+ * the next record in the fifo
+ */
+static inline unsigned int __kfifo_peek_n(struct kfifo *fifo,
+                               unsigned int recsize)
+{
+#define __KFIFO_GET(fifo, off, shift) \
+       ((fifo)->buffer[__kfifo_off((fifo), (fifo)->out+(off))] << (shift))
+
+       unsigned int l;
+
+       l = __KFIFO_GET(fifo, 0, 0);
+
+       if (--recsize)
+               l |= __KFIFO_GET(fifo, 1, 8);
+
+       return l;
+#undef __KFIFO_GET
+}
+
+/**
+ * __kfifo_poke_n internal helper function for storing the length of
+ * the next record into the fifo
+ */
+static inline void __kfifo_poke_n(struct kfifo *fifo,
+                       unsigned int recsize, unsigned int n)
+{
+#define __KFIFO_PUT(fifo, off, val, shift) \
+               ( \
+               (fifo)->buffer[__kfifo_off((fifo), (fifo)->in+(off))] = \
+               (unsigned char)((val) >> (shift)) \
+               )
 
-       spin_unlock_irqrestore(fifo->lock, flags);
+       __KFIFO_PUT(fifo, 0, n, 0);
 
+       if (--recsize)
+               __KFIFO_PUT(fifo, 1, n, 8);
+#undef __KFIFO_PUT
+}
+
+/**
+ * __kfifo_in_... internal functions for put date into the fifo
+ * do not call it directly, use kfifo_in_rec() instead
+ */
+extern unsigned int __kfifo_in_n(struct kfifo *fifo,
+       const void *from, unsigned int n, unsigned int recsize);
+
+extern unsigned int __kfifo_in_generic(struct kfifo *fifo,
+       const void *from, unsigned int n, unsigned int recsize);
+
+static inline unsigned int __kfifo_in_rec(struct kfifo *fifo,
+       const void *from, unsigned int n, unsigned int recsize)
+{
+       unsigned int ret;
+
+       ret = __kfifo_in_n(fifo, from, n, recsize);
+
+       if (likely(ret == 0)) {
+               if (recsize)
+                       __kfifo_poke_n(fifo, recsize, n);
+               __kfifo_add_in(fifo, n + recsize);
+       }
        return ret;
 }
 
 /**
- * __kfifo_len - returns the number of bytes available in the FIFO, no locking version
+ * kfifo_in_rec - puts some record data into the FIFO
  * @fifo: the fifo to be used.
+ * @from: the data to be added.
+ * @n: the length of the data to be added.
+ * @recsize: size of record field
+ *
+ * This function copies @n bytes from the @from into the FIFO and returns
+ * the number of bytes which cannot be copied.
+ * A returned value greater than the @n value means that the record doesn't
+ * fit into the buffer.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
  */
-static inline unsigned int __kfifo_len(struct kfifo *fifo)
+static inline __must_check unsigned int kfifo_in_rec(struct kfifo *fifo,
+       void *from, unsigned int n, unsigned int recsize)
 {
-       return fifo->in - fifo->out;
+       if (!__builtin_constant_p(recsize))
+               return __kfifo_in_generic(fifo, from, n, recsize);
+       return __kfifo_in_rec(fifo, from, n, recsize);
 }
 
 /**
- * kfifo_len - returns the number of bytes available in the FIFO
+ * __kfifo_out_... internal functions for get date from the fifo
+ * do not call it directly, use kfifo_out_rec() instead
+ */
+extern unsigned int __kfifo_out_n(struct kfifo *fifo,
+       void *to, unsigned int reclen, unsigned int recsize);
+
+extern unsigned int __kfifo_out_generic(struct kfifo *fifo,
+       void *to, unsigned int n,
+       unsigned int recsize, unsigned int *total);
+
+static inline unsigned int __kfifo_out_rec(struct kfifo *fifo,
+       void *to, unsigned int n, unsigned int recsize,
+       unsigned int *total)
+{
+       unsigned int l;
+
+       if (!recsize) {
+               l = n;
+               if (total)
+                       *total = l;
+       } else {
+               l = __kfifo_peek_n(fifo, recsize);
+               if (total)
+                       *total = l;
+               if (n < l)
+                       return l;
+       }
+
+       return __kfifo_out_n(fifo, to, l, recsize);
+}
+
+/**
+ * kfifo_out_rec - gets some record data from the FIFO
  * @fifo: the fifo to be used.
+ * @to: where the data must be copied.
+ * @n: the size of the destination buffer.
+ * @recsize: size of record field
+ * @total: pointer where the total number of to copied bytes should stored
+ *
+ * This function copies at most @n bytes from the FIFO to @to and returns the
+ * number of bytes which cannot be copied.
+ * A returned value greater than the @n value means that the record doesn't
+ * fit into the @to buffer.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
  */
-static inline unsigned int kfifo_len(struct kfifo *fifo)
+static inline __must_check unsigned int kfifo_out_rec(struct kfifo *fifo,
+       void *to, unsigned int n, unsigned int recsize,
+       unsigned int *total)
+
 {
-       unsigned long flags;
-       unsigned int ret;
+       if (!__builtin_constant_p(recsize))
+               return __kfifo_out_generic(fifo, to, n, recsize, total);
+       return __kfifo_out_rec(fifo, to, n, recsize, total);
+}
+
+/**
+ * __kfifo_from_user_... internal functions for transfer from user space into
+ * the fifo. do not call it directly, use kfifo_from_user_rec() instead
+ */
+extern unsigned int __kfifo_from_user_n(struct kfifo *fifo,
+       const void __user *from, unsigned int n, unsigned int recsize);
 
-       spin_lock_irqsave(fifo->lock, flags);
+extern unsigned int __kfifo_from_user_generic(struct kfifo *fifo,
+       const void __user *from, unsigned int n, unsigned int recsize);
 
-       ret = __kfifo_len(fifo);
+static inline unsigned int __kfifo_from_user_rec(struct kfifo *fifo,
+       const void __user *from, unsigned int n, unsigned int recsize)
+{
+       unsigned int ret;
 
-       spin_unlock_irqrestore(fifo->lock, flags);
+       ret = __kfifo_from_user_n(fifo, from, n, recsize);
 
+       if (likely(ret == 0)) {
+               if (recsize)
+                       __kfifo_poke_n(fifo, recsize, n);
+               __kfifo_add_in(fifo, n + recsize);
+       }
        return ret;
 }
 
+/**
+ * kfifo_from_user_rec - puts some data from user space into the FIFO
+ * @fifo: the fifo to be used.
+ * @from: pointer to the data to be added.
+ * @n: the length of the data to be added.
+ * @recsize: size of record field
+ *
+ * This function copies @n bytes from the @from into the
+ * FIFO and returns the number of bytes which cannot be copied.
+ *
+ * If the returned value is equal or less the @n value, the copy_from_user()
+ * functions has failed. Otherwise the record doesn't fit into the buffer.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+static inline __must_check unsigned int kfifo_from_user_rec(struct kfifo *fifo,
+       const void __user *from, unsigned int n, unsigned int recsize)
+{
+       if (!__builtin_constant_p(recsize))
+               return __kfifo_from_user_generic(fifo, from, n, recsize);
+       return __kfifo_from_user_rec(fifo, from, n, recsize);
+}
+
+/**
+ * __kfifo_to_user_... internal functions for transfer fifo data into user space
+ * do not call it directly, use kfifo_to_user_rec() instead
+ */
+extern unsigned int __kfifo_to_user_n(struct kfifo *fifo,
+       void __user *to, unsigned int n, unsigned int reclen,
+       unsigned int recsize);
+
+extern unsigned int __kfifo_to_user_generic(struct kfifo *fifo,
+       void __user *to, unsigned int n, unsigned int recsize,
+       unsigned int *total);
+
+static inline unsigned int __kfifo_to_user_rec(struct kfifo *fifo,
+       void __user *to, unsigned int n,
+       unsigned int recsize, unsigned int *total)
+{
+       unsigned int l;
+
+       if (!recsize) {
+               l = n;
+               if (total)
+                       *total = l;
+       } else {
+               l = __kfifo_peek_n(fifo, recsize);
+               if (total)
+                       *total = l;
+               if (n < l)
+                       return l;
+       }
+
+       return __kfifo_to_user_n(fifo, to, n, l, recsize);
+}
+
+/**
+ * kfifo_to_user_rec - gets data from the FIFO and write it to user space
+ * @fifo: the fifo to be used.
+ * @to: where the data must be copied.
+ * @n: the size of the destination buffer.
+ * @recsize: size of record field
+ * @total: pointer where the total number of to copied bytes should stored
+ *
+ * This function copies at most @n bytes from the FIFO to the @to.
+ * In case of an error, the function returns the number of bytes which cannot
+ * be copied.
+ * If the returned value is equal or less the @n value, the copy_to_user()
+ * functions has failed. Otherwise the record doesn't fit into the @to buffer.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+static inline __must_check unsigned int kfifo_to_user_rec(struct kfifo *fifo,
+               void __user *to, unsigned int n, unsigned int recsize,
+               unsigned int *total)
+{
+       if (!__builtin_constant_p(recsize))
+               return __kfifo_to_user_generic(fifo, to, n, recsize, total);
+       return __kfifo_to_user_rec(fifo, to, n, recsize, total);
+}
+
+/**
+ * __kfifo_peek_... internal functions for peek into the next fifo record
+ * do not call it directly, use kfifo_peek_rec() instead
+ */
+extern unsigned int __kfifo_peek_generic(struct kfifo *fifo,
+                               unsigned int recsize);
+
+/**
+ * kfifo_peek_rec - gets the size of the next FIFO record data
+ * @fifo: the fifo to be used.
+ * @recsize: size of record field
+ *
+ * This function returns the size of the next FIFO record in number of bytes
+ */
+static inline __must_check unsigned int kfifo_peek_rec(struct kfifo *fifo,
+       unsigned int recsize)
+{
+       if (!__builtin_constant_p(recsize))
+               return __kfifo_peek_generic(fifo, recsize);
+       if (!recsize)
+               return kfifo_len(fifo);
+       return __kfifo_peek_n(fifo, recsize);
+}
+
+/**
+ * __kfifo_skip_... internal functions for skip the next fifo record
+ * do not call it directly, use kfifo_skip_rec() instead
+ */
+extern void __kfifo_skip_generic(struct kfifo *fifo, unsigned int recsize);
+
+static inline void __kfifo_skip_rec(struct kfifo *fifo,
+       unsigned int recsize)
+{
+       unsigned int l;
+
+       if (recsize) {
+               l = __kfifo_peek_n(fifo, recsize);
+
+               if (l + recsize <= kfifo_len(fifo)) {
+                       __kfifo_add_out(fifo, l + recsize);
+                       return;
+               }
+       }
+       kfifo_reset_out(fifo);
+}
+
+/**
+ * kfifo_skip_rec - skip the next fifo out record
+ * @fifo: the fifo to be used.
+ * @recsize: size of record field
+ *
+ * This function skips the next FIFO record
+ */
+static inline void kfifo_skip_rec(struct kfifo *fifo,
+       unsigned int recsize)
+{
+       if (!__builtin_constant_p(recsize))
+               __kfifo_skip_generic(fifo, recsize);
+       else
+               __kfifo_skip_rec(fifo, recsize);
+}
+
+/**
+ * kfifo_avail_rec - returns the number of bytes available in a record FIFO
+ * @fifo: the fifo to be used.
+ * @recsize: size of record field
+ */
+static inline __must_check unsigned int kfifo_avail_rec(struct kfifo *fifo,
+       unsigned int recsize)
+{
+       unsigned int l = kfifo_size(fifo) - kfifo_len(fifo);
+
+       return (l > recsize) ? l - recsize : 0;
+}
+
 #endif
index 37fa19b..1adfe77 100644 (file)
@@ -50,6 +50,19 @@ struct memory_notify {
        int status_change_nid;
 };
 
+/*
+ * During pageblock isolation, count the number of pages within the
+ * range [start_pfn, start_pfn + nr_pages) which are owned by code
+ * in the notifier chain.
+ */
+#define MEM_ISOLATE_COUNT      (1<<0)
+
+struct memory_isolate_notify {
+       unsigned long start_pfn;        /* Start of range to check */
+       unsigned int nr_pages;          /* # pages in range to check */
+       unsigned int pages_found;       /* # pages owned found by callbacks */
+};
+
 struct notifier_block;
 struct mem_section;
 
@@ -76,14 +89,28 @@ static inline int memory_notify(unsigned long val, void *v)
 {
        return 0;
 }
+static inline int register_memory_isolate_notifier(struct notifier_block *nb)
+{
+       return 0;
+}
+static inline void unregister_memory_isolate_notifier(struct notifier_block *nb)
+{
+}
+static inline int memory_isolate_notify(unsigned long val, void *v)
+{
+       return 0;
+}
 #else
 extern int register_memory_notifier(struct notifier_block *nb);
 extern void unregister_memory_notifier(struct notifier_block *nb);
+extern int register_memory_isolate_notifier(struct notifier_block *nb);
+extern void unregister_memory_isolate_notifier(struct notifier_block *nb);
 extern int register_new_memory(int, struct mem_section *);
 extern int unregister_memory_section(struct mem_section *);
 extern int memory_dev_init(void);
 extern int remove_memory_block(unsigned long, struct mem_section *, int);
 extern int memory_notify(unsigned long val, void *v);
+extern int memory_isolate_notify(unsigned long val, void *v);
 extern struct memory_block *find_memory_block(struct mem_section *);
 #define CONFIG_MEM_BLOCK_SIZE  (PAGES_PER_SECTION<<PAGE_SHIFT)
 enum mem_add_context { BOOT, HOTPLUG };
index 0289467..05b441d 100644 (file)
@@ -72,8 +72,6 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
 
 extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
                int (*open)(struct inode *, struct file *));
-extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
-extern void release_open_intent(struct nameidata *);
 
 extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
 
index e70e621..a6861f1 100644 (file)
@@ -315,8 +315,9 @@ struct dquot_operations {
        int (*claim_space) (struct inode *, qsize_t);
        /* release rsved quota for delayed alloc */
        void (*release_rsv) (struct inode *, qsize_t);
-       /* get reserved quota for delayed alloc */
-       qsize_t (*get_reserved_space) (struct inode *);
+       /* get reserved quota for delayed alloc, value returned is managed by
+        * quota code only */
+       qsize_t *(*get_reserved_space) (struct inode *);
 };
 
 /* Operations handling requests from userspace */
index acf6e45..1819396 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kref.h>
 #include <linux/mutex.h>
 #include <linux/sysrq.h>
+#include <linux/kfifo.h>
 
 #define SERIAL_TTY_MAJOR       188     /* Nice legal number now */
 #define SERIAL_TTY_MINORS      254     /* loads of devices :) */
@@ -94,7 +95,7 @@ struct usb_serial_port {
        unsigned char           *bulk_out_buffer;
        int                     bulk_out_size;
        struct urb              *write_urb;
-       struct kfifo            *write_fifo;
+       struct kfifo            write_fifo;
        int                     write_urb_busy;
        __u8                    bulk_out_endpointAddress;
 
index 7394e3b..ff92b46 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mutex.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
+#include <linux/kfifo.h>
 #include <scsi/iscsi_proto.h>
 #include <scsi/iscsi_if.h>
 #include <scsi/scsi_transport_iscsi.h>
@@ -231,7 +232,7 @@ struct iscsi_conn {
 };
 
 struct iscsi_pool {
-       struct kfifo            *queue;         /* FIFO Queue */
+       struct kfifo            queue;          /* FIFO Queue */
        void                    **pool;         /* Pool of elements */
        int                     max;            /* Max number of elements */
 };
index 9e3182e..741ae7e 100644 (file)
@@ -80,7 +80,7 @@ struct iscsi_tcp_task {
        int                     data_offset;
        struct iscsi_r2t_info   *r2t;           /* in progress solict R2T */
        struct iscsi_pool       r2tpool;
-       struct kfifo            *r2tqueue;
+       struct kfifo            r2tqueue;
        void                    *dd_data;
 };
 
index ba615e4..07e3add 100644 (file)
@@ -21,7 +21,7 @@ struct srp_buf {
 struct srp_queue {
        void *pool;
        void *items;
-       struct kfifo *queue;
+       struct kfifo queue;
        spinlock_t lock;
 };
 
index 267e484..fc0f928 100644 (file)
@@ -250,7 +250,6 @@ struct audit_context {
 #endif
 };
 
-#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE])
 static inline int open_arg(int flags, int mask)
 {
        int n = ACC_MODE(flags);
index 3765ff3..e92d519 100644 (file)
@@ -1,6 +1,7 @@
 /*
- * A simple kernel FIFO implementation.
+ * A generic kernel FIFO implementation.
  *
+ * Copyright (C) 2009 Stefani Seibold <stefani@seibold.net>
  * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/err.h>
 #include <linux/kfifo.h>
 #include <linux/log2.h>
+#include <linux/uaccess.h>
+
+static void _kfifo_init(struct kfifo *fifo, unsigned char *buffer,
+               unsigned int size)
+{
+       fifo->buffer = buffer;
+       fifo->size = size;
+
+       kfifo_reset(fifo);
+}
 
 /**
- * kfifo_init - allocates a new FIFO using a preallocated buffer
+ * kfifo_init - initialize a FIFO using a preallocated buffer
+ * @fifo: the fifo to assign the buffer
  * @buffer: the preallocated buffer to be used.
  * @size: the size of the internal buffer, this have to be a power of 2.
- * @gfp_mask: get_free_pages mask, passed to kmalloc()
- * @lock: the lock to be used to protect the fifo buffer
  *
- * Do NOT pass the kfifo to kfifo_free() after use! Simply free the
- * &struct kfifo with kfree().
  */
-struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
-                        gfp_t gfp_mask, spinlock_t *lock)
+void kfifo_init(struct kfifo *fifo, unsigned char *buffer, unsigned int size)
 {
-       struct kfifo *fifo;
-
        /* size must be a power of 2 */
        BUG_ON(!is_power_of_2(size));
 
-       fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
-       if (!fifo)
-               return ERR_PTR(-ENOMEM);
-
-       fifo->buffer = buffer;
-       fifo->size = size;
-       fifo->in = fifo->out = 0;
-       fifo->lock = lock;
-
-       return fifo;
+       _kfifo_init(fifo, buffer, size);
 }
 EXPORT_SYMBOL(kfifo_init);
 
 /**
- * kfifo_alloc - allocates a new FIFO and its internal buffer
- * @size: the size of the internal buffer to be allocated.
+ * kfifo_alloc - allocates a new FIFO internal buffer
+ * @fifo: the fifo to assign then new buffer
+ * @size: the size of the buffer to be allocated, this have to be a power of 2.
  * @gfp_mask: get_free_pages mask, passed to kmalloc()
- * @lock: the lock to be used to protect the fifo buffer
+ *
+ * This function dynamically allocates a new fifo internal buffer
  *
  * The size will be rounded-up to a power of 2.
+ * The buffer will be release with kfifo_free().
+ * Return 0 if no error, otherwise the an error code
  */
-struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock)
+int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask)
 {
        unsigned char *buffer;
-       struct kfifo *ret;
 
        /*
         * round up to the next power of 2, since our 'let the indices
@@ -80,48 +79,91 @@ struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock)
        }
 
        buffer = kmalloc(size, gfp_mask);
-       if (!buffer)
-               return ERR_PTR(-ENOMEM);
-
-       ret = kfifo_init(buffer, size, gfp_mask, lock);
+       if (!buffer) {
+               _kfifo_init(fifo, 0, 0);
+               return -ENOMEM;
+       }
 
-       if (IS_ERR(ret))
-               kfree(buffer);
+       _kfifo_init(fifo, buffer, size);
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(kfifo_alloc);
 
 /**
- * kfifo_free - frees the FIFO
+ * kfifo_free - frees the FIFO internal buffer
  * @fifo: the fifo to be freed.
  */
 void kfifo_free(struct kfifo *fifo)
 {
        kfree(fifo->buffer);
-       kfree(fifo);
 }
 EXPORT_SYMBOL(kfifo_free);
 
 /**
- * __kfifo_put - puts some data into the FIFO, no locking version
+ * kfifo_skip - skip output data
  * @fifo: the fifo to be used.
- * @buffer: the data to be added.
- * @len: the length of the data to be added.
- *
- * This function copies at most @len bytes from the @buffer into
- * the FIFO depending on the free space, and returns the number of
- * bytes copied.
- *
- * Note that with only one concurrent reader and one concurrent
- * writer, you don't need extra locking to use these functions.
+ * @len: number of bytes to skip
  */
-unsigned int __kfifo_put(struct kfifo *fifo,
-                       const unsigned char *buffer, unsigned int len)
+void kfifo_skip(struct kfifo *fifo, unsigned int len)
+{
+       if (len < kfifo_len(fifo)) {
+               __kfifo_add_out(fifo, len);
+               return;
+       }
+       kfifo_reset_out(fifo);
+}
+EXPORT_SYMBOL(kfifo_skip);
+
+static inline void __kfifo_in_data(struct kfifo *fifo,
+               const void *from, unsigned int len, unsigned int off)
 {
        unsigned int l;
 
-       len = min(len, fifo->size - fifo->in + fifo->out);
+       /*
+        * Ensure that we sample the fifo->out index -before- we
+        * start putting bytes into the kfifo.
+        */
+
+       smp_mb();
+
+       off = __kfifo_off(fifo, fifo->in + off);
+
+       /* first put the data starting from fifo->in to buffer end */
+       l = min(len, fifo->size - off);
+       memcpy(fifo->buffer + off, from, l);
+
+       /* then put the rest (if any) at the beginning of the buffer */
+       memcpy(fifo->buffer, from + l, len - l);
+}
+
+static inline void __kfifo_out_data(struct kfifo *fifo,
+               void *to, unsigned int len, unsigned int off)
+{
+       unsigned int l;
+
+       /*
+        * Ensure that we sample the fifo->in index -before- we
+        * start removing bytes from the kfifo.
+        */
+
+       smp_rmb();
+
+       off = __kfifo_off(fifo, fifo->out + off);
+
+       /* first get the data from fifo->out until the end of the buffer */
+       l = min(len, fifo->size - off);
+       memcpy(to, fifo->buffer + off, l);
+
+       /* then get the rest (if any) from the beginning of the buffer */
+       memcpy(to + l, fifo->buffer, len - l);
+}
+
+static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo,
+        const void __user *from, unsigned int len, unsigned int off)
+{
+       unsigned int l;
+       int ret;
 
        /*
         * Ensure that we sample the fifo->out index -before- we
@@ -130,68 +172,229 @@ unsigned int __kfifo_put(struct kfifo *fifo,
 
        smp_mb();
 
+       off = __kfifo_off(fifo, fifo->in + off);
+
        /* first put the data starting from fifo->in to buffer end */
-       l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
-       memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
+       l = min(len, fifo->size - off);
+       ret = copy_from_user(fifo->buffer + off, from, l);
+
+       if (unlikely(ret))
+               return ret + len - l;
 
        /* then put the rest (if any) at the beginning of the buffer */
-       memcpy(fifo->buffer, buffer + l, len - l);
+       return copy_from_user(fifo->buffer, from + l, len - l);
+}
+
+static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo,
+               void __user *to, unsigned int len, unsigned int off)
+{
+       unsigned int l;
+       int ret;
 
        /*
-        * Ensure that we add the bytes to the kfifo -before-
-        * we update the fifo->in index.
+        * Ensure that we sample the fifo->in index -before- we
+        * start removing bytes from the kfifo.
         */
 
-       smp_wmb();
+       smp_rmb();
+
+       off = __kfifo_off(fifo, fifo->out + off);
+
+       /* first get the data from fifo->out until the end of the buffer */
+       l = min(len, fifo->size - off);
+       ret = copy_to_user(to, fifo->buffer + off, l);
+
+       if (unlikely(ret))
+               return ret + len - l;
+
+       /* then get the rest (if any) from the beginning of the buffer */
+       return copy_to_user(to + l, fifo->buffer, len - l);
+}
+
+unsigned int __kfifo_in_n(struct kfifo *fifo,
+       const void *from, unsigned int len, unsigned int recsize)
+{
+       if (kfifo_avail(fifo) < len + recsize)
+               return len + 1;
+
+       __kfifo_in_data(fifo, from, len, recsize);
+       return 0;
+}
+EXPORT_SYMBOL(__kfifo_in_n);
 
-       fifo->in += len;
+/**
+ * kfifo_in - puts some data into the FIFO
+ * @fifo: the fifo to be used.
+ * @from: the data to be added.
+ * @len: the length of the data to be added.
+ *
+ * This function copies at most @len bytes from the @from buffer into
+ * the FIFO depending on the free space, and returns the number of
+ * bytes copied.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+unsigned int kfifo_in(struct kfifo *fifo, const unsigned char *from,
+                               unsigned int len)
+{
+       len = min(kfifo_avail(fifo), len);
 
+       __kfifo_in_data(fifo, from, len, 0);
+       __kfifo_add_in(fifo, len);
        return len;
 }
-EXPORT_SYMBOL(__kfifo_put);
+EXPORT_SYMBOL(kfifo_in);
+
+unsigned int __kfifo_in_generic(struct kfifo *fifo,
+       const void *from, unsigned int len, unsigned int recsize)
+{
+       return __kfifo_in_rec(fifo, from, len, recsize);
+}
+EXPORT_SYMBOL(__kfifo_in_generic);
+
+unsigned int __kfifo_out_n(struct kfifo *fifo,
+       void *to, unsigned int len, unsigned int recsize)
+{
+       if (kfifo_len(fifo) < len + recsize)
+               return len;
+
+       __kfifo_out_data(fifo, to, len, recsize);
+       __kfifo_add_out(fifo, len + recsize);
+       return 0;
+}
+EXPORT_SYMBOL(__kfifo_out_n);
 
 /**
- * __kfifo_get - gets some data from the FIFO, no locking version
+ * kfifo_out - gets some data from the FIFO
  * @fifo: the fifo to be used.
- * @buffer: where the data must be copied.
+ * @to: where the data must be copied.
  * @len: the size of the destination buffer.
  *
  * This function copies at most @len bytes from the FIFO into the
- * @buffer and returns the number of copied bytes.
+ * @to buffer and returns the number of copied bytes.
  *
  * Note that with only one concurrent reader and one concurrent
  * writer, you don't need extra locking to use these functions.
  */
-unsigned int __kfifo_get(struct kfifo *fifo,
-                        unsigned char *buffer, unsigned int len)
+unsigned int kfifo_out(struct kfifo *fifo, unsigned char *to, unsigned int len)
 {
-       unsigned int l;
+       len = min(kfifo_len(fifo), len);
 
-       len = min(len, fifo->in - fifo->out);
+       __kfifo_out_data(fifo, to, len, 0);
+       __kfifo_add_out(fifo, len);
 
-       /*
-        * Ensure that we sample the fifo->in index -before- we
-        * start removing bytes from the kfifo.
-        */
+       return len;
+}
+EXPORT_SYMBOL(kfifo_out);
 
-       smp_rmb();
+unsigned int __kfifo_out_generic(struct kfifo *fifo,
+       void *to, unsigned int len, unsigned int recsize,
+       unsigned int *total)
+{
+       return __kfifo_out_rec(fifo, to, len, recsize, total);
+}
+EXPORT_SYMBOL(__kfifo_out_generic);
 
-       /* first get the data from fifo->out until the end of the buffer */
-       l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
-       memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
+unsigned int __kfifo_from_user_n(struct kfifo *fifo,
+       const void __user *from, unsigned int len, unsigned int recsize)
+{
+       if (kfifo_avail(fifo) < len + recsize)
+               return len + 1;
 
-       /* then get the rest (if any) from the beginning of the buffer */
-       memcpy(buffer + l, fifo->buffer, len - l);
+       return __kfifo_from_user_data(fifo, from, len, recsize);
+}
+EXPORT_SYMBOL(__kfifo_from_user_n);
 
-       /*
-        * Ensure that we remove the bytes from the kfifo -before-
-        * we update the fifo->out index.
-        */
+/**
+ * kfifo_from_user - puts some data from user space into the FIFO
+ * @fifo: the fifo to be used.
+ * @from: pointer to the data to be added.
+ * @len: the length of the data to be added.
+ *
+ * This function copies at most @len bytes from the @from into the
+ * FIFO depending and returns the number of copied bytes.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+unsigned int kfifo_from_user(struct kfifo *fifo,
+       const void __user *from, unsigned int len)
+{
+       len = min(kfifo_avail(fifo), len);
+       len -= __kfifo_from_user_data(fifo, from, len, 0);
+       __kfifo_add_in(fifo, len);
+       return len;
+}
+EXPORT_SYMBOL(kfifo_from_user);
 
-       smp_mb();
+unsigned int __kfifo_from_user_generic(struct kfifo *fifo,
+       const void __user *from, unsigned int len, unsigned int recsize)
+{
+       return __kfifo_from_user_rec(fifo, from, len, recsize);
+}
+EXPORT_SYMBOL(__kfifo_from_user_generic);
 
-       fifo->out += len;
+unsigned int __kfifo_to_user_n(struct kfifo *fifo,
+       void __user *to, unsigned int len, unsigned int reclen,
+       unsigned int recsize)
+{
+       unsigned int ret;
+
+       if (kfifo_len(fifo) < reclen + recsize)
+               return len;
+
+       ret = __kfifo_to_user_data(fifo, to, reclen, recsize);
 
+       if (likely(ret == 0))
+               __kfifo_add_out(fifo, reclen + recsize);
+
+       return ret;
+}
+EXPORT_SYMBOL(__kfifo_to_user_n);
+
+/**
+ * kfifo_to_user - gets data from the FIFO and write it to user space
+ * @fifo: the fifo to be used.
+ * @to: where the data must be copied.
+ * @len: the size of the destination buffer.
+ *
+ * This function copies at most @len bytes from the FIFO into the
+ * @to buffer and returns the number of copied bytes.
+ *
+ * Note that with only one concurrent reader and one concurrent
+ * writer, you don't need extra locking to use these functions.
+ */
+unsigned int kfifo_to_user(struct kfifo *fifo,
+       void __user *to, unsigned int len)
+{
+       len = min(kfifo_len(fifo), len);
+       len -= __kfifo_to_user_data(fifo, to, len, 0);
+       __kfifo_add_out(fifo, len);
        return len;
 }
-EXPORT_SYMBOL(__kfifo_get);
+EXPORT_SYMBOL(kfifo_to_user);
+
+unsigned int __kfifo_to_user_generic(struct kfifo *fifo,
+       void __user *to, unsigned int len, unsigned int recsize,
+       unsigned int *total)
+{
+       return __kfifo_to_user_rec(fifo, to, len, recsize, total);
+}
+EXPORT_SYMBOL(__kfifo_to_user_generic);
+
+unsigned int __kfifo_peek_generic(struct kfifo *fifo, unsigned int recsize)
+{
+       if (recsize == 0)
+               return kfifo_avail(fifo);
+
+       return __kfifo_peek_n(fifo, recsize);
+}
+EXPORT_SYMBOL(__kfifo_peek_generic);
+
+void __kfifo_skip_generic(struct kfifo *fifo, unsigned int recsize)
+{
+       __kfifo_skip_rec(fifo, recsize);
+}
+EXPORT_SYMBOL(__kfifo_skip_generic);
+
index e0eb4a2..1f38270 100644 (file)
@@ -4724,7 +4724,7 @@ SYSCALL_DEFINE5(perf_event_open,
        if (IS_ERR(event))
                goto err_put_context;
 
-       err = anon_inode_getfd("[perf_event]", &perf_fops, event, 0);
+       err = anon_inode_getfd("[perf_event]", &perf_fops, event, O_RDWR);
        if (err < 0)
                goto err_free_put_context;
 
index dc15686..af96c1e 100644 (file)
@@ -308,37 +308,37 @@ static int find_resource(struct resource *root, struct resource *new,
                         void *alignf_data)
 {
        struct resource *this = root->child;
-       resource_size_t start, end;
+       struct resource tmp = *new;
 
-       start = root->start;
+       tmp.start = root->start;
        /*
         * Skip past an allocated resource that starts at 0, since the assignment
-        * of this->start - 1 to new->end below would cause an underflow.
+        * of this->start - 1 to tmp->end below would cause an underflow.
         */
        if (this && this->start == 0) {
-               start = this->end + 1;
+               tmp.start = this->end + 1;
                this = this->sibling;
        }
        for(;;) {
                if (this)
-                       end = this->start - 1;
+                       tmp.end = this->start - 1;
                else
-                       end = root->end;
-               if (start < min)
-                       start = min;
-               if (end > max)
-                       end = max;
-               start = ALIGN(start, align);
+                       tmp.end = root->end;
+               if (tmp.start < min)
+                       tmp.start = min;
+               if (tmp.end > max)
+                       tmp.end = max;
+               tmp.start = ALIGN(tmp.start, align);
                if (alignf)
-                       alignf(alignf_data, new, size, align);
-               if (start < end && end - start >= size - 1) {
-                       new->start = start;
-                       new->end = start + size - 1;
+                       alignf(alignf_data, &tmp, size, align);
+               if (tmp.start < tmp.end && tmp.end - tmp.start >= size - 1) {
+                       new->start = tmp.start;
+                       new->end = tmp.start + size - 1;
                        return 0;
                }
                if (!this)
                        break;
-               start = this->end + 1;
+               tmp.start = this->end + 1;
                this = this->sibling;
        }
        return -EBUSY;
index c6324d9..8047980 100644 (file)
@@ -136,6 +136,7 @@ static inline void warp_clock(void)
        write_seqlock_irq(&xtime_lock);
        wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
        xtime.tv_sec += sys_tz.tz_minuteswest * 60;
+       update_xtime_cache(0);
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
 }
index af4135f..7faaa32 100644 (file)
@@ -165,6 +165,13 @@ struct timespec raw_time;
 /* flag for if timekeeping is suspended */
 int __read_mostly timekeeping_suspended;
 
+static struct timespec xtime_cache __attribute__ ((aligned (16)));
+void update_xtime_cache(u64 nsec)
+{
+       xtime_cache = xtime;
+       timespec_add_ns(&xtime_cache, nsec);
+}
+
 /* must hold xtime_lock */
 void timekeeping_leap_insert(int leapsecond)
 {
@@ -325,6 +332,8 @@ int do_settimeofday(struct timespec *tv)
 
        xtime = *tv;
 
+       update_xtime_cache(0);
+
        timekeeper.ntp_error = 0;
        ntp_clear();
 
@@ -550,6 +559,7 @@ void __init timekeeping_init(void)
        }
        set_normalized_timespec(&wall_to_monotonic,
                                -boot.tv_sec, -boot.tv_nsec);
+       update_xtime_cache(0);
        total_sleep_time.tv_sec = 0;
        total_sleep_time.tv_nsec = 0;
        write_sequnlock_irqrestore(&xtime_lock, flags);
@@ -583,6 +593,7 @@ static int timekeeping_resume(struct sys_device *dev)
                wall_to_monotonic = timespec_sub(wall_to_monotonic, ts);
                total_sleep_time = timespec_add_safe(total_sleep_time, ts);
        }
+       update_xtime_cache(0);
        /* re-base the last cycle value */
        timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock);
        timekeeper.ntp_error = 0;
@@ -722,6 +733,7 @@ static void timekeeping_adjust(s64 offset)
                                timekeeper.ntp_error_shift;
 }
 
+
 /**
  * logarithmic_accumulation - shifted accumulation of cycles
  *
@@ -765,6 +777,7 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
        return offset;
 }
 
+
 /**
  * update_wall_time - Uses the current clocksource to increment the wall time
  *
@@ -774,6 +787,7 @@ void update_wall_time(void)
 {
        struct clocksource *clock;
        cycle_t offset;
+       u64 nsecs;
        int shift = 0, maxshift;
 
        /* Make sure we're fully resumed: */
@@ -839,6 +853,9 @@ void update_wall_time(void)
        timekeeper.ntp_error += timekeeper.xtime_nsec <<
                                timekeeper.ntp_error_shift;
 
+       nsecs = clocksource_cyc2ns(offset, timekeeper.mult, timekeeper.shift);
+       update_xtime_cache(nsecs);
+
        /* check to see if there is a new clocksource to use */
        update_vsyscall(&xtime, timekeeper.clock, timekeeper.mult);
 }
@@ -875,13 +892,13 @@ void monotonic_to_bootbased(struct timespec *ts)
 
 unsigned long get_seconds(void)
 {
-       return xtime.tv_sec;
+       return xtime_cache.tv_sec;
 }
 EXPORT_SYMBOL(get_seconds);
 
 struct timespec __current_kernel_time(void)
 {
-       return xtime;
+       return xtime_cache;
 }
 
 struct timespec current_kernel_time(void)
@@ -891,7 +908,8 @@ struct timespec current_kernel_time(void)
 
        do {
                seq = read_seqbegin(&xtime_lock);
-               now = xtime;
+
+               now = xtime_cache;
        } while (read_seqretry(&xtime_lock, seq));
 
        return now;
@@ -905,7 +923,8 @@ struct timespec get_monotonic_coarse(void)
 
        do {
                seq = read_seqbegin(&xtime_lock);
-               now = xtime;
+
+               now = xtime_cache;
                mono = wall_to_monotonic;
        } while (read_seqretry(&xtime_lock, seq));
 
index afce96a..9f75b4e 100644 (file)
@@ -338,10 +338,10 @@ EXPORT_SYMBOL(strnchr);
 #endif
 
 /**
- * skip_spaces - Removes leading whitespace from @s.
- * @s: The string to be stripped.
+ * skip_spaces - Removes leading whitespace from @str.
+ * @str: The string to be stripped.
  *
- * Returns a pointer to the first non-whitespace character in @s.
+ * Returns a pointer to the first non-whitespace character in @str.
  */
 char *skip_spaces(const char *str)
 {
index 4e86965..d79b925 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/page_cgroup.h>
 #include <linux/debugobjects.h>
 #include <linux/kmemleak.h>
+#include <linux/memory.h>
 #include <trace/events/kmem.h>
 
 #include <asm/tlbflush.h>
@@ -5008,23 +5009,65 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
 int set_migratetype_isolate(struct page *page)
 {
        struct zone *zone;
-       unsigned long flags;
+       struct page *curr_page;
+       unsigned long flags, pfn, iter;
+       unsigned long immobile = 0;
+       struct memory_isolate_notify arg;
+       int notifier_ret;
        int ret = -EBUSY;
        int zone_idx;
 
        zone = page_zone(page);
        zone_idx = zone_idx(zone);
+
        spin_lock_irqsave(&zone->lock, flags);
+       if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE ||
+           zone_idx == ZONE_MOVABLE) {
+               ret = 0;
+               goto out;
+       }
+
+       pfn = page_to_pfn(page);
+       arg.start_pfn = pfn;
+       arg.nr_pages = pageblock_nr_pages;
+       arg.pages_found = 0;
+
        /*
-        * In future, more migrate types will be able to be isolation target.
+        * It may be possible to isolate a pageblock even if the
+        * migratetype is not MIGRATE_MOVABLE. The memory isolation
+        * notifier chain is used by balloon drivers to return the
+        * number of pages in a range that are held by the balloon
+        * driver to shrink memory. If all the pages are accounted for
+        * by balloons, are free, or on the LRU, isolation can continue.
+        * Later, for example, when memory hotplug notifier runs, these
+        * pages reported as "can be isolated" should be isolated(freed)
+        * by the balloon driver through the memory notifier chain.
         */
-       if (get_pageblock_migratetype(page) != MIGRATE_MOVABLE &&
-           zone_idx != ZONE_MOVABLE)
+       notifier_ret = memory_isolate_notify(MEM_ISOLATE_COUNT, &arg);
+       notifier_ret = notifier_to_errno(notifier_ret);
+       if (notifier_ret || !arg.pages_found)
                goto out;
-       set_pageblock_migratetype(page, MIGRATE_ISOLATE);
-       move_freepages_block(zone, page, MIGRATE_ISOLATE);
-       ret = 0;
+
+       for (iter = pfn; iter < (pfn + pageblock_nr_pages); iter++) {
+               if (!pfn_valid_within(pfn))
+                       continue;
+
+               curr_page = pfn_to_page(iter);
+               if (!page_count(curr_page) || PageLRU(curr_page))
+                       continue;
+
+               immobile++;
+       }
+
+       if (arg.pages_found == immobile)
+               ret = 0;
+
 out:
+       if (!ret) {
+               set_pageblock_migratetype(page, MIGRATE_ISOLATE);
+               move_freepages_block(zone, page, MIGRATE_ISOLATE);
+       }
+
        spin_unlock_irqrestore(&zone->lock, flags);
        if (!ret)
                drain_all_pages();
index dc32842..a1362dc 100644 (file)
@@ -43,7 +43,7 @@ static int bufsize = 64 * 1024;
 static const char procname[] = "dccpprobe";
 
 static struct {
-       struct kfifo      *fifo;
+       struct kfifo      fifo;
        spinlock_t        lock;
        wait_queue_head_t wait;
        struct timespec   tstart;
@@ -67,7 +67,7 @@ static void printl(const char *fmt, ...)
        len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args);
        va_end(args);
 
-       kfifo_put(dccpw.fifo, tbuf, len);
+       kfifo_in_locked(&dccpw.fifo, tbuf, len, &dccpw.lock);
        wake_up(&dccpw.wait);
 }
 
@@ -109,7 +109,7 @@ static struct jprobe dccp_send_probe = {
 
 static int dccpprobe_open(struct inode *inode, struct file *file)
 {
-       kfifo_reset(dccpw.fifo);
+       kfifo_reset(&dccpw.fifo);
        getnstimeofday(&dccpw.tstart);
        return 0;
 }
@@ -131,11 +131,11 @@ static ssize_t dccpprobe_read(struct file *file, char __user *buf,
                return -ENOMEM;
 
        error = wait_event_interruptible(dccpw.wait,
-                                        __kfifo_len(dccpw.fifo) != 0);
+                                        kfifo_len(&dccpw.fifo) != 0);
        if (error)
                goto out_free;
 
-       cnt = kfifo_get(dccpw.fifo, tbuf, len);
+       cnt = kfifo_out_locked(&dccpw.fifo, tbuf, len, &dccpw.lock);
        error = copy_to_user(buf, tbuf, cnt) ? -EFAULT : 0;
 
 out_free:
@@ -156,10 +156,8 @@ static __init int dccpprobe_init(void)
 
        init_waitqueue_head(&dccpw.wait);
        spin_lock_init(&dccpw.lock);
-       dccpw.fifo = kfifo_alloc(bufsize, GFP_KERNEL, &dccpw.lock);
-       if (IS_ERR(dccpw.fifo))
-               return PTR_ERR(dccpw.fifo);
-
+       if (kfifo_alloc(&dccpw.fifo, bufsize, GFP_KERNEL))
+               return ret;
        if (!proc_net_fops_create(&init_net, procname, S_IRUSR, &dccpprobe_fops))
                goto err0;
 
@@ -172,14 +170,14 @@ static __init int dccpprobe_init(void)
 err1:
        proc_net_remove(&init_net, procname);
 err0:
-       kfifo_free(dccpw.fifo);
+       kfifo_free(&dccpw.fifo);
        return ret;
 }
 module_init(dccpprobe_init);
 
 static __exit void dccpprobe_exit(void)
 {
-       kfifo_free(dccpw.fifo);
+       kfifo_free(&dccpw.fifo);
        proc_net_remove(&init_net, procname);
        unregister_jprobe(&dccp_send_probe);
 
index 8346938..9a6c588 100644 (file)
@@ -12,7 +12,6 @@
 #include "common.h"
 #include "tomoyo.h"
 #include "realpath.h"
-#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
 /*
  * tomoyo_globally_readable_file_entry is a structure which is used for holding
index e1f2bf8..b5af881 100644 (file)
@@ -1177,7 +1177,7 @@ static struct file_operations kvm_vcpu_fops = {
  */
 static int create_vcpu_fd(struct kvm_vcpu *vcpu)
 {
-       return anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, 0);
+       return anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, O_RDWR);
 }
 
 /*
@@ -1638,7 +1638,7 @@ static int kvm_dev_ioctl_create_vm(void)
        kvm = kvm_create_vm();
        if (IS_ERR(kvm))
                return PTR_ERR(kvm);
-       fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, 0);
+       fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, O_RDWR);
        if (fd < 0)
                kvm_put_kvm(kvm);