Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 16 Jun 2009 20:06:10 +0000 (13:06 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 16 Jun 2009 20:06:10 +0000 (13:06 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (143 commits)
  USB: xhci depends on PCI.
  USB: xhci: Add Makefile, MAINTAINERS, and Kconfig entries.
  USB: xhci: Respect critical sections.
  USB: xHCI: Fix interrupt moderation.
  USB: xhci: Remove packed attribute from structures.
  usb; xhci: Fix TRB offset calculations.
  USB: xhci: replace if-elseif-else with switch-case
  USB: xhci: Make xhci-mem.c include linux/dmapool.h
  USB: xhci: drop spinlock in xhci_urb_enqueue() error path.
  USB: Change names of SuperSpeed ep companion descriptor structs.
  USB: xhci: Avoid compiler reordering in Link TRB giveback.
  USB: xhci: Clean up xhci_irq() function.
  USB: xhci: Avoid global namespace pollution.
  USB: xhci: Fix Link TRB handoff bit twiddling.
  USB: xhci: Fix register write order.
  USB: xhci: fix some compiler warnings in xhci.h
  USB: xhci: fix lots of compiler warnings.
  USB: xhci: use xhci_handle_event instead of handle_event
  USB: xhci: URB cancellation support.
  USB: xhci: Scatter gather list support for bulk transfers.
  ...

452 files changed:
Documentation/DocBook/debugobjects.tmpl
Documentation/cdrom/packet-writing.txt
Documentation/driver-model/device.txt
Documentation/fault-injection/fault-injection.txt
Documentation/filesystems/vfat.txt
Documentation/firmware_class/README
Documentation/hwmon/f71882fg
Documentation/hwmon/ibmaem
Documentation/hwmon/sysfs-interface
Documentation/hwmon/tmp401 [new file with mode: 0644]
Documentation/hwmon/w83627ehf
Documentation/i2c/busses/i2c-viapro
Documentation/kprobes.txt
Documentation/trace/ftrace.txt
Documentation/trace/mmiotrace.txt
MAINTAINERS
arch/blackfin/Kconfig
arch/blackfin/Makefile
arch/blackfin/boot/.gitignore
arch/blackfin/boot/Makefile
arch/blackfin/include/asm/atomic.h
arch/blackfin/include/asm/bfin-global.h
arch/blackfin/include/asm/bitops.h
arch/blackfin/include/asm/bug.h
arch/blackfin/include/asm/cache.h
arch/blackfin/include/asm/cacheflush.h
arch/blackfin/include/asm/cpu.h
arch/blackfin/include/asm/ftrace.h
arch/blackfin/include/asm/ipipe.h
arch/blackfin/include/asm/irq.h
arch/blackfin/include/asm/irqflags.h [new file with mode: 0644]
arch/blackfin/include/asm/mutex-dec.h [deleted file]
arch/blackfin/include/asm/sections.h
arch/blackfin/include/asm/system.h
arch/blackfin/include/asm/unistd.h
arch/blackfin/kernel/Makefile
arch/blackfin/kernel/bfin_dma_5xx.c
arch/blackfin/kernel/bfin_ksyms.c
arch/blackfin/kernel/cplb-mpu/cplbmgr.c
arch/blackfin/kernel/cplb-nompu/cplbmgr.c
arch/blackfin/kernel/early_printk.c
arch/blackfin/kernel/ftrace-entry.S [new file with mode: 0644]
arch/blackfin/kernel/ftrace.c [new file with mode: 0644]
arch/blackfin/kernel/ipipe.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/stacktrace.c [new file with mode: 0644]
arch/blackfin/kernel/traps.c
arch/blackfin/kernel/vmlinux.lds.S
arch/blackfin/lib/checksum.c
arch/blackfin/mach-bf518/boards/ezbrd.c
arch/blackfin/mach-bf527/boards/cm_bf527.c
arch/blackfin/mach-bf527/boards/ezbrd.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf533/boards/H8606.c
arch/blackfin/mach-bf533/boards/blackstamp.c
arch/blackfin/mach-bf533/boards/cm_bf533.c
arch/blackfin/mach-bf533/boards/ezkit.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf537/boards/cm_bf537.c
arch/blackfin/mach-bf537/boards/minotaur.c
arch/blackfin/mach-bf537/boards/pnav10.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf537/boards/tcm_bf537.c
arch/blackfin/mach-bf538/boards/ezkit.c
arch/blackfin/mach-bf548/boards/cm_bf548.c
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf561/boards/cm_bf561.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-common/cache-c.c
arch/blackfin/mach-common/entry.S
arch/blackfin/mach-common/smp.c
arch/mips/configs/bigsur_defconfig
arch/mips/configs/mtx1_defconfig
arch/mips/sni/eisa.c
arch/powerpc/Kconfig
arch/powerpc/boot/install.sh
arch/powerpc/configs/ppc6xx_defconfig
arch/powerpc/include/asm/atomic.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/iommu.h
arch/powerpc/include/asm/ps3.h
arch/powerpc/include/asm/ps3gpu.h [new file with mode: 0644]
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/time.c
arch/powerpc/platforms/cell/axon_msi.c
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/iseries/dt.c
arch/powerpc/platforms/iseries/mf.c
arch/powerpc/platforms/ps3/mm.c
arch/powerpc/platforms/ps3/os-area.c
arch/powerpc/platforms/ps3/platform.h
arch/powerpc/platforms/ps3/setup.c
arch/powerpc/platforms/ps3/system-bus.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/appldata/appldata_base.c
arch/s390/include/asm/ccwdev.h
arch/s390/include/asm/ccwgroup.h
arch/s390/include/asm/suspend.h [new file with mode: 0644]
arch/s390/include/asm/system.h
arch/s390/kernel/early.c
arch/s390/kernel/mem_detect.c
arch/s390/kernel/smp.c
arch/s390/mm/pgtable.c
arch/s390/power/Makefile [new file with mode: 0644]
arch/s390/power/suspend.c [new file with mode: 0644]
arch/s390/power/swsusp.c [new file with mode: 0644]
arch/s390/power/swsusp_64.c [new file with mode: 0644]
arch/s390/power/swsusp_asm64.S [new file with mode: 0644]
arch/sparc/Kconfig
arch/sparc/configs/sparc64_defconfig
arch/sparc/include/asm/cpudata_64.h
arch/sparc/include/asm/dma-mapping.h
arch/sparc/include/asm/dma-mapping_32.h [deleted file]
arch/sparc/include/asm/dma-mapping_64.h [deleted file]
arch/sparc/include/asm/ftrace.h
arch/sparc/include/asm/mdesc.h
arch/sparc/include/asm/percpu_64.h
arch/sparc/include/asm/prom.h
arch/sparc/include/asm/trap_block.h [new file with mode: 0644]
arch/sparc/include/asm/unistd.h
arch/sparc/kernel/Makefile
arch/sparc/kernel/cpumap.c [new file with mode: 0644]
arch/sparc/kernel/cpumap.h [new file with mode: 0644]
arch/sparc/kernel/dma.c
arch/sparc/kernel/ds.c
arch/sparc/kernel/ftrace.c
arch/sparc/kernel/head_64.S
arch/sparc/kernel/iommu.c
arch/sparc/kernel/irq_64.c
arch/sparc/kernel/mdesc.c
arch/sparc/kernel/of_device_32.c
arch/sparc/kernel/of_device_64.c
arch/sparc/kernel/of_device_common.c [new file with mode: 0644]
arch/sparc/kernel/of_device_common.h [new file with mode: 0644]
arch/sparc/kernel/pci_sun4v.c
arch/sparc/kernel/prom.h
arch/sparc/kernel/prom_64.c
arch/sparc/kernel/prom_common.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/sparc/kernel/traps_64.c
arch/sparc/mm/init_32.c
arch/sparc/mm/init_64.c
arch/sparc/mm/srmmu.c
arch/um/drivers/net_kern.c
arch/um/drivers/ubd_kern.c
arch/x86/kernel/cpuid.c
arch/x86/kernel/microcode_core.c
arch/x86/kernel/msr.c
block/blk-core.c
block/blk-settings.c
block/bsg.c
block/cfq-iosched.c
block/genhd.c
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/amlcode.h
drivers/acpi/acpica/dsobject.c
drivers/acpi/acpica/dsopcode.c
drivers/acpi/acpica/dswstate.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/acpica/exconfig.c
drivers/acpi/acpica/excreate.c
drivers/acpi/acpica/exdump.c
drivers/acpi/acpica/exfldio.c
drivers/acpi/acpica/exmutex.c
drivers/acpi/acpica/exstore.c
drivers/acpi/acpica/hwregs.c
drivers/acpi/acpica/nsalloc.c
drivers/acpi/acpica/nsnames.c
drivers/acpi/acpica/nsobject.c
drivers/acpi/acpica/nspredef.c
drivers/acpi/acpica/nssearch.c
drivers/acpi/acpica/nswalk.c
drivers/acpi/acpica/nsxfname.c
drivers/acpi/acpica/nsxfobj.c
drivers/acpi/acpica/rscalc.c
drivers/acpi/acpica/rsxface.c
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/tbinstal.c
drivers/acpi/acpica/utcopy.c
drivers/acpi/acpica/utdebug.c
drivers/acpi/acpica/utdelete.c
drivers/acpi/acpica/utmisc.c
drivers/acpi/acpica/utmutex.c
drivers/base/core.c
drivers/base/dd.c
drivers/base/firmware_class.c
drivers/base/platform.c
drivers/base/sys.c
drivers/block/aoe/aoechr.c
drivers/block/cciss.c
drivers/block/mg_disk.c
drivers/block/pktcdvd.c
drivers/block/ps3disk.c
drivers/block/ps3vram.c
drivers/block/xen-blkfront.c
drivers/char/hvc_iucv.c
drivers/char/hvcs.c
drivers/char/hw_random/core.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/misc.c
drivers/char/ps3flash.c
drivers/char/pty.c
drivers/char/raw.c
drivers/char/tty_io.c
drivers/char/tty_ioctl.c
drivers/char/tty_ldisc.c
drivers/eisa/pci_eisa.c
drivers/eisa/virtual_root.c
drivers/firewire/fw-sbp2.c
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/drm_sysfs.c
drivers/hid/usbhid/hiddev.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/f71882fg.c
drivers/hwmon/hwmon.c
drivers/hwmon/ibmaem.c
drivers/hwmon/max6650.c
drivers/hwmon/sht15.c
drivers/hwmon/tmp401.c [new file with mode: 0644]
drivers/hwmon/w83627ehf.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-viapro.c
drivers/i2c/busses/i2c-voodoo3.c
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Makefile
drivers/i2c/chips/max6875.c [deleted file]
drivers/i2c/i2c-core.c
drivers/ide/ide-pm.c
drivers/ide/ide-probe.c
drivers/ide/ide_platform.c
drivers/ieee1394/eth1394.c
drivers/ieee1394/sbp2.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/hw/ehca/ehca_main.c
drivers/input/input.c
drivers/input/touchscreen/wm97xx-core.c
drivers/input/xen-kbdfront.c
drivers/macintosh/therm_adt746x.c
drivers/macintosh/therm_pm72.c
drivers/macintosh/therm_windtunnel.c
drivers/macintosh/windfarm_lm75_sensor.c
drivers/macintosh/windfarm_max6690_sensor.c
drivers/macintosh/windfarm_smu_sat.c
drivers/md/dm-ioctl.c
drivers/md/dm.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/firewire/firedtv-1394.c
drivers/media/dvb/firewire/firedtv-dvb.c
drivers/media/video/dabusb.c
drivers/media/video/pvrusb2/pvrusb2-sysfs.c
drivers/mfd/htc-pasic3.c
drivers/mfd/pcf50633-core.c
drivers/mfd/wm8400-core.c
drivers/misc/eeprom/Kconfig
drivers/misc/eeprom/Makefile
drivers/misc/eeprom/max6875.c [new file with mode: 0644]
drivers/net/Kconfig
drivers/net/ps3_gelic_net.c
drivers/net/tun.c
drivers/net/wimax/i2400m/i2400m.h
drivers/net/wireless/ath/ath5k/Kconfig
drivers/net/wireless/libertas/README
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/libertas/if_spi.h
drivers/net/wireless/libertas/if_usb.c
drivers/net/xen-netfront.c
drivers/parisc/eisa.c
drivers/parisc/sba_iommu.c
drivers/parport/parport_gsc.c
drivers/pci/pcie/portdrv_core.c
drivers/pcmcia/ds.c
drivers/ps3/ps3-sys-manager.c
drivers/ps3/ps3av.c
drivers/ps3/ps3av_cmd.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dcssblk.c
drivers/s390/block/xpram.c
drivers/s390/char/con3215.c
drivers/s390/char/con3270.c
drivers/s390/char/fs3270.c
drivers/s390/char/monreader.c
drivers/s390/char/monwriter.c
drivers/s390/char/raw3270.c
drivers/s390/char/raw3270.h
drivers/s390/char/sclp.c
drivers/s390/char/sclp.h
drivers/s390/char/sclp_cmd.c
drivers/s390/char/sclp_con.c
drivers/s390/char/sclp_rw.c
drivers/s390/char/sclp_rw.h
drivers/s390/char/sclp_vt220.c
drivers/s390/char/tape.h
drivers/s390/char/tape_34xx.c
drivers/s390/char/tape_3590.c
drivers/s390/char/tape_core.c
drivers/s390/char/vmlogrdr.c
drivers/s390/char/vmur.c
drivers/s390/char/vmwatchdog.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/cmf.c
drivers/s390/cio/css.c
drivers/s390/cio/css.h
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/io_sch.h
drivers/s390/net/claw.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/lcs.c
drivers/s390/net/lcs.h
drivers/s390/net/netiucv.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/s390/net/smsgiucv.c
drivers/s390/scsi/zfcp_ccw.c
drivers/sbus/char/openprom.c
drivers/scsi/aha1740.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvstgt.c
drivers/scsi/libsrp.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/serial/atmel_serial.c
drivers/serial/imx.c
drivers/serial/of_serial.c
drivers/spi/spi_bfin5xx.c
drivers/thermal/thermal_sys.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/class/usblp.c
drivers/usb/core/file.c
drivers/usb/core/usb.c
drivers/usb/gadget/at91_udc.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ohci-ps3.c
drivers/usb/misc/iowarrior.c
drivers/usb/misc/legousbtower.c
drivers/video/bw2.c
drivers/video/cg14.c
drivers/video/cg3.c
drivers/video/cg6.c
drivers/video/leo.c
drivers/video/p9100.c
drivers/video/ps3fb.c
drivers/video/tdfxfb.c
drivers/video/xen-fbfront.c
fs/bio.c
fs/btrfs/disk-io.c
fs/btrfs/transaction.c
fs/debugfs/file.c
fs/debugfs/inode.c
fs/fat/cache.c
fs/fat/dir.c
fs/fat/fat.h
fs/fat/fatent.c
fs/fat/file.c
fs/fat/inode.c
fs/fat/misc.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/jfs/jfs_extent.c
fs/ocfs2/alloc.c
fs/ocfs2/blockcheck.c
fs/ocfs2/blockcheck.h
fs/ocfs2/cluster/masklog.h
fs/ocfs2/cluster/tcp.c
fs/ocfs2/dir.c
fs/ocfs2/dlmglue.c
fs/ocfs2/dlmglue.h
fs/ocfs2/file.c
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_lockid.h
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c
fs/ocfs2/super.c
fs/ocfs2/xattr.c
fs/sysfs/symlink.c
fs/ubifs/super.c
include/acpi/acpixf.h
include/acpi/actypes.h
include/acpi/platform/acgcc.h
include/acpi/platform/aclinux.h
include/asm-generic/atomic64.h [new file with mode: 0644]
include/linux/bio.h
include/linux/blkdev.h
include/linux/device.h
include/linux/eisa.h
include/linux/firmware.h
include/linux/genhd.h
include/linux/kernel.h
include/linux/mg_disk.h [new file with mode: 0644]
include/linux/miscdevice.h
include/linux/platform_device.h
include/linux/sched.h
include/linux/tracepoint.h
include/linux/usb.h
init/Kconfig
kernel/module.c
kernel/printk.c
kernel/trace/Kconfig
kernel/trace/trace.c
kernel/user.c
lib/Kconfig
lib/Makefile
lib/atomic64.c [new file with mode: 0644]
lib/kobject.c
mm/Kconfig
mm/bounce.c
mm/highmem.c
net/iucv/af_iucv.c
net/iucv/iucv.c
samples/Kconfig
samples/firmware_class/firmware_sample_driver.c [deleted file]
samples/firmware_class/firmware_sample_firmware_class.c [deleted file]
scripts/recordmcount.pl
scripts/tracing/draw_functrace.py
sound/pci/ctxfi/ctatc.c
sound/pci/ctxfi/ctatc.h
sound/pci/ctxfi/cttimer.c
sound/pci/hda/patch_realtek.c
sound/pci/intel8x0.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/wm8903.c
sound/soc/pxa/magician.c
sound/soc/soc-core.c
sound/sound_core.c
sound/usb/usbquirks.h

index 7f5f218015feb8beed681fa7742caced8ac4c76f..08ff908aa7a239732fce68cc1b06e507626f216a 100644 (file)
       number of errors are printk'ed including a full stack trace.
     </para>
     <para>
-      The statistics are available via debugfs/debug_objects/stats.
+      The statistics are available via /sys/kernel/debug/debug_objects/stats.
       They provide information about the number of warnings and the
       number of successful fixups along with information about the
       usage of the internal tracking objects and the state of the
index cf1f8126991c00fe5f904631d0471821bf958515..1c407778c8b26213a69984e03a94d34a4fe16d82 100644 (file)
@@ -117,7 +117,7 @@ Using the pktcdvd debugfs interface
 
 To read pktcdvd device infos in human readable form, do:
 
-       # cat /debug/pktcdvd/pktcdvd[0-7]/info
+       # cat /sys/kernel/debug/pktcdvd/pktcdvd[0-7]/info
 
 For a description of the debugfs interface look into the file:
 
index a7cbfff40d077047f76463377381b269b5d41fc4..a124f3126b0d1f4f495c982a03df6e12f743b87b 100644 (file)
@@ -162,3 +162,35 @@ device_remove_file(dev,&dev_attr_power);
 
 The file name will be 'power' with a mode of 0644 (-rw-r--r--).
 
+Word of warning:  While the kernel allows device_create_file() and
+device_remove_file() to be called on a device at any time, userspace has
+strict expectations on when attributes get created.  When a new device is
+registered in the kernel, a uevent is generated to notify userspace (like
+udev) that a new device is available.  If attributes are added after the
+device is registered, then userspace won't get notified and userspace will
+not know about the new attributes.
+
+This is important for device driver that need to publish additional
+attributes for a device at driver probe time.  If the device driver simply
+calls device_create_file() on the device structure passed to it, then
+userspace will never be notified of the new attributes.  Instead, it should
+probably use class_create() and class->dev_attrs to set up a list of
+desired attributes in the modules_init function, and then in the .probe()
+hook, and then use device_create() to create a new device as a child
+of the probed device.  The new device will generate a new uevent and
+properly advertise the new attributes to userspace.
+
+For example, if a driver wanted to add the following attributes:
+struct device_attribute mydriver_attribs[] = {
+       __ATTR(port_count, 0444, port_count_show),
+       __ATTR(serial_number, 0444, serial_number_show),
+       NULL
+};
+
+Then in the module init function is would do:
+       mydriver_class = class_create(THIS_MODULE, "my_attrs");
+       mydriver_class.dev_attr = mydriver_attribs;
+
+And assuming 'dev' is the struct device passed into the probe hook, the driver
+probe function would do something like:
+       create_device(&mydriver_class, dev, chrdev, &private_data, "my_name");
index 4bc374a14345da10f666d67745aa151231c10c92..079305640790ee0436ab7ae46e49624498c333ce 100644 (file)
@@ -29,16 +29,16 @@ o debugfs entries
 fault-inject-debugfs kernel module provides some debugfs entries for runtime
 configuration of fault-injection capabilities.
 
-- /debug/fail*/probability:
+- /sys/kernel/debug/fail*/probability:
 
        likelihood of failure injection, in percent.
        Format: <percent>
 
        Note that one-failure-per-hundred is a very high error rate
        for some testcases.  Consider setting probability=100 and configure
-       /debug/fail*/interval for such testcases.
+       /sys/kernel/debug/fail*/interval for such testcases.
 
-- /debug/fail*/interval:
+- /sys/kernel/debug/fail*/interval:
 
        specifies the interval between failures, for calls to
        should_fail() that pass all the other tests.
@@ -46,18 +46,18 @@ configuration of fault-injection capabilities.
        Note that if you enable this, by setting interval>1, you will
        probably want to set probability=100.
 
-- /debug/fail*/times:
+- /sys/kernel/debug/fail*/times:
 
        specifies how many times failures may happen at most.
        A value of -1 means "no limit".
 
-- /debug/fail*/space:
+- /sys/kernel/debug/fail*/space:
 
        specifies an initial resource "budget", decremented by "size"
        on each call to should_fail(,size).  Failure injection is
        suppressed until "space" reaches zero.
 
-- /debug/fail*/verbose
+- /sys/kernel/debug/fail*/verbose
 
        Format: { 0 | 1 | 2 }
        specifies the verbosity of the messages when failure is
@@ -65,17 +65,17 @@ configuration of fault-injection capabilities.
        log line per failure; '2' will print a call trace too -- useful
        to debug the problems revealed by fault injection.
 
-- /debug/fail*/task-filter:
+- /sys/kernel/debug/fail*/task-filter:
 
        Format: { 'Y' | 'N' }
        A value of 'N' disables filtering by process (default).
        Any positive value limits failures to only processes indicated by
        /proc/<pid>/make-it-fail==1.
 
-- /debug/fail*/require-start:
-- /debug/fail*/require-end:
-- /debug/fail*/reject-start:
-- /debug/fail*/reject-end:
+- /sys/kernel/debug/fail*/require-start:
+- /sys/kernel/debug/fail*/require-end:
+- /sys/kernel/debug/fail*/reject-start:
+- /sys/kernel/debug/fail*/reject-end:
 
        specifies the range of virtual addresses tested during
        stacktrace walking.  Failure is injected only if some caller
@@ -84,26 +84,26 @@ configuration of fault-injection capabilities.
        Default required range is [0,ULONG_MAX) (whole of virtual address space).
        Default rejected range is [0,0).
 
-- /debug/fail*/stacktrace-depth:
+- /sys/kernel/debug/fail*/stacktrace-depth:
 
        specifies the maximum stacktrace depth walked during search
        for a caller within [require-start,require-end) OR
        [reject-start,reject-end).
 
-- /debug/fail_page_alloc/ignore-gfp-highmem:
+- /sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem:
 
        Format: { 'Y' | 'N' }
        default is 'N', setting it to 'Y' won't inject failures into
        highmem/user allocations.
 
-- /debug/failslab/ignore-gfp-wait:
-- /debug/fail_page_alloc/ignore-gfp-wait:
+- /sys/kernel/debug/failslab/ignore-gfp-wait:
+- /sys/kernel/debug/fail_page_alloc/ignore-gfp-wait:
 
        Format: { 'Y' | 'N' }
        default is 'N', setting it to 'Y' will inject failures
        only into non-sleep allocations (GFP_ATOMIC allocations).
 
-- /debug/fail_page_alloc/min-order:
+- /sys/kernel/debug/fail_page_alloc/min-order:
 
        specifies the minimum page allocation order to be injected
        failures.
@@ -166,13 +166,13 @@ o Inject slab allocation failures into module init/exit code
 #!/bin/bash
 
 FAILTYPE=failslab
-echo Y > /debug/$FAILTYPE/task-filter
-echo 10 > /debug/$FAILTYPE/probability
-echo 100 > /debug/$FAILTYPE/interval
-echo -1 > /debug/$FAILTYPE/times
-echo 0 > /debug/$FAILTYPE/space
-echo 2 > /debug/$FAILTYPE/verbose
-echo 1 > /debug/$FAILTYPE/ignore-gfp-wait
+echo Y > /sys/kernel/debug/$FAILTYPE/task-filter
+echo 10 > /sys/kernel/debug/$FAILTYPE/probability
+echo 100 > /sys/kernel/debug/$FAILTYPE/interval
+echo -1 > /sys/kernel/debug/$FAILTYPE/times
+echo 0 > /sys/kernel/debug/$FAILTYPE/space
+echo 2 > /sys/kernel/debug/$FAILTYPE/verbose
+echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait
 
 faulty_system()
 {
@@ -217,20 +217,20 @@ then
        exit 1
 fi
 
-cat /sys/module/$module/sections/.text > /debug/$FAILTYPE/require-start
-cat /sys/module/$module/sections/.data > /debug/$FAILTYPE/require-end
+cat /sys/module/$module/sections/.text > /sys/kernel/debug/$FAILTYPE/require-start
+cat /sys/module/$module/sections/.data > /sys/kernel/debug/$FAILTYPE/require-end
 
-echo N > /debug/$FAILTYPE/task-filter
-echo 10 > /debug/$FAILTYPE/probability
-echo 100 > /debug/$FAILTYPE/interval
-echo -1 > /debug/$FAILTYPE/times
-echo 0 > /debug/$FAILTYPE/space
-echo 2 > /debug/$FAILTYPE/verbose
-echo 1 > /debug/$FAILTYPE/ignore-gfp-wait
-echo 1 > /debug/$FAILTYPE/ignore-gfp-highmem
-echo 10 > /debug/$FAILTYPE/stacktrace-depth
+echo N > /sys/kernel/debug/$FAILTYPE/task-filter
+echo 10 > /sys/kernel/debug/$FAILTYPE/probability
+echo 100 > /sys/kernel/debug/$FAILTYPE/interval
+echo -1 > /sys/kernel/debug/$FAILTYPE/times
+echo 0 > /sys/kernel/debug/$FAILTYPE/space
+echo 2 > /sys/kernel/debug/$FAILTYPE/verbose
+echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait
+echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-highmem
+echo 10 > /sys/kernel/debug/$FAILTYPE/stacktrace-depth
 
-trap "echo 0 > /debug/$FAILTYPE/probability" SIGINT SIGTERM EXIT
+trap "echo 0 > /sys/kernel/debug/$FAILTYPE/probability" SIGINT SIGTERM EXIT
 
 echo "Injecting errors into the module $module... (interrupt to stop)"
 sleep 1000000
index 5147be5e13cd6376c9dac99cad8ffc186a201ab1..b58b84b50fa21944ccb98b87f5a2519f34a01705 100644 (file)
@@ -132,6 +132,11 @@ rodir            -- FAT has the ATTR_RO (read-only) attribute. On Windows,
                 If you want to use ATTR_RO as read-only flag even for
                 the directory, set this option.
 
+errors=panic|continue|remount-ro
+             -- specify FAT behavior on critical errors: panic, continue
+                without doing anything or remount the partition in
+                read-only mode (default behavior).
+
 <bool>: 0,1,yes,no,true,false
 
 TODO
index c3480aa66ba8048bf46483544ed6fb3ebb7151eb..7eceaff63f5ffb8f45748d0cb1f46b864652b69a 100644 (file)
@@ -77,7 +77,8 @@
    seconds for the whole load operation.
 
  - request_firmware_nowait() is also provided for convenience in
-   non-user contexts.
+   user contexts to request firmware asynchronously, but can't be called
+   in atomic contexts.
 
 
  about in-kernel persistence:
index a8321267b5b61901757c15f347c2a753ebbd016a..bee4c30bc1e2a82caa2421c9504e031ff1658c73 100644 (file)
@@ -2,14 +2,18 @@ Kernel driver f71882fg
 ======================
 
 Supported chips:
-  * Fintek F71882FG and F71883FG
-    Prefix: 'f71882fg'
+  * Fintek F71858FG
+    Prefix: 'f71858fg'
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: Available from the Fintek website
   * Fintek F71862FG and F71863FG
     Prefix: 'f71862fg'
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: Available from the Fintek website
+  * Fintek F71882FG and F71883FG
+    Prefix: 'f71882fg'
+    Addresses scanned: none, address read from Super I/O config space
+    Datasheet: Available from the Fintek website
   * Fintek F8000
     Prefix: 'f8000'
     Addresses scanned: none, address read from Super I/O config space
@@ -66,13 +70,13 @@ printed when loading the driver.
 
 Three different fan control modes are supported; the mode number is written
 to the pwm#_enable file. Note that not all modes are supported on all
-chips, and some modes may only be available in RPM / PWM mode on the F8000.
+chips, and some modes may only be available in RPM / PWM mode.
 Writing an unsupported mode will result in an invalid parameter error.
 
 * 1: Manual mode
   You ask for a specific PWM duty cycle / DC voltage or a specific % of
   fan#_full_speed by writing to the pwm# file. This mode is only
-  available on the F8000 if the fan channel is in RPM mode.
+  available on the F71858FG / F8000 if the fan channel is in RPM mode.
 
 * 2: Normal auto mode
   You can define a number of temperature/fan speed trip points, which % the
index e98bdfea3467f679411f86d8f82be7ea421da491..1e0d59e000b475cafe418db3fd44fba6f08b3122 100644 (file)
@@ -7,7 +7,7 @@ henceforth as AEM.
 Supported systems:
   * Any recent IBM System X server with AEM support.
     This includes the x3350, x3550, x3650, x3655, x3755, x3850 M2,
-    x3950 M2, and certain HS2x/LS2x/QS2x blades.  The IPMI host interface
+    x3950 M2, and certain HC10/HS2x/LS2x/QS2x blades.  The IPMI host interface
     driver ("ipmi-si") needs to be loaded for this driver to do anything.
     Prefix: 'ibmaem'
     Datasheet: Not available
index 004ee161721e9b3bd1aa213c174a594174b187c8..dcbd502c8792b4e786507bc2023860c716d8fd8b 100644 (file)
@@ -70,6 +70,7 @@ are interpreted as 0! For more on how written strings are interpreted see the
 [0-*]  denotes any positive number starting from 0
 [1-*]  denotes any positive number starting from 1
 RO     read only value
+WO     write only value
 RW     read/write value
 
 Read/write values may be read-only for some chips, depending on the
@@ -295,6 +296,24 @@ temp[1-*]_label    Suggested temperature channel label.
                user-space.
                RO
 
+temp[1-*]_lowest
+               Historical minimum temperature
+               Unit: millidegree Celsius
+               RO
+
+temp[1-*]_highest
+               Historical maximum temperature
+               Unit: millidegree Celsius
+               RO
+
+temp[1-*]_reset_history
+               Reset temp_lowest and temp_highest
+               WO
+
+temp_reset_history
+               Reset temp_lowest and temp_highest for all sensors
+               WO
+
 Some chips measure temperature using external thermistors and an ADC, and
 report the temperature measurement as a voltage. Converting this voltage
 back to a temperature (or the other way around for limits) requires
diff --git a/Documentation/hwmon/tmp401 b/Documentation/hwmon/tmp401
new file mode 100644 (file)
index 0000000..9fc4472
--- /dev/null
@@ -0,0 +1,42 @@
+Kernel driver tmp401
+====================
+
+Supported chips:
+  * Texas Instruments TMP401
+    Prefix: 'tmp401'
+    Addresses scanned: I2C 0x4c
+    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp401.html
+  * Texas Instruments TMP411
+    Prefix: 'tmp411'
+    Addresses scanned: I2C 0x4c
+    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp411.html
+
+Authors:
+         Hans de Goede <hdegoede@redhat.com>
+        Andre Prendel <andre.prendel@gmx.de>
+
+Description
+-----------
+
+This driver implements support for Texas Instruments TMP401 and
+TMP411 chips. These chips implements one remote and one local
+temperature sensor. Temperature is measured in degrees
+Celsius. Resolution of the remote sensor is 0.0625 degree. Local
+sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not
+supported by the driver so far, so using the default resolution of 0.5
+degree).
+
+The driver provides the common sysfs-interface for temperatures (see
+/Documentation/hwmon/sysfs-interface under Temperatures).
+
+The TMP411 chip is compatible with TMP401. It provides some additional
+features.
+
+* Minimum and Maximum temperature measured since power-on, chip-reset
+
+  Exported via sysfs attributes tempX_lowest and tempX_highest.
+
+* Reset of historical minimum/maximum temperature measurements
+
+  Exported via sysfs attribute temp_reset_history. Writing 1 to this
+  file triggers a reset.
index b6eb59384bb39c1b67d0c99a1ade601269a64d05..02b74899edaf42e5c1a266399aeb51c890fc5c5c 100644 (file)
@@ -12,6 +12,10 @@ Supported chips:
     Addresses scanned: ISA address retrieved from Super I/O registers
     Datasheet:
         http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf
+  * Winbond W83627DHG-P
+    Prefix: 'w83627dhg'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: not available
   * Winbond W83667HG
     Prefix: 'w83667hg'
     Addresses scanned: ISA address retrieved from Super I/O registers
@@ -28,8 +32,8 @@ Description
 -----------
 
 This driver implements support for the Winbond W83627EHF, W83627EHG,
-W83627DHG and W83667HG super I/O chips. We will refer to them collectively
-as Winbond chips.
+W83627DHG, W83627DHG-P and W83667HG super I/O chips. We will refer to them
+collectively as Winbond chips.
 
 The chips implement three temperature sensors, five fan rotation
 speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
@@ -135,3 +139,6 @@ done in the driver for all register addresses.
 The DHG also supports PECI, where the DHG queries Intel CPU temperatures, and
 the ICH8 southbridge gets that data via PECI from the DHG, so that the
 southbridge drives the fans. And the DHG supports SST, a one-wire serial bus.
+
+The DHG-P has an additional automatic fan speed control mode named Smart Fan
+(TM) III+. This mode is not yet supported by the driver.
index 22efedf60c872869e5230eb5ccf66c166634e22c..2e758b0e94564042d14d1d763d6a11fc998c181d 100644 (file)
@@ -19,6 +19,9 @@ Supported adapters:
   * VIA Technologies, Inc. VX800/VX820
     Datasheet: available on http://linux.via.com.tw
 
+  * VIA Technologies, Inc. VX855/VX875
+    Datasheet: Availability unknown
+
 Authors:
        Kyösti Mälkki <kmalkki@cc.hut.fi>,
        Mark D. Studebaker <mdsxyz123@yahoo.com>,
@@ -53,6 +56,7 @@ Your lspci -n listing must show one of these :
  device 1106:3287   (VT8251)
  device 1106:8324   (CX700)
  device 1106:8353   (VX800/VX820)
+ device 1106:8409   (VX855/VX875)
 
 If none of these show up, you should look in the BIOS for settings like
 enable ACPI / SMBus or even USB.
index 1e7a769a10f97354a0b3aa15229e5606723a4cd8..053037a1fe6d3b4943219c55d82dafca593c8d03 100644 (file)
@@ -507,9 +507,9 @@ http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115)
 Appendix A: The kprobes debugfs interface
 
 With recent kernels (> 2.6.20) the list of registered kprobes is visible
-under the /debug/kprobes/ directory (assuming debugfs is mounted at /debug).
+under the /sys/kernel/debug/kprobes/ directory (assuming debugfs is mounted at //sys/kernel/debug).
 
-/debug/kprobes/list: Lists all registered probes on the system
+/sys/kernel/debug/kprobes/list: Lists all registered probes on the system
 
 c015d71a  k  vfs_read+0x0
 c011a316  j  do_fork+0x0
@@ -525,7 +525,7 @@ virtual addresses that correspond to modules that've been unloaded),
 such probes are marked with [GONE]. If the probe is temporarily disabled,
 such probes are marked with [DISABLED].
 
-/debug/kprobes/enabled: Turn kprobes ON/OFF forcibly.
+/sys/kernel/debug/kprobes/enabled: Turn kprobes ON/OFF forcibly.
 
 Provides a knob to globally and forcibly turn registered kprobes ON or OFF.
 By default, all kprobes are enabled. By echoing "0" to this file, all
index 7bd27f0e288008c641c31474341a2dd84ef8bf73..a39b3c749de58c12129d80d0ffad738f9a7836f0 100644 (file)
@@ -7,7 +7,6 @@ Copyright 2008 Red Hat Inc.
                (dual licensed under the GPL v2)
 Reviewers:   Elias Oltmanns, Randy Dunlap, Andrew Morton,
             John Kacur, and David Teigland.
-
 Written for: 2.6.28-rc2
 
 Introduction
@@ -33,13 +32,26 @@ The File System
 Ftrace uses the debugfs file system to hold the control files as
 well as the files to display output.
 
-To mount the debugfs system:
+When debugfs is configured into the kernel (which selecting any ftrace
+option will do) the directory /sys/kernel/debug will be created. To mount
+this directory, you can add to your /etc/fstab file:
+
+ debugfs       /sys/kernel/debug          debugfs defaults        0       0
+
+Or you can mount it at run time with:
+
+ mount -t debugfs nodev /sys/kernel/debug
 
-  # mkdir /debug
-  # mount -t debugfs nodev /debug
+For quicker access to that directory you may want to make a soft link to
+it:
 
-( Note: it is more common to mount at /sys/kernel/debug, but for
-  simplicity this document will use /debug)
+ ln -s /sys/kernel/debug /debug
+
+Any selected ftrace option will also create a directory called tracing
+within the debugfs. The rest of the document will assume that you are in
+the ftrace directory (cd /sys/kernel/debug/tracing) and will only concentrate
+on the files within that directory and not distract from the content with
+the extended "/sys/kernel/debug/tracing" path name.
 
 That's it! (assuming that you have ftrace configured into your kernel)
 
@@ -389,18 +401,18 @@ trace_options
 The trace_options file is used to control what gets printed in
 the trace output. To see what is available, simply cat the file:
 
-  cat /debug/tracing/trace_options
+  cat trace_options
   print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \
   noblock nostacktrace nosched-tree nouserstacktrace nosym-userobj
 
 To disable one of the options, echo in the option prepended with
 "no".
 
-  echo noprint-parent > /debug/tracing/trace_options
+  echo noprint-parent > trace_options
 
 To enable an option, leave off the "no".
 
-  echo sym-offset > /debug/tracing/trace_options
+  echo sym-offset > trace_options
 
 Here are the available options:
 
@@ -476,11 +488,11 @@ sched_switch
 This tracer simply records schedule switches. Here is an example
 of how to use it.
 
- # echo sched_switch > /debug/tracing/current_tracer
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo sched_switch > current_tracer
+ # echo 1 > tracing_enabled
  # sleep 1
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/trace
+ # echo 0 > tracing_enabled
+ # cat trace
 
 # tracer: sched_switch
 #
@@ -583,13 +595,13 @@ new trace is saved.
 To reset the maximum, echo 0 into tracing_max_latency. Here is
 an example:
 
- # echo irqsoff > /debug/tracing/current_tracer
- # echo 0 > /debug/tracing/tracing_max_latency
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo irqsoff > current_tracer
+ # echo 0 > tracing_max_latency
+ # echo 1 > tracing_enabled
  # ls -ltr
  [...]
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/latency_trace
+ # echo 0 > tracing_enabled
+ # cat latency_trace
 # tracer: irqsoff
 #
 irqsoff latency trace v1.1.5 on 2.6.26
@@ -690,13 +702,13 @@ Like the irqsoff tracer, it records the maximum latency for
 which preemption was disabled. The control of preemptoff tracer
 is much like the irqsoff tracer.
 
- # echo preemptoff > /debug/tracing/current_tracer
- # echo 0 > /debug/tracing/tracing_max_latency
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo preemptoff > current_tracer
+ # echo 0 > tracing_max_latency
+ # echo 1 > tracing_enabled
  # ls -ltr
  [...]
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/latency_trace
+ # echo 0 > tracing_enabled
+ # cat latency_trace
 # tracer: preemptoff
 #
 preemptoff latency trace v1.1.5 on 2.6.26-rc8
@@ -837,13 +849,13 @@ tracer.
 Again, using this trace is much like the irqsoff and preemptoff
 tracers.
 
- # echo preemptirqsoff > /debug/tracing/current_tracer
- # echo 0 > /debug/tracing/tracing_max_latency
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo preemptirqsoff > current_tracer
+ # echo 0 > tracing_max_latency
+ # echo 1 > tracing_enabled
  # ls -ltr
  [...]
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/latency_trace
+ # echo 0 > tracing_enabled
+ # cat latency_trace
 # tracer: preemptirqsoff
 #
 preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8
@@ -999,12 +1011,12 @@ slightly differently than we did with the previous tracers.
 Instead of performing an 'ls', we will run 'sleep 1' under
 'chrt' which changes the priority of the task.
 
- # echo wakeup > /debug/tracing/current_tracer
- # echo 0 > /debug/tracing/tracing_max_latency
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo wakeup > current_tracer
+ # echo 0 > tracing_max_latency
+ # echo 1 > tracing_enabled
  # chrt -f 5 sleep 1
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/latency_trace
+ # echo 0 > tracing_enabled
+ # cat latency_trace
 # tracer: wakeup
 #
 wakeup latency trace v1.1.5 on 2.6.26-rc8
@@ -1114,11 +1126,11 @@ can be done from the debug file system. Make sure the
 ftrace_enabled is set; otherwise this tracer is a nop.
 
  # sysctl kernel.ftrace_enabled=1
- # echo function > /debug/tracing/current_tracer
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo function > current_tracer
+ # echo 1 > tracing_enabled
  # usleep 1
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/trace
+ # echo 0 > tracing_enabled
+ # cat trace
 # tracer: function
 #
 #           TASK-PID   CPU#    TIMESTAMP  FUNCTION
@@ -1155,7 +1167,7 @@ int trace_fd;
 [...]
 int main(int argc, char *argv[]) {
        [...]
-       trace_fd = open("/debug/tracing/tracing_enabled", O_WRONLY);
+       trace_fd = open(tracing_file("tracing_enabled"), O_WRONLY);
        [...]
        if (condition_hit()) {
                write(trace_fd, "0", 1);
@@ -1163,26 +1175,20 @@ int main(int argc, char *argv[]) {
        [...]
 }
 
-Note: Here we hard coded the path name. The debugfs mount is not
-guaranteed to be at /debug (and is more commonly at
-/sys/kernel/debug). For simple one time traces, the above is
-sufficent. For anything else, a search through /proc/mounts may
-be needed to find where the debugfs file-system is mounted.
-
 
 Single thread tracing
 ---------------------
 
-By writing into /debug/tracing/set_ftrace_pid you can trace a
+By writing into set_ftrace_pid you can trace a
 single thread. For example:
 
-# cat /debug/tracing/set_ftrace_pid
+# cat set_ftrace_pid
 no pid
-# echo 3111 > /debug/tracing/set_ftrace_pid
-# cat /debug/tracing/set_ftrace_pid
+# echo 3111 > set_ftrace_pid
+# cat set_ftrace_pid
 3111
-# echo function > /debug/tracing/current_tracer
-# cat /debug/tracing/trace | head
+# echo function > current_tracer
+# cat trace | head
  # tracer: function
  #
  #           TASK-PID    CPU#    TIMESTAMP  FUNCTION
@@ -1193,8 +1199,8 @@ no pid
      yum-updatesd-3111  [003]  1637.254683: lock_hrtimer_base <-hrtimer_try_to_cancel
      yum-updatesd-3111  [003]  1637.254685: fget_light <-do_sys_poll
      yum-updatesd-3111  [003]  1637.254686: pipe_poll <-do_sys_poll
-# echo -1 > /debug/tracing/set_ftrace_pid
-# cat /debug/tracing/trace |head
+# echo -1 > set_ftrace_pid
+# cat trace |head
  # tracer: function
  #
  #           TASK-PID    CPU#    TIMESTAMP  FUNCTION
@@ -1216,6 +1222,51 @@ something like this simple program:
 #include <fcntl.h>
 #include <unistd.h>
 
+#define _STR(x) #x
+#define STR(x) _STR(x)
+#define MAX_PATH 256
+
+const char *find_debugfs(void)
+{
+       static char debugfs[MAX_PATH+1];
+       static int debugfs_found;
+       char type[100];
+       FILE *fp;
+
+       if (debugfs_found)
+               return debugfs;
+
+       if ((fp = fopen("/proc/mounts","r")) == NULL) {
+               perror("/proc/mounts");
+               return NULL;
+       }
+
+       while (fscanf(fp, "%*s %"
+                     STR(MAX_PATH)
+                     "s %99s %*s %*d %*d\n",
+                     debugfs, type) == 2) {
+               if (strcmp(type, "debugfs") == 0)
+                       break;
+       }
+       fclose(fp);
+
+       if (strcmp(type, "debugfs") != 0) {
+               fprintf(stderr, "debugfs not mounted");
+               return NULL;
+       }
+
+       debugfs_found = 1;
+
+       return debugfs;
+}
+
+const char *tracing_file(const char *file_name)
+{
+       static char trace_file[MAX_PATH+1];
+       snprintf(trace_file, MAX_PATH, "%s/%s", find_debugfs(), file_name);
+       return trace_file;
+}
+
 int main (int argc, char **argv)
 {
         if (argc < 1)
@@ -1226,12 +1277,12 @@ int main (int argc, char **argv)
                 char line[64];
                 int s;
 
-                ffd = open("/debug/tracing/current_tracer", O_WRONLY);
+                ffd = open(tracing_file("current_tracer"), O_WRONLY);
                 if (ffd < 0)
                         exit(-1);
                 write(ffd, "nop", 3);
 
-                fd = open("/debug/tracing/set_ftrace_pid", O_WRONLY);
+                fd = open(tracing_file("set_ftrace_pid"), O_WRONLY);
                 s = sprintf(line, "%d\n", getpid());
                 write(fd, line, s);
 
@@ -1383,22 +1434,22 @@ want, depending on your needs.
   tracing_cpu_mask file) or you might sometimes see unordered
   function calls while cpu tracing switch.
 
-       hide: echo nofuncgraph-cpu > /debug/tracing/trace_options
-       show: echo funcgraph-cpu > /debug/tracing/trace_options
+       hide: echo nofuncgraph-cpu > trace_options
+       show: echo funcgraph-cpu > trace_options
 
 - The duration (function's time of execution) is displayed on
   the closing bracket line of a function or on the same line
   than the current function in case of a leaf one. It is default
   enabled.
 
-       hide: echo nofuncgraph-duration > /debug/tracing/trace_options
-       show: echo funcgraph-duration > /debug/tracing/trace_options
+       hide: echo nofuncgraph-duration > trace_options
+       show: echo funcgraph-duration > trace_options
 
 - The overhead field precedes the duration field in case of
   reached duration thresholds.
 
-       hide: echo nofuncgraph-overhead > /debug/tracing/trace_options
-       show: echo funcgraph-overhead > /debug/tracing/trace_options
+       hide: echo nofuncgraph-overhead > trace_options
+       show: echo funcgraph-overhead > trace_options
        depends on: funcgraph-duration
 
   ie:
@@ -1427,8 +1478,8 @@ want, depending on your needs.
 - The task/pid field displays the thread cmdline and pid which
   executed the function. It is default disabled.
 
-       hide: echo nofuncgraph-proc > /debug/tracing/trace_options
-       show: echo funcgraph-proc > /debug/tracing/trace_options
+       hide: echo nofuncgraph-proc > trace_options
+       show: echo funcgraph-proc > trace_options
 
   ie:
 
@@ -1451,8 +1502,8 @@ want, depending on your needs.
   system clock since it started. A snapshot of this time is
   given on each entry/exit of functions
 
-       hide: echo nofuncgraph-abstime > /debug/tracing/trace_options
-       show: echo funcgraph-abstime > /debug/tracing/trace_options
+       hide: echo nofuncgraph-abstime > trace_options
+       show: echo funcgraph-abstime > trace_options
 
   ie:
 
@@ -1549,7 +1600,7 @@ listed in:
 
    available_filter_functions
 
- # cat /debug/tracing/available_filter_functions
+ # cat available_filter_functions
 put_prev_task_idle
 kmem_cache_create
 pick_next_task_rt
@@ -1561,12 +1612,12 @@ mutex_lock
 If I am only interested in sys_nanosleep and hrtimer_interrupt:
 
  # echo sys_nanosleep hrtimer_interrupt \
-               > /debug/tracing/set_ftrace_filter
- # echo ftrace > /debug/tracing/current_tracer
- # echo 1 > /debug/tracing/tracing_enabled
+               > set_ftrace_filter
+ # echo ftrace > current_tracer
+ # echo 1 > tracing_enabled
  # usleep 1
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/trace
+ # echo 0 > tracing_enabled
+ # cat trace
 # tracer: ftrace
 #
 #           TASK-PID   CPU#    TIMESTAMP  FUNCTION
@@ -1577,7 +1628,7 @@ If I am only interested in sys_nanosleep and hrtimer_interrupt:
 
 To see which functions are being traced, you can cat the file:
 
- # cat /debug/tracing/set_ftrace_filter
+ # cat set_ftrace_filter
 hrtimer_interrupt
 sys_nanosleep
 
@@ -1597,7 +1648,7 @@ Note: It is better to use quotes to enclose the wild cards,
       otherwise the shell may expand the parameters into names
       of files in the local directory.
 
- # echo 'hrtimer_*' > /debug/tracing/set_ftrace_filter
+ # echo 'hrtimer_*' > set_ftrace_filter
 
 Produces:
 
@@ -1618,7 +1669,7 @@ Produces:
 
 Notice that we lost the sys_nanosleep.
 
- # cat /debug/tracing/set_ftrace_filter
+ # cat set_ftrace_filter
 hrtimer_run_queues
 hrtimer_run_pending
 hrtimer_init
@@ -1644,17 +1695,17 @@ To append to the filters, use '>>'
 To clear out a filter so that all functions will be recorded
 again:
 
- # echo > /debug/tracing/set_ftrace_filter
- # cat /debug/tracing/set_ftrace_filter
+ # echo > set_ftrace_filter
+ # cat set_ftrace_filter
  #
 
 Again, now we want to append.
 
- # echo sys_nanosleep > /debug/tracing/set_ftrace_filter
- # cat /debug/tracing/set_ftrace_filter
+ # echo sys_nanosleep > set_ftrace_filter
+ # cat set_ftrace_filter
 sys_nanosleep
- # echo 'hrtimer_*' >> /debug/tracing/set_ftrace_filter
- # cat /debug/tracing/set_ftrace_filter
+ # echo 'hrtimer_*' >> set_ftrace_filter
+ # cat set_ftrace_filter
 hrtimer_run_queues
 hrtimer_run_pending
 hrtimer_init
@@ -1677,7 +1728,7 @@ hrtimer_init_sleeper
 The set_ftrace_notrace prevents those functions from being
 traced.
 
- # echo '*preempt*' '*lock*' > /debug/tracing/set_ftrace_notrace
+ # echo '*preempt*' '*lock*' > set_ftrace_notrace
 
 Produces:
 
@@ -1767,13 +1818,13 @@ the effect on the tracing is different. Every read from
 trace_pipe is consumed. This means that subsequent reads will be
 different. The trace is live.
 
- # echo function > /debug/tracing/current_tracer
- # cat /debug/tracing/trace_pipe > /tmp/trace.out &
+ # echo function > current_tracer
+ # cat trace_pipe > /tmp/trace.out &
 [1] 4153
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo 1 > tracing_enabled
  # usleep 1
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/trace
+ # echo 0 > tracing_enabled
+ # cat trace
 # tracer: function
 #
 #           TASK-PID   CPU#    TIMESTAMP  FUNCTION
@@ -1809,7 +1860,7 @@ number listed is the number of entries that can be recorded per
 CPU. To know the full size, multiply the number of possible CPUS
 with the number of entries.
 
- # cat /debug/tracing/buffer_size_kb
+ # cat buffer_size_kb
 1408 (units kilobytes)
 
 Note, to modify this, you must have tracing completely disabled.
@@ -1817,18 +1868,18 @@ To do that, echo "nop" into the current_tracer. If the
 current_tracer is not set to "nop", an EINVAL error will be
 returned.
 
- # echo nop > /debug/tracing/current_tracer
- # echo 10000 > /debug/tracing/buffer_size_kb
- # cat /debug/tracing/buffer_size_kb
+ # echo nop > current_tracer
+ # echo 10000 > buffer_size_kb
+ # cat buffer_size_kb
 10000 (units kilobytes)
 
 The number of pages which will be allocated is limited to a
 percentage of available memory. Allocating too much will produce
 an error.
 
- # echo 1000000000000 > /debug/tracing/buffer_size_kb
+ # echo 1000000000000 > buffer_size_kb
 -bash: echo: write error: Cannot allocate memory
- # cat /debug/tracing/buffer_size_kb
+ # cat buffer_size_kb
 85
 
 -----------
index 5731c67abc558f4ac91d9f54d78bf88cacb8dad6..162effbfbdec09b947a914b27cc7197cc87f1ba9 100644 (file)
@@ -32,41 +32,41 @@ is no way to automatically detect if you are losing events due to CPUs racing.
 Usage Quick Reference
 ---------------------
 
-$ mount -t debugfs debugfs /debug
-$ echo mmiotrace > /debug/tracing/current_tracer
-$ cat /debug/tracing/trace_pipe > mydump.txt &
+$ mount -t debugfs debugfs /sys/kernel/debug
+$ echo mmiotrace > /sys/kernel/debug/tracing/current_tracer
+$ cat /sys/kernel/debug/tracing/trace_pipe > mydump.txt &
 Start X or whatever.
-$ echo "X is up" > /debug/tracing/trace_marker
-$ echo nop > /debug/tracing/current_tracer
+$ echo "X is up" > /sys/kernel/debug/tracing/trace_marker
+$ echo nop > /sys/kernel/debug/tracing/current_tracer
 Check for lost events.
 
 
 Usage
 -----
 
-Make sure debugfs is mounted to /debug. If not, (requires root privileges)
-$ mount -t debugfs debugfs /debug
+Make sure debugfs is mounted to /sys/kernel/debug. If not, (requires root privileges)
+$ mount -t debugfs debugfs /sys/kernel/debug
 
 Check that the driver you are about to trace is not loaded.
 
 Activate mmiotrace (requires root privileges):
-$ echo mmiotrace > /debug/tracing/current_tracer
+$ echo mmiotrace > /sys/kernel/debug/tracing/current_tracer
 
 Start storing the trace:
-$ cat /debug/tracing/trace_pipe > mydump.txt &
+$ cat /sys/kernel/debug/tracing/trace_pipe > mydump.txt &
 The 'cat' process should stay running (sleeping) in the background.
 
 Load the driver you want to trace and use it. Mmiotrace will only catch MMIO
 accesses to areas that are ioremapped while mmiotrace is active.
 
 During tracing you can place comments (markers) into the trace by
-$ echo "X is up" > /debug/tracing/trace_marker
+$ echo "X is up" > /sys/kernel/debug/tracing/trace_marker
 This makes it easier to see which part of the (huge) trace corresponds to
 which action. It is recommended to place descriptive markers about what you
 do.
 
 Shut down mmiotrace (requires root privileges):
-$ echo nop > /debug/tracing/current_tracer
+$ echo nop > /sys/kernel/debug/tracing/current_tracer
 The 'cat' process exits. If it does not, kill it by issuing 'fg' command and
 pressing ctrl+c.
 
@@ -78,10 +78,10 @@ to view your kernel log and look for "mmiotrace has lost events" warning. If
 events were lost, the trace is incomplete. You should enlarge the buffers and
 try again. Buffers are enlarged by first seeing how large the current buffers
 are:
-$ cat /debug/tracing/buffer_size_kb
+$ cat /sys/kernel/debug/tracing/buffer_size_kb
 gives you a number. Approximately double this number and write it back, for
 instance:
-$ echo 128000 > /debug/tracing/buffer_size_kb
+$ echo 128000 > /sys/kernel/debug/tracing/buffer_size_kb
 Then start again from the top.
 
 If you are doing a trace for a driver project, e.g. Nouveau, you should also
index 6ade3a5706227606e49bfd343ee8ccf7c43450df..685784cc023b6e4a242e4efcfc845a54c64c7e57 100644 (file)
@@ -157,9 +157,10 @@ S: Maintained
 F:     drivers/net/r8169.c
 
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
+P:     Alan Cox
+M:     alan@lxorguk.ukuu.org.uk
 L:     linux-serial@vger.kernel.org
 W:     http://serial.sourceforge.net
-M:     alan@lxorguk.ukuu.org.uk
 S:     Odd Fixes
 F:     drivers/serial/8250*
 F:     include/linux/serial_8250.h
index a60cfe757914afb4d4be86494848574cf01b56b6..8ea0d942cdeaf62b6e81ca535c044608c16a308e 100644 (file)
@@ -6,59 +6,65 @@
 mainmenu "Blackfin Kernel Configuration"
 
 config MMU
-       bool
-       default n
+       def_bool n
 
 config FPU
-       bool
-       default n
+       def_bool n
 
 config RWSEM_GENERIC_SPINLOCK
-       bool
-       default y
+       def_bool y
 
 config RWSEM_XCHGADD_ALGORITHM
-       bool
-       default n
+       def_bool n
 
 config BLACKFIN
-       bool
-       default y
+       def_bool y
+       select HAVE_FUNCTION_GRAPH_TRACER
+       select HAVE_FUNCTION_TRACER
        select HAVE_IDE
+       select HAVE_KERNEL_GZIP
+       select HAVE_KERNEL_BZIP2
+       select HAVE_KERNEL_LZMA
        select HAVE_OPROFILE
        select ARCH_WANT_OPTIONAL_GPIOLIB
 
+config GENERIC_BUG
+       def_bool y
+       depends on BUG
+
 config ZONE_DMA
-       bool
-       default y
+       def_bool y
 
 config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
+       def_bool y
 
 config GENERIC_HWEIGHT
-       bool
-       default y
+       def_bool y
 
 config GENERIC_HARDIRQS
-       bool
-       default y
+       def_bool y
 
 config GENERIC_IRQ_PROBE
-       bool
-       default y
+       def_bool y
 
 config GENERIC_GPIO
-       bool
-       default y
+       def_bool y
 
 config FORCE_MAX_ZONEORDER
        int
        default "14"
 
 config GENERIC_CALIBRATE_DELAY
-       bool
-       default y
+       def_bool y
+
+config LOCKDEP_SUPPORT
+       def_bool y
+
+config STACKTRACE_SUPPORT
+       def_bool y
+
+config TRACE_IRQFLAGS_SUPPORT
+       def_bool y
 
 source "init/Kconfig"
 
@@ -408,12 +414,12 @@ comment "Clock/PLL Setup"
 
 config CLKIN_HZ
        int "Frequency of the crystal on the board in Hz"
+       default "10000000" if BFIN532_IP0X
        default "11059200" if BFIN533_STAMP
+       default "24576000" if PNAV10
+       default "25000000" # most people use this
        default "27000000" if BFIN533_EZKIT
-       default "25000000" if (BFIN537_STAMP || BFIN527_EZKIT || H8606_HVSISTEMAS || BLACKSTAMP || BFIN526_EZBRD || BFIN538_EZKIT || BFIN518F-EZBRD)
        default "30000000" if BFIN561_EZKIT
-       default "24576000" if PNAV10
-       default "10000000" if BFIN532_IP0X
        help
          The frequency of CLKIN crystal oscillator on the board in Hz.
          Warning: This value should match the crystal on the board. Otherwise,
index d54c8283825c429c3573209f1343259c6baaac95..6f9533c3d752b6d718ad4712a8de66624ffb49ba 100644 (file)
@@ -137,7 +137,7 @@ archclean:
 
 INSTALL_PATH ?= /tftpboot
 boot := arch/$(ARCH)/boot
-BOOT_TARGETS = vmImage
+BOOT_TARGETS = vmImage vmImage.bz2 vmImage.gz vmImage.lzma
 PHONY += $(BOOT_TARGETS) install
 KBUILD_IMAGE := $(boot)/vmImage
 
@@ -150,7 +150,10 @@ install:
        $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
 
 define archhelp
-  echo  '* vmImage         - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage)'
+  echo  '* vmImage         - Alias to selected kernel format (vmImage.gz by default)'
+  echo  '  vmImage.bz2     - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.bz2)'
+  echo  '* vmImage.gz      - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.gz)'
+  echo  '  vmImage.lzma    - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.lzma)'
   echo  '  install         - Install kernel using'
   echo  '                     (your) ~/bin/$(CROSS_COMPILE)installkernel or'
   echo  '                     (distribution) PATH: $(CROSS_COMPILE)installkernel or'
index 3ae03994b88de9636a05bafb1bc1ee0361ad19b1..229e5080867770d755f4721911774dddfa40ab05 100644 (file)
@@ -1 +1,2 @@
-+vmImage
+vmImage*
+vmlinux*
index e028d13481a93660c9843cde769517500c8046f5..3ab6f23561ddfa8287a642cd82954e219db22fcc 100644 (file)
@@ -8,24 +8,41 @@
 
 MKIMAGE := $(srctree)/scripts/mkuboot.sh
 
-targets := vmImage
-extra-y += vmlinux.bin vmlinux.gz
+targets := vmImage vmImage.bz2 vmImage.gz vmImage.lzma
+extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma
 
 quiet_cmd_uimage = UIMAGE  $@
       cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \
-                   -C gzip -n 'Linux-$(KERNELRELEASE)' -a $(CONFIG_BOOT_LOAD) \
+                   -C $(2) -n 'Linux-$(KERNELRELEASE)' -a $(CONFIG_BOOT_LOAD) \
                    -e $(shell $(NM) vmlinux | awk '$$NF == "__start" {print $$1}') \
                    -d $< $@
 
 $(obj)/vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
-$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
        $(call if_changed,gzip)
 
-$(obj)/vmImage: $(obj)/vmlinux.gz
-       $(call if_changed,uimage)
-       @$(kecho) 'Kernel: $@ is ready'
+$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,bzip2)
+
+$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,lzma)
+
+$(obj)/vmImage.bz2: $(obj)/vmlinux.bin.bz2
+       $(call if_changed,uimage,bzip2)
+
+$(obj)/vmImage.gz: $(obj)/vmlinux.bin.gz
+       $(call if_changed,uimage,gzip)
+
+$(obj)/vmImage.lzma: $(obj)/vmlinux.bin.lzma
+       $(call if_changed,uimage,lzma)
+
+suffix-$(CONFIG_KERNEL_GZIP)  := gz
+suffix-$(CONFIG_KERNEL_BZIP2) := bz2
+suffix-$(CONFIG_KERNEL_LZMA)  := lzma
+$(obj)/vmImage: $(obj)/vmImage.$(suffix-y)
+       @ln -sf $(notdir $<) $@
 
 install:
        sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
index 7bbf44e4ddf9642a264396d26eba88e7ce08f842..b1d92f13ef9602ca8b54a14d30b3335b735350e2 100644 (file)
@@ -90,7 +90,7 @@ static inline int atomic_test_mask(int mask, atomic_t *v)
 
 static inline void atomic_add(int i, atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter += i;
@@ -99,7 +99,7 @@ static inline void atomic_add(int i, atomic_t *v)
 
 static inline void atomic_sub(int i, atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter -= i;
@@ -110,7 +110,7 @@ static inline void atomic_sub(int i, atomic_t *v)
 static inline int atomic_add_return(int i, atomic_t *v)
 {
        int __temp = 0;
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter += i;
@@ -124,7 +124,7 @@ static inline int atomic_add_return(int i, atomic_t *v)
 static inline int atomic_sub_return(int i, atomic_t *v)
 {
        int __temp = 0;
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter -= i;
@@ -136,7 +136,7 @@ static inline int atomic_sub_return(int i, atomic_t *v)
 
 static inline void atomic_inc(volatile atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter++;
@@ -145,7 +145,7 @@ static inline void atomic_inc(volatile atomic_t *v)
 
 static inline void atomic_dec(volatile atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter--;
@@ -154,7 +154,7 @@ static inline void atomic_dec(volatile atomic_t *v)
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter &= ~mask;
@@ -163,7 +163,7 @@ static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 
 static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter |= mask;
index daffc0684e753bd4f3f19a9e060988b694fa8219..e39277ea43e8bfd38e4daacd8792526762ae284e 100644 (file)
@@ -31,7 +31,7 @@
 
 #ifndef __ASSEMBLY__
 
-#include <asm-generic/sections.h>
+#include <asm/sections.h>
 #include <asm/ptrace.h>
 #include <asm/user.h>
 #include <linux/linkage.h>
@@ -99,15 +99,6 @@ extern const char bfin_board_name[];
 extern unsigned long bfin_sic_iwr[];
 extern unsigned vr_wakeup;
 extern u16 _bfin_swrst; /* shadow for Software Reset Register (SWRST) */
-extern unsigned long _ramstart, _ramend, _rambase;
-extern unsigned long memory_start, memory_end, physical_mem_end;
-extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[],
-       _ebss_l1[], _l1_lma_start[], _sdata_b_l1[], _sbss_b_l1[], _ebss_b_l1[],
-       _stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], _sbss_l2[],
-       _ebss_l2[], _l2_lma_start[];
-
-/* only used when MTD_UCLINUX */
-extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size;
 
 #ifdef CONFIG_BFIN_ICACHE_LOCK
 extern void cache_grab_lock(int way);
index 21b036eadab1d4e8450499c2c9c097f0f0546495..75fee2f7d9f240b3c98d5080a35016eca8e60399 100644 (file)
@@ -109,7 +109,8 @@ static inline void clear_bit(int nr, volatile unsigned long *addr)
 
 static inline void change_bit(int nr, volatile unsigned long *addr)
 {
-       int mask, flags;
+       int mask;
+       unsigned long flags;
        unsigned long *ADDR = (unsigned long *)addr;
 
        ADDR += nr >> 5;
index 6d3e11b1fc576c6f141c98e3086e477c691a23df..655e49540e41d902b6396d5a2dbbb4ae594b2778 100644 (file)
@@ -2,13 +2,58 @@
 #define _BLACKFIN_BUG_H
 
 #ifdef CONFIG_BUG
-#define HAVE_ARCH_BUG
 
-#define BUG() do { \
-       dump_bfin_trace_buffer(); \
-       printk(KERN_EMERG "BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
-       panic("BUG!"); \
-} while (0)
+#define BFIN_BUG_OPCODE        0xefcd
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+
+#define _BUG_OR_WARN(flags)                                            \
+       asm volatile(                                                   \
+               "1:     .hword  %0\n"                                   \
+               "       .section __bug_table,\"a\",@progbits\n"         \
+               "2:     .long   1b\n"                                   \
+               "       .long   %1\n"                                   \
+               "       .short  %2\n"                                   \
+               "       .short  %3\n"                                   \
+               "       .org    2b + %4\n"                              \
+               "       .previous"                                      \
+               :                                                       \
+               : "i"(BFIN_BUG_OPCODE), "i"(__FILE__),                  \
+                 "i"(__LINE__), "i"(flags),                            \
+                 "i"(sizeof(struct bug_entry)))
+
+#else
+
+#define _BUG_OR_WARN(flags)                                            \
+       asm volatile(                                                   \
+               "1:     .hword  %0\n"                                   \
+               "       .section __bug_table,\"a\",@progbits\n"         \
+               "2:     .long   1b\n"                                   \
+               "       .short  %1\n"                                   \
+               "       .org    2b + %2\n"                              \
+               "       .previous"                                      \
+               :                                                       \
+               : "i"(BFIN_BUG_OPCODE), "i"(flags),                     \
+                 "i"(sizeof(struct bug_entry)))
+
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
+
+#define BUG()                                                          \
+       do {                                                            \
+               _BUG_OR_WARN(0);                                        \
+               for (;;);                                               \
+       } while (0)
+
+#define WARN_ON(condition)                                                     \
+       ({                                                              \
+               int __ret_warn_on = !!(condition);                      \
+               if (unlikely(__ret_warn_on))                            \
+                       _BUG_OR_WARN(BUGFLAG_WARNING);                  \
+               unlikely(__ret_warn_on);                                \
+       })
+
+#define HAVE_ARCH_BUG
+#define HAVE_ARCH_WARN_ON
 
 #endif
 
index 86637814cf252b9146f398367aea451b9b829b41..2ef669ed9222f03df97a7b05e1e7e5cca8d43c2e 100644 (file)
 #define L1_CACHE_SHIFT_MAX     5
 
 #if defined(CONFIG_SMP) && \
-    !defined(CONFIG_BFIN_CACHE_COHERENT) && \
-    defined(CONFIG_BFIN_DCACHE)
-#define __ARCH_SYNC_CORE_DCACHE
+    !defined(CONFIG_BFIN_CACHE_COHERENT)
+# if defined(CONFIG_BFIN_ICACHE)
+# define __ARCH_SYNC_CORE_ICACHE
+# endif
+# if defined(CONFIG_BFIN_DCACHE)
+# define __ARCH_SYNC_CORE_DCACHE
+# endif
 #ifndef __ASSEMBLY__
 asmlinkage void __raw_smp_mark_barrier_asm(void);
 asmlinkage void __raw_smp_check_barrier_asm(void);
@@ -51,6 +55,7 @@ static inline void smp_check_barrier(void)
 }
 
 void resync_core_dcache(void);
+void resync_core_icache(void);
 #endif
 #endif
 
index 94697f0f6f402fc2bf772ca778b96dddf750344d..5c17dee53b5dca8fa3fe0e0520958c18a4ac8be8 100644 (file)
@@ -37,6 +37,7 @@ extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned lo
 extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address);
 extern void blackfin_dflush_page(void *page);
 extern void blackfin_invalidate_entire_dcache(void);
+extern void blackfin_invalidate_entire_icache(void);
 
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
@@ -97,7 +98,7 @@ do { memcpy(dst, src, len);                                           \
 extern unsigned long reserved_mem_dcache_on;
 extern unsigned long reserved_mem_icache_on;
 
-static inline int bfin_addr_dcachable(unsigned long addr)
+static inline int bfin_addr_dcacheable(unsigned long addr)
 {
 #ifdef CONFIG_BFIN_DCACHE
        if (addr < (_ramend - DMA_UNCACHED_REGION))
index c2594ef877f69bc96771f1f2d75c6509f3b4584d..565b8136855ed16d5237376cc7186878dcc46855 100644 (file)
@@ -34,6 +34,7 @@ struct blackfin_cpudata {
        unsigned int dmemctl;
        unsigned long loops_per_jiffy;
        unsigned long dcache_invld_count;
+       unsigned long icache_invld_count;
 };
 
 DECLARE_PER_CPU(struct blackfin_cpudata, cpu_data);
index 40a8c178f10d9e85a2873c83247c3f2fe553f408..8643680f0f786cf53bf94a40f6d4241a511565ec 100644 (file)
@@ -1 +1,13 @@
-/* empty */
+/*
+ * Blackfin ftrace code
+ *
+ * Copyright 2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_BFIN_FTRACE_H__
+#define __ASM_BFIN_FTRACE_H__
+
+#define MCOUNT_INSN_SIZE       8 /* sizeof mcount call: LINK + CALL */
+
+#endif
index 51d0bf5e2899d4543810e344d842591057b210ee..bbe1c3726b69acf41cc7ffb2038e5c183c718ecf 100644 (file)
 #include <asm/atomic.h>
 #include <asm/traps.h>
 
-#define IPIPE_ARCH_STRING     "1.9-01"
+#define IPIPE_ARCH_STRING     "1.10-00"
 #define IPIPE_MAJOR_NUMBER    1
-#define IPIPE_MINOR_NUMBER    9
-#define IPIPE_PATCH_NUMBER    1
+#define IPIPE_MINOR_NUMBER    10
+#define IPIPE_PATCH_NUMBER    0
 
 #ifdef CONFIG_SMP
 #error "I-pipe/blackfin: SMP not implemented"
@@ -54,10 +54,11 @@ do {                                                \
 
 #define task_hijacked(p)                                               \
        ({                                                              \
-               int __x__ = ipipe_current_domain != ipipe_root_domain;  \
-               /* We would need to clear the SYNC flag for the root domain */ \
-               /* over the current processor in SMP mode. */           \
-               local_irq_enable_hw(); __x__;                           \
+               int __x__ = __ipipe_root_domain_p;                      \
+               __clear_bit(IPIPE_SYNC_FLAG, &ipipe_root_cpudom_var(status)); \
+               if (__x__)                                              \
+                       local_irq_enable_hw();                          \
+               !__x__;                                                 \
        })
 
 struct ipipe_domain;
@@ -179,23 +180,24 @@ static inline unsigned long __ipipe_ffnz(unsigned long ul)
 
 #define __ipipe_run_isr(ipd, irq)                                      \
        do {                                                            \
-               if (ipd == ipipe_root_domain) {                         \
+               if (!__ipipe_pipeline_head_p(ipd))                      \
                        local_irq_enable_hw();                          \
-                       if (ipipe_virtual_irq_p(irq))                   \
+               if (ipd == ipipe_root_domain) {                         \
+                       if (unlikely(ipipe_virtual_irq_p(irq))) {       \
+                               irq_enter();                            \
                                ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \
-                       else                                            \
+                               irq_exit();                             \
+                       } else                                          \
                                ipd->irqs[irq].handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs)); \
-                       local_irq_disable_hw();                         \
                } else {                                                \
                        __clear_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
-                       local_irq_enable_nohead(ipd);                   \
                        ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \
                        /* Attempt to exit the outer interrupt level before \
                         * starting the deferred IRQ processing. */     \
-                       local_irq_disable_nohead(ipd);                  \
                        __ipipe_run_irqtail();                          \
                        __set_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
                }                                                       \
+               local_irq_disable_hw();                                 \
        } while (0)
 
 #define __ipipe_syscall_watched_p(p, sc)       \
index 7645e85a5f6f70319c2a20158c0f5d39fbe84ce7..400bdd52ce8732a6ed577978c65e9efcebb26f8e 100644 (file)
 #ifndef _BFIN_IRQ_H_
 #define _BFIN_IRQ_H_
 
-/* SYS_IRQS and NR_IRQS are defined in <mach-bf5xx/irq.h>*/
-#include <mach/irq.h>
-#include <asm/pda.h>
-#include <asm/processor.h>
-
-#ifdef CONFIG_SMP
-/* Forward decl needed due to cdef inter dependencies */
-static inline uint32_t __pure bfin_dspid(void);
-# define blackfin_core_id() (bfin_dspid() & 0xff)
-# define bfin_irq_flags cpu_pda[blackfin_core_id()].imask
-#else
-extern unsigned long bfin_irq_flags;
-#endif
-
-#ifdef CONFIG_IPIPE
-
-#include <linux/ipipe_trace.h>
+#include <linux/irqflags.h>
 
-void __ipipe_unstall_root(void);
-
-void __ipipe_restore_root(unsigned long flags);
-
-#ifdef CONFIG_DEBUG_HWERR
-# define __all_masked_irq_flags 0x3f
-# define __save_and_cli_hw(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               "sti %1;" \
-               : "=&d"(x) \
-               : "d" (0x3F) \
-       )
-#else
-# define __all_masked_irq_flags 0x1f
-# define __save_and_cli_hw(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               : "=&d"(x) \
-       )
-#endif
-
-#define irqs_enabled_from_flags_hw(x)  ((x) != __all_masked_irq_flags)
-#define raw_irqs_disabled_flags(flags) (!irqs_enabled_from_flags_hw(flags))
-#define local_test_iflag_hw(x)         irqs_enabled_from_flags_hw(x)
-
-#define local_save_flags(x)                                     \
-       do {                                                     \
-               (x) = __ipipe_test_root() ?                      \
-                       __all_masked_irq_flags : bfin_irq_flags; \
-               barrier();                                       \
-       } while (0)
-
-#define local_irq_save(x)                                       \
-       do {                                                     \
-               (x) = __ipipe_test_and_stall_root() ?            \
-                       __all_masked_irq_flags : bfin_irq_flags; \
-               barrier();                                       \
-       } while (0)
-
-static inline void local_irq_restore(unsigned long x)
-{
-       barrier();
-       __ipipe_restore_root(x == __all_masked_irq_flags);
-}
-
-#define local_irq_disable()                    \
-       do {                                    \
-               __ipipe_stall_root();           \
-               barrier();                      \
-       } while (0)
-
-static inline void local_irq_enable(void)
-{
-       barrier();
-       __ipipe_unstall_root();
-}
-
-#define irqs_disabled()                __ipipe_test_root()
-
-#define local_save_flags_hw(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               "sti %0;" \
-               : "=d"(x) \
-       )
-
-#define        irqs_disabled_hw()                              \
-       ({                                              \
-               unsigned long flags;                    \
-               local_save_flags_hw(flags);             \
-               !irqs_enabled_from_flags_hw(flags);     \
-       })
-
-static inline unsigned long raw_mangle_irq_bits(int virt, unsigned long real)
-{
-       /* Merge virtual and real interrupt mask bits into a single
-          32bit word. */
-       return (real & ~(1 << 31)) | ((virt != 0) << 31);
-}
-
-static inline int raw_demangle_irq_bits(unsigned long *x)
-{
-       int virt = (*x & (1 << 31)) != 0;
-       *x &= ~(1L << 31);
-       return virt;
-}
-
-#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
-
-#define local_irq_disable_hw()                                         \
-       do {                                                            \
-               int _tmp_dummy;                                         \
-               if (!irqs_disabled_hw())                                \
-                       ipipe_trace_begin(0x80000000);                  \
-               __asm__ __volatile__ ("cli %0;" : "=d" (_tmp_dummy) : );        \
-       } while (0)
-
-#define local_irq_enable_hw()                                          \
-       do {                                                            \
-               if (irqs_disabled_hw())                                 \
-                       ipipe_trace_end(0x80000000);                    \
-               __asm__ __volatile__ ("sti %0;" : : "d"(bfin_irq_flags));       \
-       } while (0)
-
-#define local_irq_save_hw(x)                           \
-       do {                                            \
-               __save_and_cli_hw(x);                   \
-               if (local_test_iflag_hw(x))             \
-                       ipipe_trace_begin(0x80000001);  \
-       } while (0)
-
-#define local_irq_restore_hw(x)                                \
-       do {                                            \
-               if (local_test_iflag_hw(x)) {           \
-                       ipipe_trace_end(0x80000001);    \
-                       local_irq_enable_hw_notrace();  \
-               }                                       \
-       } while (0)
-
-#define local_irq_disable_hw_notrace()                                 \
-       do {                                                            \
-               int _tmp_dummy;                                         \
-               __asm__ __volatile__ ("cli %0;" : "=d" (_tmp_dummy) : );        \
-       } while (0)
-
-#define local_irq_enable_hw_notrace() \
-       __asm__ __volatile__( \
-               "sti %0;" \
-               : \
-               : "d"(bfin_irq_flags) \
-       )
-
-#define local_irq_save_hw_notrace(x) __save_and_cli_hw(x)
-
-#define local_irq_restore_hw_notrace(x)                        \
-       do {                                            \
-               if (local_test_iflag_hw(x))             \
-                       local_irq_enable_hw_notrace();  \
-       } while (0)
-
-#else /* CONFIG_IPIPE_TRACE_IRQSOFF */
-
-#define local_irq_enable_hw() \
-       __asm__ __volatile__( \
-               "sti %0;" \
-               : \
-               : "d"(bfin_irq_flags) \
-       )
-
-#define local_irq_disable_hw()                 \
-       do {                                    \
-               int _tmp_dummy;                 \
-               __asm__ __volatile__ (          \
-                       "cli %0;"               \
-                       : "=d" (_tmp_dummy));   \
-       } while (0)
-
-#define local_irq_restore_hw(x) \
-       do { \
-               if (irqs_enabled_from_flags_hw(x)) \
-                       local_irq_enable_hw(); \
-       } while (0)
-
-#define local_irq_save_hw(x)           __save_and_cli_hw(x)
-
-#define local_irq_disable_hw_notrace() local_irq_disable_hw()
-#define local_irq_enable_hw_notrace()  local_irq_enable_hw()
-#define local_irq_save_hw_notrace(x)   local_irq_save_hw(x)
-#define local_irq_restore_hw_notrace(x)        local_irq_restore_hw(x)
-
-#endif  /* CONFIG_IPIPE_TRACE_IRQSOFF */
-
-#else /* !CONFIG_IPIPE */
-
-/*
- * Interrupt configuring macros.
- */
-#define local_irq_disable() \
-       do { \
-               int __tmp_dummy; \
-               __asm__ __volatile__( \
-                       "cli %0;" \
-                       : "=d" (__tmp_dummy) \
-               ); \
-       } while (0)
-
-#define local_irq_enable() \
-       __asm__ __volatile__( \
-               "sti %0;" \
-               : \
-               : "d" (bfin_irq_flags) \
-       )
-
-#ifdef CONFIG_DEBUG_HWERR
-# define __save_and_cli(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               "sti %1;" \
-               : "=&d" (x) \
-               : "d" (0x3F) \
-       )
-#else
-# define __save_and_cli(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               : "=&d" (x) \
-       )
-#endif
-
-#define local_save_flags(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               "sti %0;" \
-               : "=d" (x) \
-       )
-
-#ifdef CONFIG_DEBUG_HWERR
-#define irqs_enabled_from_flags(x) (((x) & ~0x3f) != 0)
-#else
-#define irqs_enabled_from_flags(x) ((x) != 0x1f)
-#endif
-
-#define local_irq_restore(x) \
-       do { \
-               if (irqs_enabled_from_flags(x)) \
-                       local_irq_enable(); \
-       } while (0)
-
-/* For spinlocks etc */
-#define local_irq_save(x) __save_and_cli(x)
-
-#define irqs_disabled()                                \
-({                                             \
-       unsigned long flags;                    \
-       local_save_flags(flags);                \
-       !irqs_enabled_from_flags(flags);        \
-})
-
-#define local_irq_save_hw(x)           local_irq_save(x)
-#define local_irq_restore_hw(x)                local_irq_restore(x)
-#define local_irq_enable_hw()          local_irq_enable()
-#define local_irq_disable_hw()         local_irq_disable()
-#define irqs_disabled_hw()             irqs_disabled()
+/* SYS_IRQS and NR_IRQS are defined in <mach-bf5xx/irq.h> */
+#include <mach/irq.h>
 
-#endif /* !CONFIG_IPIPE */
+/* Xenomai IPIPE helpers */
+#define local_irq_restore_hw(x) local_irq_restore(x)
+#define local_irq_save_hw(x)    local_irq_save(x)
+#define local_irq_enable_hw(x)  local_irq_enable(x)
+#define local_irq_disable_hw(x) local_irq_disable(x)
+#define irqs_disabled_hw(x)     irqs_disabled(x)
 
 #if ANOMALY_05000244 && defined(CONFIG_BFIN_ICACHE)
 # define NOP_PAD_ANOMALY_05000244 "nop; nop;"
diff --git a/arch/blackfin/include/asm/irqflags.h b/arch/blackfin/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..139cba4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * interface to Blackfin CEC
+ *
+ * Copyright 2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_BFIN_IRQFLAGS_H__
+#define __ASM_BFIN_IRQFLAGS_H__
+
+#ifdef CONFIG_SMP
+# include <asm/pda.h>
+# include <asm/processor.h>
+/* Forward decl needed due to cdef inter dependencies */
+static inline uint32_t __pure bfin_dspid(void);
+# define blackfin_core_id() (bfin_dspid() & 0xff)
+# define bfin_irq_flags cpu_pda[blackfin_core_id()].imask
+#else
+extern unsigned long bfin_irq_flags;
+#endif
+
+static inline void bfin_sti(unsigned long flags)
+{
+       asm volatile("sti %0;" : : "d" (flags));
+}
+
+static inline unsigned long bfin_cli(void)
+{
+       unsigned long flags;
+       asm volatile("cli %0;" : "=d" (flags));
+       return flags;
+}
+
+static inline void raw_local_irq_disable(void)
+{
+       bfin_cli();
+}
+static inline void raw_local_irq_enable(void)
+{
+       bfin_sti(bfin_irq_flags);
+}
+
+#define raw_local_save_flags(flags) do { (flags) = bfin_read_IMASK(); } while (0)
+
+#define raw_irqs_disabled_flags(flags) (((flags) & ~0x3f) == 0)
+
+static inline void raw_local_irq_restore(unsigned long flags)
+{
+       if (!raw_irqs_disabled_flags(flags))
+               raw_local_irq_enable();
+}
+
+static inline unsigned long __raw_local_irq_save(void)
+{
+       unsigned long flags = bfin_cli();
+#ifdef CONFIG_DEBUG_HWERR
+       bfin_sti(0x3f);
+#endif
+       return flags;
+}
+#define raw_local_irq_save(flags) do { (flags) = __raw_local_irq_save(); } while (0)
+
+#endif
diff --git a/arch/blackfin/include/asm/mutex-dec.h b/arch/blackfin/include/asm/mutex-dec.h
deleted file mode 100644 (file)
index 0134151..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * include/asm-generic/mutex-dec.h
- *
- * Generic implementation of the mutex fastpath, based on atomic
- * decrement/increment.
- */
-#ifndef _ASM_GENERIC_MUTEX_DEC_H
-#define _ASM_GENERIC_MUTEX_DEC_H
-
-/**
- *  __mutex_fastpath_lock - try to take the lock by moving the count
- *                          from 1 to a 0 value
- *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 1
- *
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function MUST leave the value lower than
- * 1 even when the "1" assertion wasn't true.
- */
-static inline void
-__mutex_fastpath_lock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
-{
-       if (unlikely(atomic_dec_return(count) < 0))
-               fail_fn(count);
-       else
-               smp_mb();
-}
-
-/**
- *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
- *                                 from 1 to a 0 value
- *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 1
- *
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns.
- */
-static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, fastcall int (*fail_fn)(atomic_t *))
-{
-       if (unlikely(atomic_dec_return(count) < 0))
-               return fail_fn(count);
-       else {
-               smp_mb();
-               return 0;
-       }
-}
-
-/**
- *  __mutex_fastpath_unlock - try to promote the count from 0 to 1
- *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 0
- *
- * Try to promote the count from 0 to 1. If it wasn't 0, call <fail_fn>.
- * In the failure case, this function is allowed to either set the value to
- * 1, or to set it to a value lower than 1.
- *
- * If the implementation sets it to a value of lower than 1, then the
- * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs
- * to return 0 otherwise.
- */
-static inline void
-__mutex_fastpath_unlock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
-{
-       smp_mb();
-       if (unlikely(atomic_inc_return(count) <= 0))
-               fail_fn(count);
-}
-
-#define __mutex_slowpath_needs_to_unlock()             1
-
-/**
- * __mutex_fastpath_trylock - try to acquire the mutex, without waiting
- *
- *  @count: pointer of type atomic_t
- *  @fail_fn: fallback function
- *
- * Change the count from 1 to a value lower than 1, and return 0 (failure)
- * if it wasn't 1 originally, or return 1 (success) otherwise. This function
- * MUST leave the value lower than 1 even when the "1" assertion wasn't true.
- * Additionally, if the value was < 0 originally, this function must not leave
- * it to 0 on failure.
- *
- * If the architecture has no effective trylock variant, it should call the
- * <fail_fn> spinlock-based trylock variant unconditionally.
- */
-static inline int
-__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
-{
-       /*
-        * We have two variants here. The cmpxchg based one is the best one
-        * because it never induce a false contention state.  It is included
-        * here because architectures using the inc/dec algorithms over the
-        * xchg ones are much more likely to support cmpxchg natively.
-        *
-        * If not we fall back to the spinlock based variant - that is
-        * just as efficient (and simpler) as a 'destructive' probing of
-        * the mutex state would be.
-        */
-#ifdef __HAVE_ARCH_CMPXCHG
-       if (likely(atomic_cmpxchg(count, 1, 0) == 1)) {
-               smp_mb();
-               return 1;
-       }
-       return 0;
-#else
-       return fail_fn(count);
-#endif
-}
-
-#endif
index 1443c3353a8c811bc701f16a078ef04ec52c9ad6..e7fd0ecd73f75de4d2a7df13b85a5049e046b7aa 100644 (file)
@@ -4,4 +4,15 @@
 /* nothing to see, move along */
 #include <asm-generic/sections.h>
 
+/* only used when MTD_UCLINUX */
+extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size;
+
+extern unsigned long _ramstart, _ramend, _rambase;
+extern unsigned long memory_start, memory_end, physical_mem_end;
+
+extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[],
+       _ebss_l1[], _l1_lma_start[], _sdata_b_l1[], _sbss_b_l1[], _ebss_b_l1[],
+       _stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], _sbss_l2[],
+       _ebss_l2[], _l2_lma_start[];
+
 #endif
index a4c8254bec5514eff746b217417816930f34a291..294dbda24164c442beea46664f8133c9c6bba85d 100644 (file)
 #define _BLACKFIN_SYSTEM_H
 
 #include <linux/linkage.h>
-#include <linux/compiler.h>
+#include <linux/irqflags.h>
 #include <mach/anomaly.h>
+#include <asm/cache.h>
 #include <asm/pda.h>
-#include <asm/processor.h>
 #include <asm/irq.h>
 
 /*
index cf5066d3efd2b79f6e9f287de452ec8efd96385a..da35133c171de5e57fdee251e2c16b2b7d8ea5a7 100644 (file)
 #define __NR_inotify_init1     365
 #define __NR_preadv            366
 #define __NR_pwritev           367
+#define __NR_rt_tgsigqueueinfo 368
 
-#define __NR_syscall           368
+#define __NR_syscall           369
 #define NR_syscalls            __NR_syscall
 
 /* Old optional stuff no one actually uses */
index fd4d4328a0f2aa94fb5ef97afcc01f0018e89edf..3731088e181b4a85b010971423e817b448bfed3a 100644 (file)
@@ -15,6 +15,10 @@ else
     obj-y += time.o
 endif
 
+obj-$(CONFIG_FUNCTION_TRACER)        += ftrace-entry.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER)  += ftrace.o
+CFLAGS_REMOVE_ftrace.o = -pg
+
 obj-$(CONFIG_IPIPE)                  += ipipe.o
 obj-$(CONFIG_IPIPE_TRACE_MCOUNT)     += mcount.o
 obj-$(CONFIG_BFIN_GPTIMERS)          += gptimers.o
@@ -23,6 +27,7 @@ obj-$(CONFIG_MODULES)                += module.o
 obj-$(CONFIG_KGDB)                   += kgdb.o
 obj-$(CONFIG_KGDB_TESTS)             += kgdb_test.o
 obj-$(CONFIG_EARLY_PRINTK)           += early_printk.o
+obj-$(CONFIG_STACKTRACE)             += stacktrace.o
 
 # the kgdb test puts code into L2 and without linker
 # relaxation, we need to force long calls to/from it
index 763ed84ba459f3236fd7831075cdb002bd610d96..e0bf8cc06907abd67040c37127f0091792c39a8a 100644 (file)
@@ -453,10 +453,10 @@ void *dma_memcpy(void *pdst, const void *psrc, size_t size)
        unsigned long src = (unsigned long)psrc;
        size_t bulk, rest;
 
-       if (bfin_addr_dcachable(src))
+       if (bfin_addr_dcacheable(src))
                blackfin_dcache_flush_range(src, src + size);
 
-       if (bfin_addr_dcachable(dst))
+       if (bfin_addr_dcacheable(dst))
                blackfin_dcache_invalidate_range(dst, dst + size);
 
        bulk = size & ~0xffff;
index 53e893ff708aa547674aaab28c0974c54272f37c..aa05e638fb7cb6fa3d4b5cd7e05b2c3ecc128eb1 100644 (file)
@@ -103,3 +103,8 @@ EXPORT_SYMBOL(__raw_smp_mark_barrier_asm);
 EXPORT_SYMBOL(__raw_smp_check_barrier_asm);
 #endif
 #endif
+
+#ifdef CONFIG_FUNCTION_TRACER
+extern void _mcount(void);
+EXPORT_SYMBOL(_mcount);
+#endif
index 87463ce87f5aef0073e0d5fcebad50eb61404cf7..784923e52a9a740714d37f74feca5272bc1c84fc 100644 (file)
@@ -151,7 +151,7 @@ static noinline int dcplb_miss(unsigned int cpu)
 
        d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
 #ifdef CONFIG_BFIN_DCACHE
-       if (bfin_addr_dcachable(addr)) {
+       if (bfin_addr_dcacheable(addr)) {
                d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
 #ifdef CONFIG_BFIN_WT
                d_data |= CPLB_L1_AOW | CPLB_WT;
index 8cbb47c7b6639a76434f395b820304a62ecf9f82..12b030842fdbc1623c99997c60e67d534f168112 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/cplbinit.h>
 #include <asm/cplb.h>
 #include <asm/mmu_context.h>
+#include <asm/traps.h>
 
 /*
  * WARNING
@@ -100,28 +101,6 @@ static inline void write_icplb_data(int cpu, int idx, unsigned long data,
 #endif
 }
 
-/*
- * Given the contents of the status register, return the index of the
- * CPLB that caused the fault.
- */
-static inline int faulting_cplb_index(int status)
-{
-       int signbits = __builtin_bfin_norm_fr1x32(status & 0xFFFF);
-       return 30 - signbits;
-}
-
-/*
- * Given the contents of the status register and the DCPLB_DATA contents,
- * return true if a write access should be permitted.
- */
-static inline int write_permitted(int status, unsigned long data)
-{
-       if (status & FAULT_USERSUPV)
-               return !!(data & CPLB_SUPV_WR);
-       else
-               return !!(data & CPLB_USER_WR);
-}
-
 /* Counters to implement round-robin replacement.  */
 static int icplb_rr_index[NR_CPUS] PDT_ATTR;
 static int dcplb_rr_index[NR_CPUS] PDT_ATTR;
@@ -245,43 +224,16 @@ MGR_ATTR static int dcplb_miss(int cpu)
        return CPLB_RELOADED;
 }
 
-MGR_ATTR static noinline int dcplb_protection_fault(int cpu)
-{
-       int status = bfin_read_DCPLB_STATUS();
-
-       nr_dcplb_prot[cpu]++;
-
-       if (likely(status & FAULT_RW)) {
-               int idx = faulting_cplb_index(status);
-               unsigned long regaddr = DCPLB_DATA0 + idx * 4;
-               unsigned long data = bfin_read32(regaddr);
-
-               /* Check if fault is to dirty a clean page */
-               if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) &&
-                   write_permitted(status, data)) {
-
-                       dcplb_tbl[cpu][idx].data = data;
-                       bfin_write32(regaddr, data);
-                       return CPLB_RELOADED;
-               }
-       }
-
-       return CPLB_PROT_VIOL;
-}
-
 MGR_ATTR int cplb_hdr(int seqstat, struct pt_regs *regs)
 {
        int cause = seqstat & 0x3f;
        unsigned int cpu = smp_processor_id();
        switch (cause) {
-       case 0x2C:
+       case VEC_CPLB_I_M:
                return icplb_miss(cpu);
-       case 0x26:
+       case VEC_CPLB_M:
                return dcplb_miss(cpu);
        default:
-               if (unlikely(cause == 0x23))
-                       return dcplb_protection_fault(cpu);
-
                return CPLB_UNKNOWN_ERR;
        }
 }
index 3302719173ca63ba39656ad5d8a5623c74994993..2ab56811841c6c6982e8cc00d1ca2724addc54d1 100644 (file)
@@ -202,11 +202,15 @@ asmlinkage void __init init_early_exception_vectors(void)
 asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
 {
        /* This can happen before the uart is initialized, so initialize
-        * the UART now
+        * the UART now (but only if we are running on the processor we think
+        * we are compiled for - otherwise we write to MMRs that don't exist,
+        * and cause other problems. Nothing comes out the UART, but it does
+        * end up in the __buf_log.
         */
-       if (likely(early_console == NULL))
+       if (likely(early_console == NULL) && CPUID == bfin_cpuid())
                setup_early_printk(DEFAULT_EARLY_PORT);
 
+       printk(KERN_EMERG "Early panic\n");
        dump_bfin_mem(fp);
        show_regs(fp);
        dump_bfin_trace_buffer();
diff --git a/arch/blackfin/kernel/ftrace-entry.S b/arch/blackfin/kernel/ftrace-entry.S
new file mode 100644 (file)
index 0000000..6980b7a
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * mcount and friends -- ftrace stuff
+ *
+ * Copyright (C) 2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/linkage.h>
+#include <asm/ftrace.h>
+
+.text
+
+/* GCC will have called us before setting up the function prologue, so we
+ * can clobber the normal scratch registers, but we need to make sure to
+ * save/restore the registers used for argument passing (R0-R2) in case
+ * the profiled function is using them.  With data registers, R3 is the
+ * only one we can blow away.  With pointer registers, we have P0-P2.
+ *
+ * Upon entry, the RETS will point to the top of the current profiled
+ * function.  And since GCC setup the frame for us, the previous function
+ * will be waiting there.  mmmm pie.
+ */
+ENTRY(__mcount)
+       /* save third function arg early so we can do testing below */
+       [--sp] = r2;
+
+       /* load the function pointer to the tracer */
+       p0.l = _ftrace_trace_function;
+       p0.h = _ftrace_trace_function;
+       r3 = [p0];
+
+       /* optional micro optimization: don't call the stub tracer */
+       r2.l = _ftrace_stub;
+       r2.h = _ftrace_stub;
+       cc = r2 == r3;
+       if ! cc jump .Ldo_trace;
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       /* if the ftrace_graph_return function pointer is not set to
+        * the ftrace_stub entry, call prepare_ftrace_return().
+        */
+       p0.l = _ftrace_graph_return;
+       p0.h = _ftrace_graph_return;
+       r3 = [p0];
+       cc = r2 == r3;
+       if ! cc jump _ftrace_graph_caller;
+
+       /* similarly, if the ftrace_graph_entry function pointer is not
+        * set to the ftrace_graph_entry_stub entry, ...
+        */
+       p0.l = _ftrace_graph_entry;
+       p0.h = _ftrace_graph_entry;
+       r2.l = _ftrace_graph_entry_stub;
+       r2.h = _ftrace_graph_entry_stub;
+       r3 = [p0];
+       cc = r2 == r3;
+       if ! cc jump _ftrace_graph_caller;
+#endif
+
+       r2 = [sp++];
+       rts;
+
+.Ldo_trace:
+
+       /* save first/second function arg and the return register */
+       [--sp] = r0;
+       [--sp] = r1;
+       [--sp] = rets;
+
+       /* setup the tracer function */
+       p0 = r3;
+
+       /* tracer(ulong frompc, ulong selfpc):
+        *  frompc: the pc that did the call to ...
+        *  selfpc: ... this location
+        * the selfpc itself will need adjusting for the mcount call
+        */
+       r1 = rets;
+       r0 = [fp + 4];
+       r1 += -MCOUNT_INSN_SIZE;
+
+       /* call the tracer */
+       call (p0);
+
+       /* restore state and get out of dodge */
+.Lfinish_trace:
+       rets = [sp++];
+       r1 = [sp++];
+       r0 = [sp++];
+       r2 = [sp++];
+
+.globl _ftrace_stub
+_ftrace_stub:
+       rts;
+ENDPROC(__mcount)
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+/* The prepare_ftrace_return() function is similar to the trace function
+ * except it takes a pointer to the location of the frompc.  This is so
+ * the prepare_ftrace_return() can hijack it temporarily for probing
+ * purposes.
+ */
+ENTRY(_ftrace_graph_caller)
+       /* save first/second function arg and the return register */
+       [--sp] = r0;
+       [--sp] = r1;
+       [--sp] = rets;
+
+       r0 = fp;
+       r1 = rets;
+       r0 += 4;
+       r1 += -MCOUNT_INSN_SIZE;
+       call _prepare_ftrace_return;
+
+       jump .Lfinish_trace;
+ENDPROC(_ftrace_graph_caller)
+
+/* Undo the rewrite caused by ftrace_graph_caller().  The common function
+ * ftrace_return_to_handler() will return the original rets so we can
+ * restore it and be on our way.
+ */
+ENTRY(_return_to_handler)
+       /* make sure original return values are saved */
+       [--sp] = p0;
+       [--sp] = r0;
+       [--sp] = r1;
+
+       /* get original return address */
+       call _ftrace_return_to_handler;
+       rets = r0;
+
+       /* anomaly 05000371 - make sure we have at least three instructions
+        * between rets setting and the return
+        */
+       r1 = [sp++];
+       r0 = [sp++];
+       p0 = [sp++];
+       rts;
+ENDPROC(_return_to_handler)
+#endif
diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c
new file mode 100644 (file)
index 0000000..905bfc4
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * ftrace graph code
+ *
+ * Copyright (C) 2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/ftrace.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/atomic.h>
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in current thread info.
+ */
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
+{
+       struct ftrace_graph_ent trace;
+       unsigned long return_hooker = (unsigned long)&return_to_handler;
+
+       if (unlikely(atomic_read(&current->tracing_graph_pause)))
+               return;
+
+       if (ftrace_push_return_trace(*parent, self_addr, &trace.depth) == -EBUSY)
+               return;
+
+       trace.func = self_addr;
+
+       /* Only trace if the calling function expects to */
+       if (!ftrace_graph_entry(&trace)) {
+               current->curr_ret_stack--;
+               return;
+       }
+
+       /* all is well in the world !  hijack RETS ... */
+       *parent = return_hooker;
+}
+
+#endif
index 5fc424803a1788409a3b51d479c242d9ee16b6ae..d8cde1fc5cb937f9540485b70754e5b8a871fee3 100644 (file)
@@ -99,7 +99,7 @@ void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs)
         * interrupt.
         */
        m_ack = (regs == NULL || irq == IRQ_SYSTMR || irq == IRQ_CORETMR);
-       this_domain = ipipe_current_domain;
+       this_domain = __ipipe_current_domain;
 
        if (unlikely(test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control)))
                head = &this_domain->p_link;
@@ -212,7 +212,9 @@ void __ipipe_unstall_root_raw(void)
 
 int __ipipe_syscall_root(struct pt_regs *regs)
 {
+       struct ipipe_percpu_domain_data *p;
        unsigned long flags;
+       int ret;
 
        /*
         * We need to run the IRQ tail hook whenever we don't
@@ -231,29 +233,31 @@ int __ipipe_syscall_root(struct pt_regs *regs)
        /*
         * This routine either returns:
         * 0 -- if the syscall is to be passed to Linux;
-        * 1 -- if the syscall should not be passed to Linux, and no
+        * >0 -- if the syscall should not be passed to Linux, and no
         * tail work should be performed;
-        * -1 -- if the syscall should not be passed to Linux but the
+        * <0 -- if the syscall should not be passed to Linux but the
         * tail work has to be performed (for handling signals etc).
         */
 
-       if (__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL) &&
-           __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs) > 0) {
-               if (ipipe_root_domain_p && !in_atomic()) {
-                       /*
-                        * Sync pending VIRQs before _TIF_NEED_RESCHED
-                        * is tested.
-                        */
-                       local_irq_save_hw(flags);
-                       if ((ipipe_root_cpudom_var(irqpend_himask) & IPIPE_IRQMASK_VIRT) != 0)
-                               __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
-                       local_irq_restore_hw(flags);
-                       return -1;
-               }
+       if (!__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL))
+               return 0;
+
+       ret = __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs);
+
+       local_irq_save_hw(flags);
+
+       if (!__ipipe_root_domain_p) {
+               local_irq_restore_hw(flags);
                return 1;
        }
 
-       return 0;
+       p = ipipe_root_cpudom_ptr();
+       if ((p->irqpend_himask & IPIPE_IRQMASK_VIRT) != 0)
+               __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
+
+       local_irq_restore_hw(flags);
+
+       return -ret;
 }
 
 unsigned long ipipe_critical_enter(void (*syncfn) (void))
@@ -329,9 +333,7 @@ asmlinkage void __ipipe_sync_root(void)
 
 void ___ipipe_sync_pipeline(unsigned long syncmask)
 {
-       struct ipipe_domain *ipd = ipipe_current_domain;
-
-       if (ipd == ipipe_root_domain) {
+       if (__ipipe_root_domain_p) {
                if (test_bit(IPIPE_SYNCDEFER_FLAG, &ipipe_root_cpudom_var(status)))
                        return;
        }
index 80447f99c2b5f43cb0af2662e8e3717e214ab3e3..6454babdfaff571f7a04cab973f1d377b6041460 100644 (file)
@@ -1098,7 +1098,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                        CPUID, bfin_cpuid());
 
        seq_printf(m, "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n"
-               "stepping\t: %d\n",
+               "stepping\t: %d ",
                cpu, cclk/1000000, sclk/1000000,
 #ifdef CONFIG_MPU
                "mpu on",
@@ -1107,7 +1107,16 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 #endif
                revid);
 
-       seq_printf(m, "cpu MHz\t\t: %lu.%03lu/%lu.%03lu\n",
+       if (bfin_revid() != bfin_compiled_revid()) {
+               if (bfin_compiled_revid() == -1)
+                       seq_printf(m, "(Compiled for Rev none)");
+               else if (bfin_compiled_revid() == 0xffff)
+                       seq_printf(m, "(Compiled for Rev any)");
+               else
+                       seq_printf(m, "(Compiled for Rev %d)", bfin_compiled_revid());
+       }
+
+       seq_printf(m, "\ncpu MHz\t\t: %lu.%03lu/%lu.%03lu\n",
                cclk/1000000, cclk%1000000,
                sclk/1000000, sclk%1000000);
        seq_printf(m, "bogomips\t: %lu.%02lu\n"
@@ -1172,6 +1181,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 #ifdef __ARCH_SYNC_CORE_DCACHE
        seq_printf(m, "SMP Dcache Flushes\t: %lu\n\n", cpudata->dcache_invld_count);
 #endif
+#ifdef __ARCH_SYNC_CORE_ICACHE
+       seq_printf(m, "SMP Icache Flushes\t: %lu\n\n", cpudata->icache_invld_count);
+#endif
 #ifdef CONFIG_BFIN_ICACHE_LOCK
        switch ((cpudata->imemctl >> 3) & WAYALL_L) {
        case WAY0_L:
diff --git a/arch/blackfin/kernel/stacktrace.c b/arch/blackfin/kernel/stacktrace.c
new file mode 100644 (file)
index 0000000..30301e1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Blackfin stacktrace code (mostly copied from avr32)
+ *
+ * Copyright 2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/thread_info.h>
+#include <linux/module.h>
+
+register unsigned long current_frame_pointer asm("FP");
+
+struct stackframe {
+       unsigned long fp;
+       unsigned long rets;
+};
+
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+ */
+void save_stack_trace(struct stack_trace *trace)
+{
+       unsigned long low, high;
+       unsigned long fp;
+       struct stackframe *frame;
+       int skip = trace->skip;
+
+       low = (unsigned long)task_stack_page(current);
+       high = low + THREAD_SIZE;
+       fp = current_frame_pointer;
+
+       while (fp >= low && fp <= (high - sizeof(*frame))) {
+               frame = (struct stackframe *)fp;
+
+               if (skip) {
+                       skip--;
+               } else {
+                       trace->entries[trace->nr_entries++] = frame->rets;
+                       if (trace->nr_entries >= trace->max_entries)
+                               break;
+               }
+
+               /*
+                * The next frame must be at a higher address than the
+                * current frame.
+                */
+               low = fp + sizeof(*frame);
+               fp = frame->fp;
+       }
+}
+EXPORT_SYMBOL_GPL(save_stack_trace);
index aa76dfb0226ecd6dcf03136c463eb2969ac78f4b..d279552fe9b01633738880454872ce4e581dc03f 100644 (file)
@@ -27,6 +27,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <linux/bug.h>
 #include <linux/uaccess.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
@@ -238,6 +239,11 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
 
 }
 
+static int kernel_mode_regs(struct pt_regs *regs)
+{
+       return regs->ipend & 0xffc0;
+}
+
 asmlinkage void trap_c(struct pt_regs *fp)
 {
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
@@ -246,6 +252,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
        unsigned int cpu = smp_processor_id();
 #endif
+       const char *strerror = NULL;
        int sig = 0;
        siginfo_t info;
        unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
@@ -259,27 +266,10 @@ asmlinkage void trap_c(struct pt_regs *fp)
         * double faults if the stack has become corrupt
         */
 
-       /* If the fault was caused by a kernel thread, or interrupt handler
-        * we will kernel panic, so the system reboots.
-        * If KGDB is enabled, don't set this for kernel breakpoints
-       */
-
-       /* TODO: check to see if we are in some sort of deferred HWERR
-        * that we should be able to recover from, not kernel panic
-        */
-       if ((bfin_read_IPEND() & 0xFFC0) && (trapnr != VEC_STEP)
-#ifdef CONFIG_KGDB
-               && (trapnr != VEC_EXCPT02)
+#ifndef CONFIG_KGDB
+       /* IPEND is skipped if KGDB isn't enabled (see entry code) */
+       fp->ipend = bfin_read_IPEND();
 #endif
-       ){
-               console_verbose();
-               oops_in_progress = 1;
-       } else if (current) {
-               if (current->mm == NULL) {
-                       console_verbose();
-                       oops_in_progress = 1;
-               }
-       }
 
        /* trap_c() will be called for exceptions. During exceptions
         * processing, the pc value should be set with retx value.
@@ -307,15 +297,15 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGTRAP;
                CHK_DEBUGGER_TRAP_MAYBE();
                /* Check if this is a breakpoint in kernel space */
-               if (fp->ipend & 0xffc0)
-                       return;
+               if (kernel_mode_regs(fp))
+                       goto traps_done;
                else
                        break;
        /* 0x03 - User Defined, userspace stack overflow */
        case VEC_EXCPT03:
                info.si_code = SEGV_STACKFLOW;
                sig = SIGSEGV;
-               verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x03(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x02 - KGDB initial connection and break signal trap */
@@ -324,7 +314,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
                info.si_code = TRAP_ILLTRAP;
                sig = SIGTRAP;
                CHK_DEBUGGER_TRAP();
-               return;
+               goto traps_done;
 #endif
        /* 0x04 - User Defined */
        /* 0x05 - User Defined */
@@ -344,7 +334,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_EXCPT04 ... VEC_EXCPT15:
                info.si_code = ILL_ILLPARAOP;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x04(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x10 HW Single step, handled here */
@@ -353,15 +343,15 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGTRAP;
                CHK_DEBUGGER_TRAP_MAYBE();
                /* Check if this is a single step in kernel space */
-               if (fp->ipend & 0xffc0)
-                       return;
+               if (kernel_mode_regs(fp))
+                       goto traps_done;
                else
                        break;
        /* 0x11 - Trace Buffer Full, handled here */
        case VEC_OVFLOW:
                info.si_code = TRAP_TRACEFLOW;
                sig = SIGTRAP;
-               verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x11(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x12 - Reserved, Caught by default */
@@ -381,37 +371,54 @@ asmlinkage void trap_c(struct pt_regs *fp)
        /* 0x20 - Reserved, Caught by default */
        /* 0x21 - Undefined Instruction, handled here */
        case VEC_UNDEF_I:
+#ifdef CONFIG_BUG
+               if (kernel_mode_regs(fp)) {
+                       switch (report_bug(fp->pc, fp)) {
+                       case BUG_TRAP_TYPE_NONE:
+                               break;
+                       case BUG_TRAP_TYPE_WARN:
+                               dump_bfin_trace_buffer();
+                               fp->pc += 2;
+                               goto traps_done;
+                       case BUG_TRAP_TYPE_BUG:
+                               /* call to panic() will dump trace, and it is
+                                * off at this point, so it won't be clobbered
+                                */
+                               panic("BUG()");
+                       }
+               }
+#endif
                info.si_code = ILL_ILLOPC;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x21(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x22 - Illegal Instruction Combination, handled here */
        case VEC_ILGAL_I:
                info.si_code = ILL_ILLPARAOP;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x22(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x23 - Data CPLB protection violation, handled here */
        case VEC_CPLB_VL:
                info.si_code = ILL_CPLB_VI;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x23(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x24 - Data access misaligned, handled here */
        case VEC_MISALI_D:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x24(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x25 - Unrecoverable Event, handled here */
        case VEC_UNCOV:
                info.si_code = ILL_ILLEXCPT;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x25(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
@@ -419,7 +426,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_CPLB_M:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x26(KERN_NOTICE);
                break;
        /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
        case VEC_CPLB_MHIT:
@@ -427,10 +434,10 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGSEGV;
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
                if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START)
-                       verbose_printk(KERN_NOTICE "NULL pointer access\n");
+                       strerror = KERN_NOTICE "NULL pointer access\n";
                else
 #endif
-                       verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
+                       strerror = KERN_NOTICE EXC_0x27(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x28 - Emulation Watchpoint, handled here */
@@ -440,8 +447,8 @@ asmlinkage void trap_c(struct pt_regs *fp)
                pr_debug(EXC_0x28(KERN_DEBUG));
                CHK_DEBUGGER_TRAP_MAYBE();
                /* Check if this is a watchpoint in kernel space */
-               if (fp->ipend & 0xffc0)
-                       return;
+               if (kernel_mode_regs(fp))
+                       goto traps_done;
                else
                        break;
 #ifdef CONFIG_BF535
@@ -449,7 +456,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_ISTRU_VL:      /* ADSP-BF535 only (MH) */
                info.si_code = BUS_OPFETCH;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
+               strerror = KERN_NOTICE "BF535: VEC_ISTRU_VL\n";
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
 #else
@@ -459,21 +466,21 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_MISALI_I:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2A(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2B - Instruction CPLB protection violation, handled here */
        case VEC_CPLB_I_VL:
                info.si_code = ILL_CPLB_VI;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2B(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
        case VEC_CPLB_I_M:
                info.si_code = ILL_CPLB_MISS;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2C(KERN_NOTICE);
                break;
        /* 0x2D - Instruction CPLB Multiple Hits, handled here */
        case VEC_CPLB_I_MHIT:
@@ -481,17 +488,17 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGSEGV;
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
                if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START)
-                       verbose_printk(KERN_NOTICE "Jump to NULL address\n");
+                       strerror = KERN_NOTICE "Jump to NULL address\n";
                else
 #endif
-                       verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
+                       strerror = KERN_NOTICE EXC_0x2D(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2E - Illegal use of Supervisor Resource, handled here */
        case VEC_ILL_RES:
                info.si_code = ILL_PRVOPC;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2E(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2F - Reserved, Caught by default */
@@ -519,17 +526,17 @@ asmlinkage void trap_c(struct pt_regs *fp)
                case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
                        info.si_code = BUS_ADRALN;
                        sig = SIGBUS;
-                       verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
+                       strerror = KERN_NOTICE HWC_x2(KERN_NOTICE);
                        break;
                /* External Memory Addressing Error */
                case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
                        info.si_code = BUS_ADRERR;
                        sig = SIGBUS;
-                       verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
+                       strerror = KERN_NOTICE HWC_x3(KERN_NOTICE);
                        break;
                /* Performance Monitor Overflow */
                case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
-                       verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
+                       strerror = KERN_NOTICE HWC_x12(KERN_NOTICE);
                        break;
                /* RAISE 5 instruction */
                case (SEQSTAT_HWERRCAUSE_RAISE_5):
@@ -546,7 +553,6 @@ asmlinkage void trap_c(struct pt_regs *fp)
         * if we get here we hit a reserved one, so panic
         */
        default:
-               oops_in_progress = 1;
                info.si_code = ILL_ILLPARAOP;
                sig = SIGILL;
                verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
@@ -557,6 +563,16 @@ asmlinkage void trap_c(struct pt_regs *fp)
 
        BUG_ON(sig == 0);
 
+       /* If the fault was caused by a kernel thread, or interrupt handler
+        * we will kernel panic, so the system reboots.
+        */
+       if (kernel_mode_regs(fp) || (current && !current->mm)) {
+               console_verbose();
+               oops_in_progress = 1;
+               if (strerror)
+                       verbose_printk(strerror);
+       }
+
        if (sig != SIGTRAP) {
                dump_bfin_process(fp);
                dump_bfin_mem(fp);
@@ -606,8 +622,8 @@ asmlinkage void trap_c(struct pt_regs *fp)
        if (ANOMALY_05000461 && trapnr == VEC_HWERR && !access_ok(VERIFY_READ, fp->pc, 8))
                fp->pc = SAFE_USER_INSTRUCTION;
 
+ traps_done:
        trace_buffer_restore(j);
-       return;
 }
 
 /* Typical exception handling routines */
@@ -792,6 +808,18 @@ void dump_bfin_trace_buffer(void)
 }
 EXPORT_SYMBOL(dump_bfin_trace_buffer);
 
+#ifdef CONFIG_BUG
+int is_valid_bugaddr(unsigned long addr)
+{
+       unsigned short opcode;
+
+       if (!get_instruction(&opcode, (unsigned short *)addr))
+               return 0;
+
+       return opcode == BFIN_BUG_OPCODE;
+}
+#endif
+
 /*
  * Checks to see if the address pointed to is either a
  * 16-bit CALL instruction, or a 32-bit CALL instruction
index 8b67167cb4f4cdeac39c465c0be0a5ba4f52711e..6ac307ca0d805a7487d1990b59978bcf9f834ec1 100644 (file)
@@ -54,6 +54,7 @@ SECTIONS
                SCHED_TEXT
 #endif
                LOCK_TEXT
+               IRQENTRY_TEXT
                KPROBES_TEXT
                *(.text.*)
                *(.fixup)
@@ -166,6 +167,20 @@ SECTIONS
        }
        PERCPU(4)
        SECURITY_INIT
+
+       /* we have to discard exit text and such at runtime, not link time, to
+        * handle embedded cross-section references (alt instructions, bug
+        * table, eh_frame, etc...)
+        */
+       .exit.text :
+       {
+               EXIT_TEXT
+       }
+       .exit.data :
+       {
+               EXIT_DATA
+       }
+
        .init.ramfs :
        {
                . = ALIGN(4);
@@ -264,8 +279,6 @@ SECTIONS
 
        /DISCARD/ :
        {
-               EXIT_TEXT
-               EXIT_DATA
                *(.exitcall.exit)
        }
 }
index 762a7f02970ac0508ce99f3de9d1dd6d9432bc20..cd605e7d8518c43ce400cb3ab9be75e4b3c26244 100644 (file)
@@ -116,6 +116,7 @@ __sum16 ip_compute_csum(const void *buff, int len)
 {
        return (__force __sum16)~do_csum(buff, len);
 }
+EXPORT_SYMBOL(ip_compute_csum);
 
 /*
  * copy from fs while checksumming, otherwise like csum_partial
@@ -130,6 +131,7 @@ csum_partial_copy_from_user(const void __user *src, void *dst,
        memcpy(dst, (__force void *)src, len);
        return csum_partial(dst, len, sum);
 }
+EXPORT_SYMBOL(csum_partial_copy_from_user);
 
 /*
  * copy from ds while checksumming, otherwise like csum_partial
index 62bba09bcce689dfe908b5b702e76fb20877921f..1382f0382359a1dc44b743b900d285abedb537dd 100644 (file)
@@ -246,7 +246,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .modalias = "m25p80", /* Name of spi_driver for this device */
                .max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
                .bus_num = 0, /* Framework bus number */
-               .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+               .chip_select = 2, /* On BF518F-EZBRD it's SPI0_SSEL2 */
                .platform_data = &bfin_spi_flash_data,
                .controller_data = &spi_flash_chip_info,
                .mode = SPI_MODE_3,
@@ -369,6 +369,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI0,
                .end   = CH_SPI0,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
                .flags = IORESOURCE_IRQ,
        },
 };
@@ -399,6 +404,11 @@ static struct resource bfin_spi1_resource[] = {
        [1] = {
                .start = CH_SPI1,
                .end   = CH_SPI1,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
                .flags = IORESOURCE_IRQ,
        },
 };
index 6d6f9effa0bb8e36f38f99ba9f7a8cfdb6798b16..1eaf27ff722ebf878880c2278970c8a3d6a8002b 100644 (file)
@@ -664,6 +664,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        },
 };
index 1435c5d38cd515127d5f6b16f60fc084f8c96287..9f9c0005dcf12a7fc3b19d155ff5e4db62ef4b15 100644 (file)
@@ -467,6 +467,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        },
 };
index 147edd1eb1ad44f52850a8d9977a36dbbfd5aab0..3e5b7db6b0658d2a629c154bdc35f0905839578c 100644 (file)
@@ -723,6 +723,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        },
 };
index 895f213ea454d11038c536a5c0e9645093e6ea51..38cf8ffd6d74ac68a14d723f739ecf78aa92b60d 100644 (file)
@@ -266,6 +266,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index 0765872a8ada70a9114bfc98266ad7798e384ca9..9ecdc361fa6d56f299555fa28fb7b04298c81211 100644 (file)
@@ -162,6 +162,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index a727e538fa2857e128baa6d9b61a73f0c06b8eb0..1443e92d8b6241e56138fc08a82e5c5b28eb6c24 100644 (file)
@@ -160,6 +160,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index 842f1c9c239336e684bc2f7fd7ad0d733a27ffb7..89a5ec4ca048ad6b6716e5791bdd70783949c783 100644 (file)
@@ -196,6 +196,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index e19c565ade160e4639c4f17bddf4c4e13c17c225..a68ade8a3ca2a876c721c030efa84dfa01087d0d 100644 (file)
@@ -299,6 +299,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index 4fee196731279f5eb86a794be4894d6eefb114db..2a87d1cfcd06661f6d7307cd7d8e07362033a0fd 100644 (file)
@@ -182,8 +182,13 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
-       }
+       },
 };
 
 /* SPI controller data */
index 3c159819e5550ee178d93cf33a2a4efbbeacd6c2..399f81da7b933f5a189a3aef59e4f4ece80f7d5c 100644 (file)
@@ -184,6 +184,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        },
 };
index 26707ce39f29b98666593b011deb89c8912e5ede..838240f151f5b79dc26e88152e9b7cc54fd9bde7 100644 (file)
@@ -398,8 +398,13 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
-       }
+       },
 };
 
 /* SPI controller data */
index dfb5036f8a6b2d8dacdb414227f010196b830e39..ff7228caa7da042b537f81242e6cf822a6436969 100644 (file)
@@ -1345,7 +1345,7 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
 #if defined(CONFIG_PMIC_ADP5520) || defined(CONFIG_PMIC_ADP5520_MODULE)
        {
                I2C_BOARD_INFO("pmic-adp5520", 0x32),
-               .irq = IRQ_PF7,
+               .irq = IRQ_PG0,
                .platform_data = (void *)&adp5520_pdev_data,
        },
 #endif
index 280574591201e54b98b61d65513d6d92d79098a3..e523e6e610d0b04f98b45aa4f049ea36f78053ac 100644 (file)
@@ -182,6 +182,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index e37cb937888422128cd4f987ac36b517966d6b56..57695b4c3c0964c60413da1b7c55e889059282ae 100644 (file)
@@ -352,6 +352,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI0,
                .end   = CH_SPI0,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
                .flags = IORESOURCE_IRQ,
        }
 };
@@ -366,6 +371,11 @@ static struct resource bfin_spi1_resource[] = {
        [1] = {
                .start = CH_SPI1,
                .end   = CH_SPI1,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
                .flags = IORESOURCE_IRQ,
        }
 };
index f53ad682530b9849c0f20504cf6d4d66ccaa82ff..f5a3c30a41bd299d5c1899b4e18564309deab658 100644 (file)
@@ -612,6 +612,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI0,
                .end   = CH_SPI0,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
                .flags = IORESOURCE_IRQ,
        }
 };
@@ -626,6 +631,11 @@ static struct resource bfin_spi1_resource[] = {
        [1] = {
                .start = CH_SPI1,
                .end   = CH_SPI1,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
                .flags = IORESOURCE_IRQ,
        }
 };
index add5a17452cec8010bf3386de428a6d47ce3af1e..805a57b5e6501b6d850d85d58ea831c84b2ab413 100644 (file)
@@ -396,6 +396,8 @@ static struct platform_device bfin_sir3_device = {
 #endif
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+#include <linux/smsc911x.h>
+
 static struct resource smsc911x_resources[] = {
        {
                .name = "smsc911x-memory",
@@ -409,11 +411,22 @@ static struct resource smsc911x_resources[] = {
                .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
        },
 };
+
+static struct smsc911x_platform_config smsc911x_config = {
+       .flags = SMSC911X_USE_32BIT,
+       .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .phy_interface = PHY_INTERFACE_MODE_MII,
+};
+
 static struct platform_device smsc911x_device = {
        .name = "smsc911x",
        .id = 0,
        .num_resources = ARRAY_SIZE(smsc911x_resources),
        .resource = smsc911x_resources,
+       .dev = {
+               .platform_data = &smsc911x_config,
+       },
 };
 #endif
 
@@ -741,6 +754,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI0,
                .end   = CH_SPI0,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
                .flags = IORESOURCE_IRQ,
        }
 };
@@ -755,6 +773,11 @@ static struct resource bfin_spi1_resource[] = {
        [1] = {
                .start = CH_SPI1,
                .end   = CH_SPI1,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
                .flags = IORESOURCE_IRQ,
        }
 };
index 0dd9685e5d53f967e9e76a3aea1a317f983c8911..0c9d72c5f5babdef3fab2e5cdb9e87eced038b04 100644 (file)
@@ -177,8 +177,13 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
-       }
+       },
 };
 
 /* SPI controller data */
index 0e2178a1aec501023cd3051f18d8cc75346aa133..b5ef7ff7b7bdca0284f41624509e893a5d254f40 100644 (file)
@@ -304,6 +304,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index e6ab1f815123b62e6269f335294ea76378fd530c..b59ce3cb380718a5030e9ce99e154ad5e9bd54db 100644 (file)
 void blackfin_invalidate_entire_dcache(void)
 {
        u32 dmem = bfin_read_DMEM_CONTROL();
-       SSYNC();
        bfin_write_DMEM_CONTROL(dmem & ~0xc);
        SSYNC();
        bfin_write_DMEM_CONTROL(dmem);
        SSYNC();
 }
+
+/* Invalidate the Entire Instruction cache by
+ * clearing IMC bit
+ */
+void blackfin_invalidate_entire_icache(void)
+{
+       u32 imem = bfin_read_IMEM_CONTROL();
+       bfin_write_IMEM_CONTROL(imem & ~0x4);
+       SSYNC();
+       bfin_write_IMEM_CONTROL(imem);
+       SSYNC();
+}
+
index da0558ad1b1a7495764d2b375de4de409e7df992..31fa313e81cf0c42c51ff8524f1e32a692bf17b2 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/thread_info.h>  /* TIF_NEED_RESCHED */
 #include <asm/asm-offsets.h>
 #include <asm/trace.h>
+#include <asm/traps.h>
 
 #include <asm/context.S>
 
@@ -84,13 +85,15 @@ ENTRY(_ex_workaround_261)
        if !cc jump _bfin_return_from_exception;
        /* fall through */
        R7 = P4;
-       R6 = 0x26;      /* Data CPLB Miss */
+       R6 = VEC_CPLB_M;        /* Data CPLB Miss */
        cc = R6 == R7;
        if cc jump _ex_dcplb_miss (BP);
-       R6 = 0x23;      /* Data CPLB Miss */
+#ifdef CONFIG_MPU
+       R6 = VEC_CPLB_VL;       /* Data CPLB Violation */
        cc = R6 == R7;
        if cc jump _ex_dcplb_viol (BP);
-       /* Handle 0x23 Data CPLB Protection Violation
+#endif
+       /* Handle Data CPLB Protection Violation
         * and Data CPLB Multiple Hits - Linux Trap Zero
         */
        jump _ex_trap_c;
@@ -270,7 +273,7 @@ ENTRY(_bfin_return_from_exception)
        r6.l = lo(SEQSTAT_EXCAUSE);
        r6.h = hi(SEQSTAT_EXCAUSE);
        r7 = r7 & r6;
-       r6 = 0x25;
+       r6 = VEC_UNCOV;
        CC = R7 == R6;
        if CC JUMP _double_fault;
 #endif
@@ -1605,6 +1608,7 @@ ENTRY(_sys_call_table)
        .long _sys_inotify_init1        /* 365 */
        .long _sys_preadv
        .long _sys_pwritev
+       .long _sys_rt_tgsigqueueinfo
 
        .rept NR_syscalls-(.-_sys_call_table)/4
        .long _sys_ni_syscall
index 3b8ebaee77f2d1dd38adbaa5a2a6f0eac036a5db..61840059dfac30feb314fcf373f4ef51dea943cd 100644 (file)
@@ -144,7 +144,7 @@ static void ipi_call_function(unsigned int cpu, struct ipi_message *msg)
 
 static irqreturn_t ipi_handler(int irq, void *dev_instance)
 {
-       struct ipi_message *msg, *mg;
+       struct ipi_message *msg;
        struct ipi_message_queue *msg_queue;
        unsigned int cpu = smp_processor_id();
 
@@ -154,7 +154,8 @@ static irqreturn_t ipi_handler(int irq, void *dev_instance)
        msg_queue->count++;
 
        spin_lock(&msg_queue->lock);
-       list_for_each_entry_safe(msg, mg, &msg_queue->head, list) {
+       while (!list_empty(&msg_queue->head)) {
+               msg = list_entry(msg_queue->head.next, typeof(*msg), list);
                list_del(&msg->list);
                switch (msg->type) {
                case BFIN_IPI_RESCHEDULE:
@@ -221,7 +222,7 @@ int smp_call_function(void (*func)(void *info), void *info, int wait)
        for_each_cpu_mask(cpu, callmap) {
                msg_queue = &per_cpu(ipi_msg_queue, cpu);
                spin_lock_irqsave(&msg_queue->lock, flags);
-               list_add(&msg->list, &msg_queue->head);
+               list_add_tail(&msg->list, &msg_queue->head);
                spin_unlock_irqrestore(&msg_queue->lock, flags);
                platform_send_ipi_cpu(cpu);
        }
@@ -261,7 +262,7 @@ int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
 
        msg_queue = &per_cpu(ipi_msg_queue, cpu);
        spin_lock_irqsave(&msg_queue->lock, flags);
-       list_add(&msg->list, &msg_queue->head);
+       list_add_tail(&msg->list, &msg_queue->head);
        spin_unlock_irqrestore(&msg_queue->lock, flags);
        platform_send_ipi_cpu(cpu);
 
@@ -292,7 +293,7 @@ void smp_send_reschedule(int cpu)
 
        msg_queue = &per_cpu(ipi_msg_queue, cpu);
        spin_lock_irqsave(&msg_queue->lock, flags);
-       list_add(&msg->list, &msg_queue->head);
+       list_add_tail(&msg->list, &msg_queue->head);
        spin_unlock_irqrestore(&msg_queue->lock, flags);
        platform_send_ipi_cpu(cpu);
 
@@ -320,7 +321,7 @@ void smp_send_stop(void)
        for_each_cpu_mask(cpu, callmap) {
                msg_queue = &per_cpu(ipi_msg_queue, cpu);
                spin_lock_irqsave(&msg_queue->lock, flags);
-               list_add(&msg->list, &msg_queue->head);
+               list_add_tail(&msg->list, &msg_queue->head);
                spin_unlock_irqrestore(&msg_queue->lock, flags);
                platform_send_ipi_cpu(cpu);
        }
@@ -468,6 +469,17 @@ void smp_icache_flush_range_others(unsigned long start, unsigned long end)
 }
 EXPORT_SYMBOL_GPL(smp_icache_flush_range_others);
 
+#ifdef __ARCH_SYNC_CORE_ICACHE
+void resync_core_icache(void)
+{
+       unsigned int cpu = get_cpu();
+       blackfin_invalidate_entire_icache();
+       ++per_cpu(cpu_data, cpu).icache_invld_count;
+       put_cpu();
+}
+EXPORT_SYMBOL(resync_core_icache);
+#endif
+
 #ifdef __ARCH_SYNC_CORE_DCACHE
 unsigned long barrier_mask __attribute__ ((__section__(".l2.bss")));
 
index 783da855a2e34df9f9aa071287b236aec843faf0..d6d35b2e5fe877b303e90f498b326542aeed6a40 100644 (file)
@@ -963,7 +963,7 @@ CONFIG_EEPROM_LEGACY=y
 CONFIG_SENSORS_PCF8574=y
 # CONFIG_PCF8575 is not set
 CONFIG_SENSORS_PCF8591=y
-CONFIG_SENSORS_MAX6875=y
+CONFIG_EEPROM_MAX6875=y
 # CONFIG_SENSORS_TSL2550 is not set
 CONFIG_I2C_DEBUG_CORE=y
 CONFIG_I2C_DEBUG_ALGO=y
index 8426d3b9501ca1aefb5cb31f37e6f22e3e553de0..fadb351d249bbfdc2fc0291ba44b27b4ab2c5afe 100644 (file)
@@ -1849,7 +1849,7 @@ CONFIG_EEPROM_LEGACY=m
 CONFIG_SENSORS_PCF8574=m
 CONFIG_SENSORS_PCA9539=m
 CONFIG_SENSORS_PCF8591=m
-CONFIG_SENSORS_MAX6875=m
+CONFIG_EEPROM_MAX6875=m
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
index 7396cd719900255c0379eda6b4d62dafe5fa8c6f..6827feb4de9671b7ef72201e55bff0abdffa6329 100644 (file)
@@ -38,7 +38,7 @@ int __init sni_eisa_root_init(void)
        if (!r)
                return r;
 
-       eisa_root_dev.dev.driver_data = &eisa_bus_root;
+       dev_set_drvdata(&eisa_root_dev.dev, &eisa_bus_root);
 
        if (eisa_root_register(&eisa_bus_root)) {
                /* A real bridge may have been registered before
index 93a61898b25936f5d0abeef302745f7ca25b91c3..9fb344d5a86a737e459c998d8e83a653ccf19501 100644 (file)
@@ -93,10 +93,6 @@ config GENERIC_HWEIGHT
        bool
        default y
 
-config GENERIC_CALIBRATE_DELAY
-       bool
-       default y
-
 config GENERIC_FIND_NEXT_BIT
        bool
        default y
@@ -129,6 +125,7 @@ config PPC
        select USE_GENERIC_SMP_HELPERS if SMP
        select HAVE_OPROFILE
        select HAVE_SYSCALL_WRAPPERS if PPC64
+       select GENERIC_ATOMIC64 if PPC32
 
 config EARLY_PRINTK
        bool
index 51b2387bdba0e82dfd8b75de48b56a18cd4fd2ef..98312d169c859926932356cd7018a57ffed23e9f 100644 (file)
@@ -18,6 +18,9 @@
 #   $5 and more - kernel boot files; zImage*, uImage, cuImage.*, etc.
 #
 
+# Bail with error code if anything goes wrong
+set -e
+
 # User may have a custom install script
 
 if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi
index 7d044dfd9236e55cdf1defd64760275285213e84..12dc7c40961632287270c473a37518236d1830b9 100644 (file)
@@ -1808,7 +1808,7 @@ CONFIG_PCF8575=m
 CONFIG_SENSORS_PCA9539=m
 CONFIG_SENSORS_PCF8591=m
 # CONFIG_TPS65010 is not set
-CONFIG_SENSORS_MAX6875=m
+CONFIG_EEPROM_MAX6875=m
 CONFIG_SENSORS_TSL2550=m
 CONFIG_MCU_MPC8349EMITX=m
 # CONFIG_I2C_DEBUG_CORE is not set
index b7d2d07b6f965f5a613c92b12ebaf23fd938c141..4012483b1899d32a84097bbbdb543c80f025f0d0 100644 (file)
@@ -470,6 +470,9 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 
+#else  /* __powerpc64__ */
+#include <asm-generic/atomic64.h>
+
 #endif /* __powerpc64__ */
 
 #include <asm-generic/atomic-long.h>
index 53512374e1c9daea22bd71d6d153b69d1b0e0d42..b7f8f4a87cc04cc882f1179414dd34c3e189c58f 100644 (file)
@@ -80,7 +80,7 @@ static inline void local_irq_disable(void)
        __asm__ __volatile__("wrteei 0": : :"memory");
 #else
        unsigned long msr;
-       __asm__ __volatile__("": : :"memory");
+
        msr = mfmsr();
        SET_MSR_EE(msr & ~MSR_EE);
 #endif
@@ -92,7 +92,7 @@ static inline void local_irq_enable(void)
        __asm__ __volatile__("wrteei 1": : :"memory");
 #else
        unsigned long msr;
-       __asm__ __volatile__("": : :"memory");
+
        msr = mfmsr();
        SET_MSR_EE(msr | MSR_EE);
 #endif
@@ -108,7 +108,6 @@ static inline void local_irq_save_ptr(unsigned long *flags)
 #else
        SET_MSR_EE(msr & ~MSR_EE);
 #endif
-       __asm__ __volatile__("": : :"memory");
 }
 
 #define local_save_flags(flags)        ((flags) = mfmsr())
index 7464c0daddd1d02f5f8f66d1df9a26f92bbc7783..7ead7c16fb7cdb563ee41f0146b16471bf700d7a 100644 (file)
 #define IOMMU_PAGE_MASK       (~((1 << IOMMU_PAGE_SHIFT) - 1))
 #define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE)
 
+/* Cell page table entries */
+#define CBE_IOPTE_PP_W         0x8000000000000000ul /* protection: write */
+#define CBE_IOPTE_PP_R         0x4000000000000000ul /* protection: read */
+#define CBE_IOPTE_M            0x2000000000000000ul /* coherency required */
+#define CBE_IOPTE_SO_R         0x1000000000000000ul /* ordering: writes */
+#define CBE_IOPTE_SO_RW                0x1800000000000000ul /* ordering: r & w */
+#define CBE_IOPTE_RPN_Mask     0x07fffffffffff000ul /* RPN */
+#define CBE_IOPTE_H            0x0000000000000800ul /* cache hint */
+#define CBE_IOPTE_IOID_Mask    0x00000000000007fful /* ioid */
+
 /* Boot time flags */
 extern int iommu_is_off;
 extern int iommu_force_on;
index cdb6fd814de8880541d2c4130b33ea7e7b9f6234..7f065e178ec463cc7ab648883cfa57c2a0f33928 100644 (file)
@@ -53,6 +53,13 @@ enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void);
 extern u64 ps3_os_area_get_rtc_diff(void);
 extern void ps3_os_area_set_rtc_diff(u64 rtc_diff);
 
+struct ps3_os_area_flash_ops {
+       ssize_t (*read)(void *buf, size_t count, loff_t pos);
+       ssize_t (*write)(const void *buf, size_t count, loff_t pos);
+};
+
+extern void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops);
+
 /* dma routines */
 
 enum ps3_dma_page_size {
@@ -418,15 +425,15 @@ static inline struct ps3_system_bus_driver *
  * @data: Data to set
  */
 
-static inline void ps3_system_bus_set_driver_data(
+static inline void ps3_system_bus_set_drvdata(
        struct ps3_system_bus_device *dev, void *data)
 {
-       dev->core.driver_data = data;
+       dev_set_drvdata(&dev->core, data);
 }
-static inline void *ps3_system_bus_get_driver_data(
+static inline void *ps3_system_bus_get_drvdata(
        struct ps3_system_bus_device *dev)
 {
-       return dev->core.driver_data;
+       return dev_get_drvdata(&dev->core);
 }
 
 /* These two need global scope for get_dma_ops(). */
@@ -520,7 +527,4 @@ void ps3_sync_irq(int node);
 u32 ps3_get_hw_thread_id(int cpu);
 u64 ps3_get_spe_id(void *arg);
 
-/* mutex synchronizing GPU accesses and video mode changes */
-extern struct mutex ps3_gpu_mutex;
-
 #endif
diff --git a/arch/powerpc/include/asm/ps3gpu.h b/arch/powerpc/include/asm/ps3gpu.h
new file mode 100644 (file)
index 0000000..b2b8959
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *  PS3 GPU declarations.
+ *
+ *  Copyright 2009 Sony Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.
+ *  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _ASM_POWERPC_PS3GPU_H
+#define _ASM_POWERPC_PS3GPU_H
+
+#include <linux/mutex.h>
+
+#include <asm/lv1call.h>
+
+
+#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC   0x101
+#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP   0x102
+
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP       0x600
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT                0x601
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC   0x602
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE       0x603
+
+#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION      (1ULL << 32)
+
+#define L1GPU_DISPLAY_SYNC_HSYNC               1
+#define L1GPU_DISPLAY_SYNC_VSYNC               2
+
+
+/* mutex synchronizing GPU accesses and video mode changes */
+extern struct mutex ps3_gpu_mutex;
+
+
+static inline int lv1_gpu_display_sync(u64 context_handle, u64 head,
+                                      u64 ddr_offset)
+{
+       return lv1_gpu_context_attribute(context_handle,
+                                        L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
+                                        head, ddr_offset, 0, 0);
+}
+
+static inline int lv1_gpu_display_flip(u64 context_handle, u64 head,
+                                      u64 ddr_offset)
+{
+       return lv1_gpu_context_attribute(context_handle,
+                                        L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
+                                        head, ddr_offset, 0, 0);
+}
+
+static inline int lv1_gpu_fb_setup(u64 context_handle, u64 xdr_lpar,
+                                  u64 xdr_size, u64 ioif_offset)
+{
+       return lv1_gpu_context_attribute(context_handle,
+                                        L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
+                                        xdr_lpar, xdr_size, ioif_offset, 0);
+}
+
+static inline int lv1_gpu_fb_blit(u64 context_handle, u64 ddr_offset,
+                                 u64 ioif_offset, u64 sync_width, u64 pitch)
+{
+       return lv1_gpu_context_attribute(context_handle,
+                                        L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
+                                        ddr_offset, ioif_offset, sync_width,
+                                        pitch);
+}
+
+static inline int lv1_gpu_fb_close(u64 context_handle)
+{
+       return lv1_gpu_context_attribute(context_handle,
+                                        L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE, 0,
+                                        0, 0, 0);
+}
+
+#endif /* _ASM_POWERPC_PS3GPU_H */
index fb359b0a6937de645c8101709ac4ade7fd9df446..a3c28e46947c7e30f3690c8cb00ee985090b1082 100644 (file)
                        asm volatile("mfmsr %0" : "=r" (rval)); rval;})
 #ifdef CONFIG_PPC64
 #define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \
-                                    : : "r" (v))
+                                    : : "r" (v) : "memory")
 #define mtmsrd(v)      __mtmsrd((v), 0)
 #define mtmsr(v)       mtmsrd(v)
 #else
-#define mtmsr(v)       asm volatile("mtmsr %0" : : "r" (v))
+#define mtmsr(v)       asm volatile("mtmsr %0" : : "r" (v) : "memory")
 #endif
 
 #define mfspr(rn)      ({unsigned long rval; \
index a0b92de51c7edfa594941f134de592c77eb49b3e..370600ca2765332ec542ff0c269aa3d5b614c9f0 100644 (file)
@@ -325,3 +325,4 @@ SYSCALL(inotify_init1)
 SYSCALL_SPU(perf_counter_open)
 COMPAT_SYS_SPU(preadv)
 COMPAT_SYS_SPU(pwritev)
+COMPAT_SYS(rt_tgsigqueueinfo)
index 4badac2d11d1a7f3c8989ffb5be20dd4cd131a57..cef080bfc607be937cd816bd9f3ac5cca443aaac 100644 (file)
 #define __NR_perf_counter_open 319
 #define __NR_preadv            320
 #define __NR_pwritev           321
+#define __NR_rt_tgsigqueueinfo 322
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls          322
+#define __NR_syscalls          323
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index a7def5f90cadbe2392b7ecfd6aa65f80570b1014..612b0c4dc26d90d818d299805a34c7b453eb09c3 100644 (file)
@@ -125,6 +125,7 @@ PHONY += systbl_chk
 systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i
        $(call cmd,systbl_chk)
 
+ifeq ($(CONFIG_PPC_OF_BOOT_TRAMPOLINE),y)
 $(obj)/built-in.o:             prom_init_check
 
 quiet_cmd_prom_init_check = CALL    $<
@@ -133,5 +134,6 @@ quiet_cmd_prom_init_check = CALL    $<
 PHONY += prom_init_check
 prom_init_check: $(src)/prom_init_check.sh $(obj)/prom_init.o
        $(call cmd,prom_init_check)
+endif
 
 clean-files := vmlinux.lds
index f46548e6604550ac45309c07932efcb5db08a818..1f6816003ebef9bebcbb3319e83bac2243437d47 100644 (file)
@@ -424,8 +424,8 @@ void __init setup_system(void)
        printk("htab_hash_mask                = 0x%lx\n", htab_hash_mask);
 #endif /* CONFIG_PPC_STD_MMU_64 */
        if (PHYSICAL_START > 0)
-               printk("physical_start                = 0x%lx\n",
-                      PHYSICAL_START);
+               printk("physical_start                = 0x%llx\n",
+                      (unsigned long long)PHYSICAL_START);
        printk("-----------------------------------------------------\n");
 
        DBG(" <- setup_system()\n");
index bee1443da7634d3cf9a062d9223a11d4a63540de..15391c2ab013bc0691228b97076d126fa5dc1aa1 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/jiffies.h>
 #include <linux/posix-timers.h>
 #include <linux/irq.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/processor.h>
@@ -1143,6 +1144,15 @@ void div128_by_32(u64 dividend_high, u64 dividend_low,
 
 }
 
+/* We don't need to calibrate delay, we use the CPU timebase for that */
+void calibrate_delay(void)
+{
+       /* Some generic code (such as spinlock debug) use loops_per_jiffy
+        * as the number of __delay(1) in a jiffy, so make it so
+        */
+       loops_per_jiffy = tb_ticks_per_jiffy;
+}
+
 static int __init rtc_init(void)
 {
        struct platform_device *pdev;
index 0ce45c2b42f8eb67a1ea5156fcf476bdb3f3924a..c71498dbf211780675293c205d258cd17350f987 100644 (file)
@@ -329,7 +329,7 @@ static struct irq_host_ops msic_host_ops = {
 
 static int axon_msi_shutdown(struct of_device *device)
 {
-       struct axon_msic *msic = device->dev.platform_data;
+       struct axon_msic *msic = dev_get_drvdata(&device->dev);
        u32 tmp;
 
        pr_debug("axon_msi: disabling %s\n",
@@ -416,7 +416,7 @@ static int axon_msi_probe(struct of_device *device,
        msic->read_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG)
                                & MSIC_FIFO_SIZE_MASK;
 
-       device->dev.platform_data = msic;
+       dev_set_drvdata(&device->dev, msic);
 
        ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
        ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
index bed4690de3944162eca2918e8df1164e1fd5b678..5b34fc211f35bb9b4f4ac5d3fdded3293f6c044c 100644 (file)
 #define IOSTE_PS_1M            0x0000000000000005ul /*   - 1MB  */
 #define IOSTE_PS_16M           0x0000000000000007ul /*   - 16MB */
 
-/* Page table entries */
-#define IOPTE_PP_W             0x8000000000000000ul /* protection: write */
-#define IOPTE_PP_R             0x4000000000000000ul /* protection: read */
-#define IOPTE_M                        0x2000000000000000ul /* coherency required */
-#define IOPTE_SO_R             0x1000000000000000ul /* ordering: writes */
-#define IOPTE_SO_RW             0x1800000000000000ul /* ordering: r & w */
-#define IOPTE_RPN_Mask         0x07fffffffffff000ul /* RPN */
-#define IOPTE_H                        0x0000000000000800ul /* cache hint */
-#define IOPTE_IOID_Mask                0x00000000000007fful /* ioid */
-
 
 /* IOMMU sizing */
 #define IO_SEGMENT_SHIFT       28
@@ -193,19 +183,21 @@ static int tce_build_cell(struct iommu_table *tbl, long index, long npages,
         */
        const unsigned long prot = 0xc48;
        base_pte =
-               ((prot << (52 + 4 * direction)) & (IOPTE_PP_W | IOPTE_PP_R))
-               | IOPTE_M | IOPTE_SO_RW | (window->ioid & IOPTE_IOID_Mask);
+               ((prot << (52 + 4 * direction)) &
+                (CBE_IOPTE_PP_W | CBE_IOPTE_PP_R)) |
+               CBE_IOPTE_M | CBE_IOPTE_SO_RW |
+               (window->ioid & CBE_IOPTE_IOID_Mask);
 #else
-       base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW |
-               (window->ioid & IOPTE_IOID_Mask);
+       base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M |
+               CBE_IOPTE_SO_RW | (window->ioid & CBE_IOPTE_IOID_Mask);
 #endif
        if (unlikely(dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)))
-               base_pte &= ~IOPTE_SO_RW;
+               base_pte &= ~CBE_IOPTE_SO_RW;
 
        io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
 
        for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE)
-               io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask);
+               io_pte[i] = base_pte | (__pa(uaddr) & CBE_IOPTE_RPN_Mask);
 
        mb();
 
@@ -231,8 +223,9 @@ static void tce_free_cell(struct iommu_table *tbl, long index, long npages)
 #else
        /* spider bridge does PCI reads after freeing - insert a mapping
         * to a scratch page instead of an invalid entry */
-       pte = IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | __pa(window->iommu->pad_page)
-               | (window->ioid & IOPTE_IOID_Mask);
+       pte = CBE_IOPTE_PP_R | CBE_IOPTE_M | CBE_IOPTE_SO_RW |
+               __pa(window->iommu->pad_page) |
+               (window->ioid & CBE_IOPTE_IOID_Mask);
 #endif
 
        io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
@@ -1001,7 +994,7 @@ static void insert_16M_pte(unsigned long addr, unsigned long *ptab,
        pr_debug("iommu: addr %lx ptab %p segment %lx offset %lx\n",
                  addr, ptab, segment, offset);
 
-       ptab[offset] = base_pte | (__pa(addr) & IOPTE_RPN_Mask);
+       ptab[offset] = base_pte | (__pa(addr) & CBE_IOPTE_RPN_Mask);
 }
 
 static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
@@ -1016,14 +1009,14 @@ static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
 
        pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase);
 
-       base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M
-                   | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask);
+       base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M |
+               (cell_iommu_get_ioid(np) & CBE_IOPTE_IOID_Mask);
 
        if (iommu_fixed_is_weak)
                pr_info("IOMMU: Using weak ordering for fixed mapping\n");
        else {
                pr_info("IOMMU: Using strong ordering for fixed mapping\n");
-               base_pte |= IOPTE_SO_RW;
+               base_pte |= CBE_IOPTE_SO_RW;
        }
 
        for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) {
index 4543c4bc3a56e158cb47a3387d97c715dabc515e..c5a87a72057b42b700fe1a514795185e12b31f80 100644 (file)
@@ -204,7 +204,8 @@ static void __init dt_prop_u32(struct iseries_flat_dt *dt, const char *name,
        dt_prop(dt, name, &data, sizeof(u32));
 }
 
-static void __init dt_prop_u64(struct iseries_flat_dt *dt, const char *name,
+static void __init __maybe_unused dt_prop_u64(struct iseries_flat_dt *dt,
+                                             const char *name,
                u64 data)
 {
        dt_prop(dt, name, &data, sizeof(u64));
index 3689c2413d24d758faf9bd9bda5c41400d1b6b71..fef4d5150517474460aa5c97bea5efb5c32254f9 100644 (file)
@@ -267,7 +267,8 @@ static struct pending_event *new_pending_event(void)
        return ev;
 }
 
-static int signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
+static int __maybe_unused
+signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
 {
        struct pending_event *ev = new_pending_event();
        int rc;
index 9a2b6d948610c003485e38ded9e561f6514760fa..846eb8b57fd1dbb80fca175bb2813e97f0e7ef49 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/lmb.h>
 
 #include <asm/firmware.h>
+#include <asm/iommu.h>
 #include <asm/prom.h>
 #include <asm/udbg.h>
 #include <asm/lv1call.h>
@@ -605,9 +606,8 @@ static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
                                       r->ioid,
                                       iopte_flag);
                if (result) {
-                       printk(KERN_WARNING "%s:%d: lv1_map_device_dma_region "
-                               "failed: %s\n", __func__, __LINE__,
-                               ps3_result(result));
+                       pr_warning("%s:%d: lv1_put_iopte failed: %s\n",
+                                  __func__, __LINE__, ps3_result(result));
                        goto fail_map;
                }
                DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__,
@@ -1001,7 +1001,8 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r)
                if (len > r->len)
                        len = r->len;
                result = dma_sb_map_area(r, virt_addr, len, &tmp,
-                       IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
+                       CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_SO_RW |
+                       CBE_IOPTE_M);
                BUG_ON(result);
        }
 
@@ -1014,7 +1015,8 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r)
                else
                        len -= map.rm.size - r->offset;
                result = dma_sb_map_area(r, virt_addr, len, &tmp,
-                       IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
+                       CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_SO_RW |
+                       CBE_IOPTE_M);
                BUG_ON(result);
        }
 
index cf1cd0f8c18f9dca3b9917cc509dbc2179119b67..d6487a9c801900d3aa9ee9db65a245f44f26f702 100644 (file)
@@ -226,6 +226,44 @@ static struct property property_av_multi_out = {
        .value = &saved_params.av_multi_out,
 };
 
+
+static DEFINE_MUTEX(os_area_flash_mutex);
+
+static const struct ps3_os_area_flash_ops *os_area_flash_ops;
+
+void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops)
+{
+       mutex_lock(&os_area_flash_mutex);
+       os_area_flash_ops = ops;
+       mutex_unlock(&os_area_flash_mutex);
+}
+EXPORT_SYMBOL_GPL(ps3_os_area_flash_register);
+
+static ssize_t os_area_flash_read(void *buf, size_t count, loff_t pos)
+{
+       ssize_t res = -ENODEV;
+
+       mutex_lock(&os_area_flash_mutex);
+       if (os_area_flash_ops)
+               res = os_area_flash_ops->read(buf, count, pos);
+       mutex_unlock(&os_area_flash_mutex);
+
+       return res;
+}
+
+static ssize_t os_area_flash_write(const void *buf, size_t count, loff_t pos)
+{
+       ssize_t res = -ENODEV;
+
+       mutex_lock(&os_area_flash_mutex);
+       if (os_area_flash_ops)
+               res = os_area_flash_ops->write(buf, count, pos);
+       mutex_unlock(&os_area_flash_mutex);
+
+       return res;
+}
+
+
 /**
  * os_area_set_property - Add or overwrite a saved_params value to the device tree.
  *
@@ -352,12 +390,12 @@ static int db_verify(const struct os_area_db *db)
        if (memcmp(db->magic_num, OS_AREA_DB_MAGIC_NUM,
                sizeof(db->magic_num))) {
                pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
-               return -1;
+               return -EINVAL;
        }
 
        if (db->version != 1) {
                pr_debug("%s:%d version failed\n", __func__, __LINE__);
-               return -1;
+               return -EINVAL;
        }
 
        return 0;
@@ -578,59 +616,48 @@ static void os_area_db_init(struct os_area_db *db)
  *
  */
 
-static void __maybe_unused update_flash_db(void)
+static int update_flash_db(void)
 {
-       int result;
-       int file;
-       off_t offset;
+       const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
+       struct os_area_header *header;
        ssize_t count;
-       static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
-       const struct os_area_header *header;
+       int error;
+       loff_t pos;
        struct os_area_db* db;
 
        /* Read in header and db from flash. */
 
-       file = sys_open("/dev/ps3flash", O_RDWR, 0);
-
-       if (file < 0) {
-               pr_debug("%s:%d sys_open failed\n", __func__, __LINE__);
-               goto fail_open;
-       }
-
        header = kmalloc(buf_len, GFP_KERNEL);
-
        if (!header) {
-               pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__);
-               goto fail_malloc;
+               pr_debug("%s: kmalloc failed\n", __func__);
+               return -ENOMEM;
        }
 
-       offset = sys_lseek(file, 0, SEEK_SET);
-
-       if (offset != 0) {
-               pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
-               goto fail_header_seek;
+       count = os_area_flash_read(header, buf_len, 0);
+       if (count < 0) {
+               pr_debug("%s: os_area_flash_read failed %zd\n", __func__,
+                        count);
+               error = count;
+               goto fail;
        }
 
-       count = sys_read(file, (char __user *)header, buf_len);
-
-       result = count < OS_AREA_SEGMENT_SIZE || verify_header(header)
-               || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE;
-
-       if (result) {
-               pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
+       pos = header->db_area_offset * OS_AREA_SEGMENT_SIZE;
+       if (count < OS_AREA_SEGMENT_SIZE || verify_header(header) ||
+           count < pos) {
+               pr_debug("%s: verify_header failed\n", __func__);
                dump_header(header);
-               goto fail_header;
+               error = -EINVAL;
+               goto fail;
        }
 
        /* Now got a good db offset and some maybe good db data. */
 
-       db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE;
+       db = (void *)header + pos;
 
-       result = db_verify(db);
-
-       if (result) {
-               printk(KERN_NOTICE "%s:%d: Verify of flash database failed, "
-                       "formatting.\n", __func__, __LINE__);
+       error = db_verify(db);
+       if (error) {
+               pr_notice("%s: Verify of flash database failed, formatting.\n",
+                         __func__);
                dump_db(db);
                os_area_db_init(db);
        }
@@ -639,29 +666,16 @@ static void __maybe_unused update_flash_db(void)
 
        db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff);
 
-       offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE,
-               SEEK_SET);
-
-       if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) {
-               pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
-               goto fail_db_seek;
-       }
-
-       count = sys_write(file, (const char __user *)db,
-               sizeof(struct os_area_db));
-
+       count = os_area_flash_write(db, sizeof(struct os_area_db), pos);
        if (count < sizeof(struct os_area_db)) {
-               pr_debug("%s:%d sys_write failed\n", __func__, __LINE__);
+               pr_debug("%s: os_area_flash_write failed %zd\n", __func__,
+                        count);
+               error = count < 0 ? count : -EIO;
        }
 
-fail_db_seek:
-fail_header:
-fail_header_seek:
+fail:
        kfree(header);
-fail_malloc:
-       sys_close(file);
-fail_open:
-       return;
+       return error;
 }
 
 /**
@@ -674,11 +688,11 @@ fail_open:
 static void os_area_queue_work_handler(struct work_struct *work)
 {
        struct device_node *node;
+       int error;
 
        pr_debug(" -> %s:%d\n", __func__, __LINE__);
 
        node = of_find_node_by_path("/");
-
        if (node) {
                os_area_set_property(node, &property_rtc_diff);
                of_node_put(node);
@@ -686,12 +700,10 @@ static void os_area_queue_work_handler(struct work_struct *work)
                pr_debug("%s:%d of_find_node_by_path failed\n",
                        __func__, __LINE__);
 
-#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
-       update_flash_db();
-#else
-       printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n",
-               __func__, __LINE__);
-#endif
+       error = update_flash_db();
+       if (error)
+               pr_warning("%s: Could not update FLASH ROM\n", __func__);
+
        pr_debug(" <- %s:%d\n", __func__, __LINE__);
 }
 
@@ -808,7 +820,7 @@ u64 ps3_os_area_get_rtc_diff(void)
 {
        return saved_params.rtc_diff;
 }
-EXPORT_SYMBOL(ps3_os_area_get_rtc_diff);
+EXPORT_SYMBOL_GPL(ps3_os_area_get_rtc_diff);
 
 /**
  * ps3_os_area_set_rtc_diff - Set the rtc diff value.
@@ -824,7 +836,7 @@ void ps3_os_area_set_rtc_diff(u64 rtc_diff)
                os_area_queue_work();
        }
 }
-EXPORT_SYMBOL(ps3_os_area_set_rtc_diff);
+EXPORT_SYMBOL_GPL(ps3_os_area_set_rtc_diff);
 
 /**
  * ps3_os_area_get_av_multi_out - Returns the default video mode.
index 136aa0637d9c0bbc67e10f13b98d96f5540aa288..9a196a88eda794d6d07f50abefaebc7a21902427 100644 (file)
@@ -232,14 +232,4 @@ int ps3_repository_read_spu_resource_id(unsigned int res_index,
 int ps3_repository_read_vuart_av_port(unsigned int *port);
 int ps3_repository_read_vuart_sysmgr_port(unsigned int *port);
 
-/* Page table entries */
-#define IOPTE_PP_W             0x8000000000000000ul /* protection: write */
-#define IOPTE_PP_R             0x4000000000000000ul /* protection: read */
-#define IOPTE_M                        0x2000000000000000ul /* coherency required */
-#define IOPTE_SO_R             0x1000000000000000ul /* ordering: writes */
-#define IOPTE_SO_RW             0x1800000000000000ul /* ordering: r & w */
-#define IOPTE_RPN_Mask         0x07fffffffffff000ul /* RPN */
-#define IOPTE_H                        0x0000000000000800ul /* cache hint */
-#define IOPTE_IOID_Mask                0x00000000000007fful /* ioid */
-
 #endif
index 1a7b5ae0c83e3eb92bccde0b6201ad78a6cb7a27..149bea2ce58370b606fc51132760123d1bebadba 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/udbg.h>
 #include <asm/prom.h>
 #include <asm/lv1call.h>
+#include <asm/ps3gpu.h>
 
 #include "platform.h"
 
index 9a73d0238639307cd2f1f16d5352def20aa27e86..9fead0faf38bbd5930fe0dd0f75fcc1f2711c296 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/udbg.h>
 #include <asm/lv1call.h>
 #include <asm/firmware.h>
+#include <asm/iommu.h>
 
 #include "platform.h"
 
@@ -531,7 +532,8 @@ static void * ps3_alloc_coherent(struct device *_dev, size_t size,
        }
 
        result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle,
-                            IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
+                            CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
+                            CBE_IOPTE_SO_RW | CBE_IOPTE_M);
 
        if (result) {
                pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@@ -575,7 +577,8 @@ static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page,
 
        result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
                             &bus_addr,
-                            IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M);
+                            CBE_IOPTE_PP_R | CBE_IOPTE_PP_W |
+                            CBE_IOPTE_SO_RW | CBE_IOPTE_M);
 
        if (result) {
                pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@@ -596,16 +599,16 @@ static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
        u64 iopte_flag;
        void *ptr = page_address(page) + offset;
 
-       iopte_flag = IOPTE_M;
+       iopte_flag = CBE_IOPTE_M;
        switch (direction) {
        case DMA_BIDIRECTIONAL:
-               iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW;
+               iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW;
                break;
        case DMA_TO_DEVICE:
-               iopte_flag |= IOPTE_PP_R | IOPTE_SO_R;
+               iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_SO_R;
                break;
        case DMA_FROM_DEVICE:
-               iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW;
+               iopte_flag |= CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW;
                break;
        default:
                /* not happned */
index 99dc3ded6b4975dc190d0243b856d539c9a932ce..a14dba0e4d67105c89838e8416d2dab0443640a2 100644 (file)
@@ -348,6 +348,9 @@ config ARCH_ENABLE_MEMORY_HOTPLUG
 config ARCH_ENABLE_MEMORY_HOTREMOVE
        def_bool y
 
+config ARCH_HIBERNATION_POSSIBLE
+       def_bool y if 64BIT
+
 source "mm/Kconfig"
 
 comment "I/O subsystem configuration"
@@ -592,6 +595,12 @@ config SECCOMP
 
 endmenu
 
+menu "Power Management"
+
+source "kernel/power/Kconfig"
+
+endmenu
+
 source "net/Kconfig"
 
 config PCMCIA
index 578c61f15a4beff789126dfa98478992e028ca2a..0ff387cebf88e5032847811ae959a5afa607d3a9 100644 (file)
@@ -88,7 +88,9 @@ LDFLAGS_vmlinux := -e start
 head-y         := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
 
 core-y         += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \
-                  arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/
+                  arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/ \
+                  arch/s390/power/
+
 libs-y         += arch/s390/lib/
 drivers-y      += drivers/s390/
 drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/
index 1dfc7100c7ee358cb0a0e131b43d36145f64a6fd..264528e4f58d5ea3fa0ff12f534c925df21001a6 100644 (file)
@@ -5,7 +5,7 @@
  * Exports appldata_register_ops() and appldata_unregister_ops() for the
  * data gathering modules.
  *
- * Copyright IBM Corp. 2003, 2008
+ * Copyright IBM Corp. 2003, 2009
  *
  * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
@@ -26,6 +26,8 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/workqueue.h>
+#include <linux/suspend.h>
+#include <linux/platform_device.h>
 #include <asm/appldata.h>
 #include <asm/timer.h>
 #include <asm/uaccess.h>
@@ -41,6 +43,9 @@
 
 #define TOD_MICRO      0x01000                 /* nr. of TOD clock units
                                                   for 1 microsecond */
+
+static struct platform_device *appldata_pdev;
+
 /*
  * /proc entries (sysctl)
  */
@@ -86,6 +91,7 @@ static atomic_t appldata_expire_count = ATOMIC_INIT(0);
 static DEFINE_SPINLOCK(appldata_timer_lock);
 static int appldata_interval = APPLDATA_CPU_INTERVAL;
 static int appldata_timer_active;
+static int appldata_timer_suspended = 0;
 
 /*
  * Work queue
@@ -475,6 +481,93 @@ void appldata_unregister_ops(struct appldata_ops *ops)
 /********************** module-ops management <END> **************************/
 
 
+/**************************** suspend / resume *******************************/
+static int appldata_freeze(struct device *dev)
+{
+       struct appldata_ops *ops;
+       int rc;
+       struct list_head *lh;
+
+       get_online_cpus();
+       spin_lock(&appldata_timer_lock);
+       if (appldata_timer_active) {
+               __appldata_vtimer_setup(APPLDATA_DEL_TIMER);
+               appldata_timer_suspended = 1;
+       }
+       spin_unlock(&appldata_timer_lock);
+       put_online_cpus();
+
+       mutex_lock(&appldata_ops_mutex);
+       list_for_each(lh, &appldata_ops_list) {
+               ops = list_entry(lh, struct appldata_ops, list);
+               if (ops->active == 1) {
+                       rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
+                                       (unsigned long) ops->data, ops->size,
+                                       ops->mod_lvl);
+                       if (rc != 0)
+                               pr_err("Stopping the data collection for %s "
+                                      "failed with rc=%d\n", ops->name, rc);
+               }
+       }
+       mutex_unlock(&appldata_ops_mutex);
+       return 0;
+}
+
+static int appldata_restore(struct device *dev)
+{
+       struct appldata_ops *ops;
+       int rc;
+       struct list_head *lh;
+
+       get_online_cpus();
+       spin_lock(&appldata_timer_lock);
+       if (appldata_timer_suspended) {
+               __appldata_vtimer_setup(APPLDATA_ADD_TIMER);
+               appldata_timer_suspended = 0;
+       }
+       spin_unlock(&appldata_timer_lock);
+       put_online_cpus();
+
+       mutex_lock(&appldata_ops_mutex);
+       list_for_each(lh, &appldata_ops_list) {
+               ops = list_entry(lh, struct appldata_ops, list);
+               if (ops->active == 1) {
+                       ops->callback(ops->data);       // init record
+                       rc = appldata_diag(ops->record_nr,
+                                       APPLDATA_START_INTERVAL_REC,
+                                       (unsigned long) ops->data, ops->size,
+                                       ops->mod_lvl);
+                       if (rc != 0) {
+                               pr_err("Starting the data collection for %s "
+                                      "failed with rc=%d\n", ops->name, rc);
+                       }
+               }
+       }
+       mutex_unlock(&appldata_ops_mutex);
+       return 0;
+}
+
+static int appldata_thaw(struct device *dev)
+{
+       return appldata_restore(dev);
+}
+
+static struct dev_pm_ops appldata_pm_ops = {
+       .freeze         = appldata_freeze,
+       .thaw           = appldata_thaw,
+       .restore        = appldata_restore,
+};
+
+static struct platform_driver appldata_pdrv = {
+       .driver = {
+               .name   = "appldata",
+               .owner  = THIS_MODULE,
+               .pm     = &appldata_pm_ops,
+       },
+};
+/************************* suspend / resume <END> ****************************/
+
+
 /******************************* init / exit *********************************/
 
 static void __cpuinit appldata_online_cpu(int cpu)
@@ -531,11 +624,23 @@ static struct notifier_block __cpuinitdata appldata_nb = {
  */
 static int __init appldata_init(void)
 {
-       int i;
+       int i, rc;
+
+       rc = platform_driver_register(&appldata_pdrv);
+       if (rc)
+               return rc;
 
+       appldata_pdev = platform_device_register_simple("appldata", -1, NULL,
+                                                       0);
+       if (IS_ERR(appldata_pdev)) {
+               rc = PTR_ERR(appldata_pdev);
+               goto out_driver;
+       }
        appldata_wq = create_singlethread_workqueue("appldata");
-       if (!appldata_wq)
-               return -ENOMEM;
+       if (!appldata_wq) {
+               rc = -ENOMEM;
+               goto out_device;
+       }
 
        get_online_cpus();
        for_each_online_cpu(i)
@@ -547,6 +652,12 @@ static int __init appldata_init(void)
 
        appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
        return 0;
+
+out_device:
+       platform_device_unregister(appldata_pdev);
+out_driver:
+       platform_driver_unregister(&appldata_pdrv);
+       return rc;
 }
 
 __initcall(appldata_init);
index ba007d8df9411867260f9b75591219ed8872da0d..2a541955117688b23de8b40557dfd944d1dce02c 100644 (file)
@@ -1,11 +1,9 @@
 /*
- *  include/asm-s390/ccwdev.h
- *  include/asm-s390x/ccwdev.h
+ * Copyright  IBM Corp. 2002, 2009
  *
- *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Arnd Bergmann <arndb@de.ibm.com>
+ * Author(s): Arnd Bergmann <arndb@de.ibm.com>
  *
- *  Interface for CCW device drivers
+ * Interface for CCW device drivers
  */
 #ifndef _S390_CCWDEV_H_
 #define _S390_CCWDEV_H_
@@ -104,6 +102,11 @@ struct ccw_device {
  * @set_offline: called when setting device offline
  * @notify: notify driver of device state changes
  * @shutdown: called at device shutdown
+ * @prepare: prepare for pm state transition
+ * @complete: undo work done in @prepare
+ * @freeze: callback for freezing during hibernation snapshotting
+ * @thaw: undo work done in @freeze
+ * @restore: callback for restoring after hibernation
  * @driver: embedded device driver structure
  * @name: device driver name
  */
@@ -116,6 +119,11 @@ struct ccw_driver {
        int (*set_offline) (struct ccw_device *);
        int (*notify) (struct ccw_device *, int);
        void (*shutdown) (struct ccw_device *);
+       int (*prepare) (struct ccw_device *);
+       void (*complete) (struct ccw_device *);
+       int (*freeze)(struct ccw_device *);
+       int (*thaw) (struct ccw_device *);
+       int (*restore)(struct ccw_device *);
        struct device_driver driver;
        char *name;
 };
@@ -184,6 +192,7 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
 #define to_ccwdrv(n) container_of(n, struct ccw_driver, driver)
 
 extern struct ccw_device *ccw_device_probe_console(void);
+extern int ccw_device_force_console(void);
 
 // FIXME: these have to go
 extern int _ccw_device_get_subchannel_number(struct ccw_device *);
index a27f68985a791d7c5317a8574c0605ef1c54064c..c79c1e787b86fc67903c0823d9637b94a784ac93 100644 (file)
@@ -38,6 +38,11 @@ struct ccwgroup_device {
  * @set_online: function called when device is set online
  * @set_offline: function called when device is set offline
  * @shutdown: function called when device is shut down
+ * @prepare: prepare for pm state transition
+ * @complete: undo work done in @prepare
+ * @freeze: callback for freezing during hibernation snapshotting
+ * @thaw: undo work done in @freeze
+ * @restore: callback for restoring after hibernation
  * @driver: embedded driver structure
  */
 struct ccwgroup_driver {
@@ -51,6 +56,11 @@ struct ccwgroup_driver {
        int (*set_online) (struct ccwgroup_device *);
        int (*set_offline) (struct ccwgroup_device *);
        void (*shutdown)(struct ccwgroup_device *);
+       int (*prepare) (struct ccwgroup_device *);
+       void (*complete) (struct ccwgroup_device *);
+       int (*freeze)(struct ccwgroup_device *);
+       int (*thaw) (struct ccwgroup_device *);
+       int (*restore)(struct ccwgroup_device *);
 
        struct device_driver driver;
 };
diff --git a/arch/s390/include/asm/suspend.h b/arch/s390/include/asm/suspend.h
new file mode 100644 (file)
index 0000000..dc75c61
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __ASM_S390_SUSPEND_H
+#define __ASM_S390_SUSPEND_H
+
+static inline int arch_prepare_suspend(void)
+{
+       return 0;
+}
+
+#endif
+
index 3a8b26eb1f2e827d3d6de72b508dd307c08de6a0..4fb83c1cdb77a206d72136830107e912f83a1dd1 100644 (file)
@@ -1,11 +1,7 @@
 /*
- *  include/asm-s390/system.h
+ * Copyright IBM Corp. 1999, 2009
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- *
- *  Derived from "include/asm-i386/system.h"
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #ifndef __ASM_SYSTEM_H
@@ -469,6 +465,20 @@ extern psw_t sysc_restore_trace_psw;
 extern psw_t io_restore_trace_psw;
 #endif
 
+static inline int tprot(unsigned long addr)
+{
+       int rc = -EFAULT;
+
+       asm volatile(
+               "       tprot   0(%1),0\n"
+               "0:     ipm     %0\n"
+               "       srl     %0,28\n"
+               "1:\n"
+               EX_TABLE(0b,1b)
+               : "+d" (rc) : "a" (addr) : "cc");
+       return rc;
+}
+
 #endif /* __KERNEL__ */
 
 #endif
index fb263736826c8d73d0e2f0031afbbd24c88c69a9..f9b144049dc983ef16419a415feadb14e2c0374b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/s390/kernel/early.c
  *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007, 2009
  *    Author(s): Hongjie Yang <hongjie@us.ibm.com>,
  *              Heiko Carstens <heiko.carstens@de.ibm.com>
  */
@@ -210,7 +210,7 @@ static noinline __init void detect_machine_type(void)
                machine_flags |= MACHINE_FLAG_VM;
 }
 
-static __init void early_pgm_check_handler(void)
+static void early_pgm_check_handler(void)
 {
        unsigned long addr;
        const struct exception_table_entry *fixup;
@@ -222,7 +222,7 @@ static __init void early_pgm_check_handler(void)
        S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
 }
 
-static noinline __init void setup_lowcore_early(void)
+void setup_lowcore_early(void)
 {
        psw_t psw;
 
index 9872999c66d1e4304afad270652bee5cda303da7..559af0d07878867cb0e382226c33852af5e17e62 100644 (file)
@@ -1,6 +1,7 @@
 /*
- *    Copyright IBM Corp. 2008
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ * Copyright IBM Corp. 2008, 2009
+ *
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
  */
 
 #include <linux/kernel.h>
@@ -9,20 +10,6 @@
 #include <asm/sclp.h>
 #include <asm/setup.h>
 
-static inline int tprot(unsigned long addr)
-{
-       int rc = -EFAULT;
-
-       asm volatile(
-               "       tprot   0(%1),0\n"
-               "0:     ipm     %0\n"
-               "       srl     %0,28\n"
-               "1:\n"
-               EX_TABLE(0b,1b)
-               : "+d" (rc) : "a" (addr) : "cc");
-       return rc;
-}
-
 #define ADDR2G (1ULL << 31)
 
 static void find_memory_chunks(struct mem_chunk chunk[])
index cc8c484984e33160375b11fd9f147c764b805cde..fd8e3111a4e8f6dd862d45b9787d0f23fff51b60 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/s390/kernel/smp.c
  *
- *    Copyright IBM Corp. 1999,2007
+ *    Copyright IBM Corp. 1999, 2009
  *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
  *              Heiko Carstens (heiko.carstens@de.ibm.com)
@@ -1031,6 +1031,42 @@ out:
 static SYSDEV_CLASS_ATTR(dispatching, 0644, dispatching_show,
                         dispatching_store);
 
+/*
+ * If the resume kernel runs on another cpu than the suspended kernel,
+ * we have to switch the cpu IDs in the logical map.
+ */
+void smp_switch_boot_cpu_in_resume(u32 resume_phys_cpu_id,
+                                  struct _lowcore *suspend_lowcore)
+{
+       int cpu, suspend_cpu_id, resume_cpu_id;
+       u32 suspend_phys_cpu_id;
+
+       suspend_phys_cpu_id = __cpu_logical_map[suspend_lowcore->cpu_nr];
+       suspend_cpu_id = suspend_lowcore->cpu_nr;
+
+       for_each_present_cpu(cpu) {
+               if (__cpu_logical_map[cpu] == resume_phys_cpu_id) {
+                       resume_cpu_id = cpu;
+                       goto found;
+               }
+       }
+       panic("Could not find resume cpu in logical map.\n");
+
+found:
+       printk("Resume  cpu ID: %i/%i\n", resume_phys_cpu_id, resume_cpu_id);
+       printk("Suspend cpu ID: %i/%i\n", suspend_phys_cpu_id, suspend_cpu_id);
+
+       __cpu_logical_map[resume_cpu_id] = suspend_phys_cpu_id;
+       __cpu_logical_map[suspend_cpu_id] = resume_phys_cpu_id;
+
+       lowcore_ptr[suspend_cpu_id]->cpu_addr = resume_phys_cpu_id;
+}
+
+u32 smp_get_phys_cpu_id(void)
+{
+       return __cpu_logical_map[smp_processor_id()];
+}
+
 static int __init topology_init(void)
 {
        int cpu;
index 4ca8e826bf303b4d8694f0757fe8b471ba52d099..565667207985c15e6e5ca4526dd2a36ec33b293e 100644 (file)
@@ -313,3 +313,22 @@ int s390_enable_sie(void)
        return 0;
 }
 EXPORT_SYMBOL_GPL(s390_enable_sie);
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+#ifdef CONFIG_HIBERNATION
+bool kernel_page_present(struct page *page)
+{
+       unsigned long addr;
+       int cc;
+
+       addr = page_to_phys(page);
+       asm("lra %1,0(%1)\n"
+           "ipm %0\n"
+           "srl %0,28"
+           :"=d"(cc),"+a"(addr)::"cc");
+       return cc == 0;
+}
+
+#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_DEBUG_PAGEALLOC */
+
diff --git a/arch/s390/power/Makefile b/arch/s390/power/Makefile
new file mode 100644 (file)
index 0000000..973bb45
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for s390 PM support
+#
+
+obj-$(CONFIG_HIBERNATION) += suspend.o
+obj-$(CONFIG_HIBERNATION) += swsusp.o
+obj-$(CONFIG_HIBERNATION) += swsusp_64.o
+obj-$(CONFIG_HIBERNATION) += swsusp_asm64.o
diff --git a/arch/s390/power/suspend.c b/arch/s390/power/suspend.c
new file mode 100644 (file)
index 0000000..b3351ec
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Suspend support specific for s390.
+ *
+ * Copyright IBM Corp. 2009
+ *
+ * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
+ */
+
+#include <linux/mm.h>
+#include <linux/suspend.h>
+#include <linux/reboot.h>
+#include <linux/pfn.h>
+#include <asm/sections.h>
+#include <asm/ipl.h>
+
+/*
+ * References to section boundaries
+ */
+extern const void __nosave_begin, __nosave_end;
+
+/*
+ *  check if given pfn is in the 'nosave' or in the read only NSS section
+ */
+int pfn_is_nosave(unsigned long pfn)
+{
+       unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
+       unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end))
+                                       >> PAGE_SHIFT;
+       unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1;
+       unsigned long stext_pfn = PFN_DOWN(__pa(&_stext));
+
+       if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn)
+               return 1;
+       if (pfn >= stext_pfn && pfn <= eshared_pfn) {
+               if (ipl_info.type == IPL_TYPE_NSS)
+                       return 1;
+       } else if ((tprot(pfn * PAGE_SIZE) && pfn > 0))
+               return 1;
+       return 0;
+}
diff --git a/arch/s390/power/swsusp.c b/arch/s390/power/swsusp.c
new file mode 100644 (file)
index 0000000..e6a4fe9
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Support for suspend and resume on s390
+ *
+ * Copyright IBM Corp. 2009
+ *
+ * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
+ *
+ */
+
+
+/*
+ * save CPU registers before creating a hibernation image and before
+ * restoring the memory state from it
+ */
+void save_processor_state(void)
+{
+       /* implentation contained in the
+        * swsusp_arch_suspend function
+        */
+}
+
+/*
+ * restore the contents of CPU registers
+ */
+void restore_processor_state(void)
+{
+       /* implentation contained in the
+        * swsusp_arch_resume function
+        */
+}
diff --git a/arch/s390/power/swsusp_64.c b/arch/s390/power/swsusp_64.c
new file mode 100644 (file)
index 0000000..9516a51
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Support for suspend and resume on s390
+ *
+ * Copyright IBM Corp. 2009
+ *
+ * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
+ *
+ */
+
+#include <asm/system.h>
+#include <linux/interrupt.h>
+
+void do_after_copyback(void)
+{
+       mb();
+}
+
diff --git a/arch/s390/power/swsusp_asm64.S b/arch/s390/power/swsusp_asm64.S
new file mode 100644 (file)
index 0000000..3c74e7d
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * S390 64-bit swsusp implementation
+ *
+ * Copyright IBM Corp. 2009
+ *
+ * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
+ *           Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/asm-offsets.h>
+
+/*
+ * Save register context in absolute 0 lowcore and call swsusp_save() to
+ * create in-memory kernel image. The context is saved in the designated
+ * "store status" memory locations (see POP).
+ * We return from this function twice. The first time during the suspend to
+ * disk process. The second time via the swsusp_arch_resume() function
+ * (see below) in the resume process.
+ * This function runs with disabled interrupts.
+ */
+       .section .text
+       .align  2
+       .globl swsusp_arch_suspend
+swsusp_arch_suspend:
+       stmg    %r6,%r15,__SF_GPRS(%r15)
+       lgr     %r1,%r15
+       aghi    %r15,-STACK_FRAME_OVERHEAD
+       stg     %r1,__SF_BACKCHAIN(%r15)
+
+       /* Deactivate DAT */
+       stnsm   __SF_EMPTY(%r15),0xfb
+
+       /* Switch off lowcore protection */
+       stctg   %c0,%c0,__SF_EMPTY(%r15)
+       ni      __SF_EMPTY+4(%r15),0xef
+       lctlg   %c0,%c0,__SF_EMPTY(%r15)
+
+       /* Store prefix register on stack */
+       stpx    __SF_EMPTY(%r15)
+
+       /* Setup base register for lowcore (absolute 0) */
+       llgf    %r1,__SF_EMPTY(%r15)
+
+       /* Get pointer to save area */
+       aghi    %r1,0x1000
+
+       /* Store registers */
+       mvc     0x318(4,%r1),__SF_EMPTY(%r15)   /* move prefix to lowcore */
+       stfpc   0x31c(%r1)                      /* store fpu control */
+       std     0,0x200(%r1)                    /* store f0 */
+       std     1,0x208(%r1)                    /* store f1 */
+       std     2,0x210(%r1)                    /* store f2 */
+       std     3,0x218(%r1)                    /* store f3 */
+       std     4,0x220(%r1)                    /* store f4 */
+       std     5,0x228(%r1)                    /* store f5 */
+       std     6,0x230(%r1)                    /* store f6 */
+       std     7,0x238(%r1)                    /* store f7 */
+       std     8,0x240(%r1)                    /* store f8 */
+       std     9,0x248(%r1)                    /* store f9 */
+       std     10,0x250(%r1)                   /* store f10 */
+       std     11,0x258(%r1)                   /* store f11 */
+       std     12,0x260(%r1)                   /* store f12 */
+       std     13,0x268(%r1)                   /* store f13 */
+       std     14,0x270(%r1)                   /* store f14 */
+       std     15,0x278(%r1)                   /* store f15 */
+       stam    %a0,%a15,0x340(%r1)             /* store access registers */
+       stctg   %c0,%c15,0x380(%r1)             /* store control registers */
+       stmg    %r0,%r15,0x280(%r1)             /* store general registers */
+
+       stpt    0x328(%r1)                      /* store timer */
+       stckc   0x330(%r1)                      /* store clock comparator */
+
+       /* Activate DAT */
+       stosm   __SF_EMPTY(%r15),0x04
+
+       /* Set prefix page to zero */
+       xc      __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
+       spx     __SF_EMPTY(%r15)
+
+       /* Setup lowcore */
+       brasl   %r14,setup_lowcore_early
+
+       /* Save image */
+       brasl   %r14,swsusp_save
+
+       /* Switch on lowcore protection */
+       stctg   %c0,%c0,__SF_EMPTY(%r15)
+       oi      __SF_EMPTY+4(%r15),0x10
+       lctlg   %c0,%c0,__SF_EMPTY(%r15)
+
+       /* Restore prefix register and return */
+       lghi    %r1,0x1000
+       spx     0x318(%r1)
+       lmg     %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
+       lghi    %r2,0
+       br      %r14
+
+/*
+ * Restore saved memory image to correct place and restore register context.
+ * Then we return to the function that called swsusp_arch_suspend().
+ * swsusp_arch_resume() runs with disabled interrupts.
+ */
+       .globl swsusp_arch_resume
+swsusp_arch_resume:
+       stmg    %r6,%r15,__SF_GPRS(%r15)
+       lgr     %r1,%r15
+       aghi    %r15,-STACK_FRAME_OVERHEAD
+       stg     %r1,__SF_BACKCHAIN(%r15)
+
+       /* Save boot cpu number */
+       brasl   %r14,smp_get_phys_cpu_id
+       lgr     %r10,%r2
+
+       /* Deactivate DAT */
+       stnsm   __SF_EMPTY(%r15),0xfb
+
+       /* Switch off lowcore protection */
+       stctg   %c0,%c0,__SF_EMPTY(%r15)
+       ni      __SF_EMPTY+4(%r15),0xef
+       lctlg   %c0,%c0,__SF_EMPTY(%r15)
+
+       /* Set prefix page to zero */
+       xc      __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
+       spx     __SF_EMPTY(%r15)
+
+       /* Restore saved image */
+       larl    %r1,restore_pblist
+       lg      %r1,0(%r1)
+       ltgr    %r1,%r1
+       jz      2f
+0:
+       lg      %r2,8(%r1)
+       lg      %r4,0(%r1)
+       lghi    %r3,PAGE_SIZE
+       lghi    %r5,PAGE_SIZE
+1:
+       mvcle   %r2,%r4,0
+       jo      1b
+       lg      %r1,16(%r1)
+       ltgr    %r1,%r1
+       jnz     0b
+2:
+       ptlb                            /* flush tlb */
+
+       /* Restore registers */
+       lghi    %r13,0x1000             /* %r1 = pointer to save arae */
+
+       spt     0x328(%r13)             /* reprogram timer */
+       //sckc  0x330(%r13)             /* set clock comparator */
+
+       lctlg   %c0,%c15,0x380(%r13)    /* load control registers */
+       lam     %a0,%a15,0x340(%r13)    /* load access registers */
+
+       lfpc    0x31c(%r13)             /* load fpu control */
+       ld      0,0x200(%r13)           /* load f0 */
+       ld      1,0x208(%r13)           /* load f1 */
+       ld      2,0x210(%r13)           /* load f2 */
+       ld      3,0x218(%r13)           /* load f3 */
+       ld      4,0x220(%r13)           /* load f4 */
+       ld      5,0x228(%r13)           /* load f5 */
+       ld      6,0x230(%r13)           /* load f6 */
+       ld      7,0x238(%r13)           /* load f7 */
+       ld      8,0x240(%r13)           /* load f8 */
+       ld      9,0x248(%r13)           /* load f9 */
+       ld      10,0x250(%r13)          /* load f10 */
+       ld      11,0x258(%r13)          /* load f11 */
+       ld      12,0x260(%r13)          /* load f12 */
+       ld      13,0x268(%r13)          /* load f13 */
+       ld      14,0x270(%r13)          /* load f14 */
+       ld      15,0x278(%r13)          /* load f15 */
+
+       /* Load old stack */
+       lg      %r15,0x2f8(%r13)
+
+       /* Pointer to save arae */
+       lghi    %r13,0x1000
+
+       /* Switch CPUs */
+       lgr     %r2,%r10                /* get cpu id */
+       llgf    %r3,0x318(%r13)
+       brasl   %r14,smp_switch_boot_cpu_in_resume
+
+       /* Restore prefix register */
+       spx     0x318(%r13)
+
+       /* Switch on lowcore protection */
+       stctg   %c0,%c0,__SF_EMPTY(%r15)
+       oi      __SF_EMPTY+4(%r15),0x10
+       lctlg   %c0,%c0,__SF_EMPTY(%r15)
+
+       /* Activate DAT */
+       stosm   __SF_EMPTY(%r15),0x04
+
+       /* Return 0 */
+       lmg     %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
+       lghi    %r2,0
+       br      %r14
index cc12cd48bbc51a41bc157681de49a2b1eeb102d3..3f8b6a92eabdff56413ed4cefd54d678290a228a 100644 (file)
@@ -37,6 +37,8 @@ config SPARC64
        select HAVE_KPROBES
        select HAVE_LMB
        select HAVE_SYSCALL_WRAPPERS
+       select HAVE_DYNAMIC_FTRACE
+       select HAVE_FTRACE_MCOUNT_RECORD
        select USE_GENERIC_SMP_HELPERS if SMP
        select RTC_DRV_CMOS
        select RTC_DRV_BQ4802
@@ -93,6 +95,9 @@ config AUDIT_ARCH
 config HAVE_SETUP_PER_CPU_AREA
        def_bool y if SPARC64
 
+config HAVE_DYNAMIC_PER_CPU_AREA
+       def_bool y if SPARC64
+
 config GENERIC_HARDIRQS_NO__DO_IRQ
        bool
        def_bool y if SPARC64
index b5d63bd8716ead259a5ea8c0c59cbabe9fd09931..0123a4c596cef67a537d6a3f660b0cbf0a3b74c6 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Fri Apr 17 02:03:07 2009
+# Linux kernel version: 2.6.30
+# Tue Jun 16 04:59:36 2009
 #
 CONFIG_64BIT=y
 CONFIG_SPARC=y
@@ -19,6 +19,7 @@ CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
 CONFIG_AUDIT_ARCH=y
 CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HAVE_DYNAMIC_PER_CPU_AREA=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_MMU=y
 CONFIG_ARCH_NO_VIRT_TO_BUS=y
@@ -82,7 +83,6 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -95,16 +95,21 @@ CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
+
+#
+# Performance Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_PCI_QUIRKS=y
 CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_COMPAT_BRK is not set
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 CONFIG_PROFILING=y
 CONFIG_TRACEPOINTS=y
-# CONFIG_MARKERS is not set
+CONFIG_MARKERS=y
 CONFIG_OPROFILE=m
 CONFIG_HAVE_OPROFILE=y
 CONFIG_KPROBES=y
@@ -202,6 +207,7 @@ CONFIG_NR_QUICK=1
 CONFIG_UNEVICTABLE_LRU=y
 CONFIG_HAVE_MLOCK=y
 CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=8192
 CONFIG_SCHED_SMT=y
 CONFIG_SCHED_MC=y
 # CONFIG_PREEMPT_NONE is not set
@@ -321,6 +327,7 @@ CONFIG_VLAN_8021Q=m
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 
@@ -340,7 +347,11 @@ CONFIG_WIRELESS=y
 CONFIG_WIRELESS_OLD_REGULATORY=y
 # CONFIG_WIRELESS_EXT is not set
 # CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
 # CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
@@ -364,6 +375,7 @@ CONFIG_EXTRA_FIRMWARE=""
 CONFIG_CONNECTOR=m
 # CONFIG_MTD is not set
 CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=m
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_FD is not set
@@ -399,6 +411,7 @@ CONFIG_MISC_DEVICES=y
 # CONFIG_EEPROM_AT24 is not set
 # CONFIG_EEPROM_LEGACY is not set
 # CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
 CONFIG_HAVE_IDE=y
 CONFIG_IDE=y
 
@@ -477,10 +490,6 @@ CONFIG_BLK_DEV_SR=m
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 # CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -499,6 +508,7 @@ CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
@@ -507,6 +517,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
 # CONFIG_SCSI_ARCMSR is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
@@ -521,7 +532,6 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
 # CONFIG_SCSI_STEX is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
@@ -569,7 +579,6 @@ CONFIG_DM_ZERO=m
 # CONFIG_IEEE1394 is not set
 # CONFIG_I2O is not set
 CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
@@ -635,6 +644,7 @@ CONFIG_NET_PCI=y
 # CONFIG_SMSC9420 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_SC92031 is not set
 # CONFIG_ATL2 is not set
@@ -1127,6 +1137,11 @@ CONFIG_SND_VERBOSE_PROCFS=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 CONFIG_SND_VMASTER=y
+CONFIG_SND_RAWMIDI_SEQ=m
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
 CONFIG_SND_MPU401_UART=m
 CONFIG_SND_AC97_CODEC=m
 CONFIG_SND_DRIVERS=y
@@ -1153,6 +1168,7 @@ CONFIG_SND_ALI5451=m
 # CONFIG_SND_OXYGEN is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CTXFI is not set
 # CONFIG_SND_DARLA20 is not set
 # CONFIG_SND_GINA20 is not set
 # CONFIG_SND_LAYLA20 is not set
@@ -1183,6 +1199,7 @@ CONFIG_SND_ALI5451=m
 # CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0M is not set
 # CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LX6464ES is not set
 # CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_MIXART is not set
 # CONFIG_SND_NM256 is not set
@@ -1229,6 +1246,7 @@ CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
 # CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
 CONFIG_HID_KYE=y
@@ -1246,9 +1264,14 @@ CONFIG_HID_PETALYNX=y
 CONFIG_HID_SAMSUNG=y
 CONFIG_HID_SONY=y
 CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
 # CONFIG_GREENASIA_FF is not set
+CONFIG_HID_SMARTJOYPLUS=y
+# CONFIG_SMARTJOYPLUS_FF is not set
 CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
 # CONFIG_THRUSTMASTER_FF is not set
+CONFIG_HID_ZEROPLUS=y
 # CONFIG_ZEROPLUS_FF is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
@@ -1462,6 +1485,7 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1636,25 +1660,28 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
 # CONFIG_DEBUG_PAGEALLOC is not set
 CONFIG_NOP_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
 CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
 CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
 # CONFIG_FUNCTION_TRACER is not set
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
 # CONFIG_STACK_TRACER is not set
 # CONFIG_KMEMTRACE is not set
 # CONFIG_WORKQUEUE_TRACER is not set
 CONFIG_BLK_DEV_IO_TRACE=y
 # CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
 # CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
index a11b89ee9ef8f0a9e0758811dd633101adb4b12f..926397d345ff8c9c661ac69635ec11778c666d7b 100644 (file)
@@ -6,9 +6,6 @@
 #ifndef _SPARC64_CPUDATA_H
 #define _SPARC64_CPUDATA_H
 
-#include <asm/hypervisor.h>
-#include <asm/asi.h>
-
 #ifndef __ASSEMBLY__
 
 #include <linux/percpu.h>
@@ -38,202 +35,10 @@ DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);
 #define cpu_data(__cpu)                per_cpu(__cpu_data, (__cpu))
 #define local_cpu_data()       __get_cpu_var(__cpu_data)
 
-/* Trap handling code needs to get at a few critical values upon
- * trap entry and to process TSB misses.  These cannot be in the
- * per_cpu() area as we really need to lock them into the TLB and
- * thus make them part of the main kernel image.  As a result we
- * try to make this as small as possible.
- *
- * This is padded out and aligned to 64-bytes to avoid false sharing
- * on SMP.
- */
-
-/* If you modify the size of this structure, please update
- * TRAP_BLOCK_SZ_SHIFT below.
- */
-struct thread_info;
-struct trap_per_cpu {
-/* D-cache line 1: Basic thread information, cpu and device mondo queues */
-       struct thread_info      *thread;
-       unsigned long           pgd_paddr;
-       unsigned long           cpu_mondo_pa;
-       unsigned long           dev_mondo_pa;
-
-/* D-cache line 2: Error Mondo Queue and kernel buffer pointers */
-       unsigned long           resum_mondo_pa;
-       unsigned long           resum_kernel_buf_pa;
-       unsigned long           nonresum_mondo_pa;
-       unsigned long           nonresum_kernel_buf_pa;
-
-/* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */
-       struct hv_fault_status  fault_info;
-
-/* Dcache line 7: Physical addresses of CPU send mondo block and CPU list.  */
-       unsigned long           cpu_mondo_block_pa;
-       unsigned long           cpu_list_pa;
-       unsigned long           tsb_huge;
-       unsigned long           tsb_huge_temp;
-
-/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size.  */
-       unsigned long           irq_worklist_pa;
-       unsigned int            cpu_mondo_qmask;
-       unsigned int            dev_mondo_qmask;
-       unsigned int            resum_qmask;
-       unsigned int            nonresum_qmask;
-       void                    *hdesc;
-} __attribute__((aligned(64)));
-extern struct trap_per_cpu trap_block[NR_CPUS];
-extern void init_cur_cpu_trap(struct thread_info *);
-extern void setup_tba(void);
-extern int ncpus_probed;
 extern const struct seq_operations cpuinfo_op;
 
-extern unsigned long real_hard_smp_processor_id(void);
-
-struct cpuid_patch_entry {
-       unsigned int    addr;
-       unsigned int    cheetah_safari[4];
-       unsigned int    cheetah_jbus[4];
-       unsigned int    starfire[4];
-       unsigned int    sun4v[4];
-};
-extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
-
-struct sun4v_1insn_patch_entry {
-       unsigned int    addr;
-       unsigned int    insn;
-};
-extern struct sun4v_1insn_patch_entry __sun4v_1insn_patch,
-       __sun4v_1insn_patch_end;
-
-struct sun4v_2insn_patch_entry {
-       unsigned int    addr;
-       unsigned int    insns[2];
-};
-extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
-       __sun4v_2insn_patch_end;
-
 #endif /* !(__ASSEMBLY__) */
 
-#define TRAP_PER_CPU_THREAD            0x00
-#define TRAP_PER_CPU_PGD_PADDR         0x08
-#define TRAP_PER_CPU_CPU_MONDO_PA      0x10
-#define TRAP_PER_CPU_DEV_MONDO_PA      0x18
-#define TRAP_PER_CPU_RESUM_MONDO_PA    0x20
-#define TRAP_PER_CPU_RESUM_KBUF_PA     0x28
-#define TRAP_PER_CPU_NONRESUM_MONDO_PA 0x30
-#define TRAP_PER_CPU_NONRESUM_KBUF_PA  0x38
-#define TRAP_PER_CPU_FAULT_INFO                0x40
-#define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA        0xc0
-#define TRAP_PER_CPU_CPU_LIST_PA       0xc8
-#define TRAP_PER_CPU_TSB_HUGE          0xd0
-#define TRAP_PER_CPU_TSB_HUGE_TEMP     0xd8
-#define TRAP_PER_CPU_IRQ_WORKLIST_PA   0xe0
-#define TRAP_PER_CPU_CPU_MONDO_QMASK   0xe8
-#define TRAP_PER_CPU_DEV_MONDO_QMASK   0xec
-#define TRAP_PER_CPU_RESUM_QMASK       0xf0
-#define TRAP_PER_CPU_NONRESUM_QMASK    0xf4
-
-#define TRAP_BLOCK_SZ_SHIFT            8
-
-#include <asm/scratchpad.h>
-
-#define __GET_CPUID(REG)                               \
-       /* Spitfire implementation (default). */        \
-661:   ldxa            [%g0] ASI_UPA_CONFIG, REG;      \
-       srlx            REG, 17, REG;                   \
-        and            REG, 0x1f, REG;                 \
-       nop;                                            \
-       .section        .cpuid_patch, "ax";             \
-       /* Instruction location. */                     \
-       .word           661b;                           \
-       /* Cheetah Safari implementation. */            \
-       ldxa            [%g0] ASI_SAFARI_CONFIG, REG;   \
-       srlx            REG, 17, REG;                   \
-       and             REG, 0x3ff, REG;                \
-       nop;                                            \
-       /* Cheetah JBUS implementation. */              \
-       ldxa            [%g0] ASI_JBUS_CONFIG, REG;     \
-       srlx            REG, 17, REG;                   \
-       and             REG, 0x1f, REG;                 \
-       nop;                                            \
-       /* Starfire implementation. */                  \
-       sethi           %hi(0x1fff40000d0 >> 9), REG;   \
-       sllx            REG, 9, REG;                    \
-       or              REG, 0xd0, REG;                 \
-       lduwa           [REG] ASI_PHYS_BYPASS_EC_E, REG;\
-       /* sun4v implementation. */                     \
-       mov             SCRATCHPAD_CPUID, REG;          \
-       ldxa            [REG] ASI_SCRATCHPAD, REG;      \
-       nop;                                            \
-       nop;                                            \
-       .previous;
-
-#ifdef CONFIG_SMP
-
-#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP)                \
-       __GET_CPUID(TMP)                        \
-       sethi   %hi(trap_block), DEST;          \
-       sllx    TMP, TRAP_BLOCK_SZ_SHIFT, TMP;  \
-       or      DEST, %lo(trap_block), DEST;    \
-       add     DEST, TMP, DEST;                \
-
-/* Clobbers TMP, current address space PGD phys address into DEST.  */
-#define TRAP_LOAD_PGD_PHYS(DEST, TMP)          \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       ldx     [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
-
-/* Clobbers TMP, loads local processor's IRQ work area into DEST.  */
-#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP)       \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
-
-/* Clobbers TMP, loads DEST with current thread info pointer.  */
-#define TRAP_LOAD_THREAD_REG(DEST, TMP)                \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       ldx     [DEST + TRAP_PER_CPU_THREAD], DEST;
-
-/* Given the current thread info pointer in THR, load the per-cpu
- * area base of the current processor into DEST.  REG1, REG2, and REG3 are
- * clobbered.
- *
- * You absolutely cannot use DEST as a temporary in this code.  The
- * reason is that traps can happen during execution, and return from
- * trap will load the fully resolved DEST per-cpu base.  This can corrupt
- * the calculations done by the macro mid-stream.
- */
-#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) \
-       lduh    [THR + TI_CPU], REG1;                   \
-       sethi   %hi(__per_cpu_shift), REG3;             \
-       sethi   %hi(__per_cpu_base), REG2;              \
-       ldx     [REG3 + %lo(__per_cpu_shift)], REG3;    \
-       ldx     [REG2 + %lo(__per_cpu_base)], REG2;     \
-       sllx    REG1, REG3, REG3;                       \
-       add     REG3, REG2, DEST;
-
-#else
-
-#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP)                \
-       sethi   %hi(trap_block), DEST;          \
-       or      DEST, %lo(trap_block), DEST;    \
-
-/* Uniprocessor versions, we know the cpuid is zero.  */
-#define TRAP_LOAD_PGD_PHYS(DEST, TMP)          \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       ldx     [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
-
-/* Clobbers TMP, loads local processor's IRQ work area into DEST.  */
-#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP)       \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
-
-#define TRAP_LOAD_THREAD_REG(DEST, TMP)                \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       ldx     [DEST + TRAP_PER_CPU_THREAD], DEST;
-
-/* No per-cpu areas on uniprocessor, so no need to load DEST.  */
-#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3)
-
-#endif /* !(CONFIG_SMP) */
+#include <asm/trap_block.h>
 
 #endif /* _SPARC64_CPUDATA_H */
index 0f4150e26619c3a2063f92abe4ff95ca8dece6cc..204e4bf644380560394902b95445c3d9f6020ed1 100644 (file)
@@ -1,8 +1,166 @@
 #ifndef ___ASM_SPARC_DMA_MAPPING_H
 #define ___ASM_SPARC_DMA_MAPPING_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/dma-mapping_64.h>
-#else
-#include <asm/dma-mapping_32.h>
-#endif
+
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
+
+#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
+
+extern int dma_supported(struct device *dev, u64 mask);
+extern int dma_set_mask(struct device *dev, u64 dma_mask);
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_is_consistent(d, h)        (1)
+
+struct dma_ops {
+       void *(*alloc_coherent)(struct device *dev, size_t size,
+                               dma_addr_t *dma_handle, gfp_t flag);
+       void (*free_coherent)(struct device *dev, size_t size,
+                             void *cpu_addr, dma_addr_t dma_handle);
+       dma_addr_t (*map_page)(struct device *dev, struct page *page,
+                              unsigned long offset, size_t size,
+                              enum dma_data_direction direction);
+       void (*unmap_page)(struct device *dev, dma_addr_t dma_addr,
+                          size_t size,
+                          enum dma_data_direction direction);
+       int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents,
+                     enum dma_data_direction direction);
+       void (*unmap_sg)(struct device *dev, struct scatterlist *sg,
+                        int nhwentries,
+                        enum dma_data_direction direction);
+       void (*sync_single_for_cpu)(struct device *dev,
+                                   dma_addr_t dma_handle, size_t size,
+                                   enum dma_data_direction direction);
+       void (*sync_single_for_device)(struct device *dev,
+                                      dma_addr_t dma_handle, size_t size,
+                                      enum dma_data_direction direction);
+       void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg,
+                               int nelems,
+                               enum dma_data_direction direction);
+       void (*sync_sg_for_device)(struct device *dev,
+                                  struct scatterlist *sg, int nents,
+                                  enum dma_data_direction dir);
+};
+extern const struct dma_ops *dma_ops;
+
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+                                      dma_addr_t *dma_handle, gfp_t flag)
+{
+       return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+}
+
+static inline void dma_free_coherent(struct device *dev, size_t size,
+                                    void *cpu_addr, dma_addr_t dma_handle)
+{
+       dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+}
+
+static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+                                       size_t size,
+                                       enum dma_data_direction direction)
+{
+       return dma_ops->map_page(dev, virt_to_page(cpu_addr),
+                                (unsigned long)cpu_addr & ~PAGE_MASK, size,
+                                direction);
+}
+
+static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+                                   size_t size,
+                                   enum dma_data_direction direction)
+{
+       dma_ops->unmap_page(dev, dma_addr, size, direction);
+}
+
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+                                     unsigned long offset, size_t size,
+                                     enum dma_data_direction direction)
+{
+       return dma_ops->map_page(dev, page, offset, size, direction);
+}
+
+static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+                                 size_t size,
+                                 enum dma_data_direction direction)
+{
+       dma_ops->unmap_page(dev, dma_address, size, direction);
+}
+
+static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
+                            int nents, enum dma_data_direction direction)
+{
+       return dma_ops->map_sg(dev, sg, nents, direction);
+}
+
+static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+                               int nents, enum dma_data_direction direction)
+{
+       dma_ops->unmap_sg(dev, sg, nents, direction);
+}
+
+static inline void dma_sync_single_for_cpu(struct device *dev,
+                                          dma_addr_t dma_handle, size_t size,
+                                          enum dma_data_direction direction)
+{
+       dma_ops->sync_single_for_cpu(dev, dma_handle, size, direction);
+}
+
+static inline void dma_sync_single_for_device(struct device *dev,
+                                             dma_addr_t dma_handle,
+                                             size_t size,
+                                             enum dma_data_direction direction)
+{
+       if (dma_ops->sync_single_for_device)
+               dma_ops->sync_single_for_device(dev, dma_handle, size,
+                                               direction);
+}
+
+static inline void dma_sync_sg_for_cpu(struct device *dev,
+                                      struct scatterlist *sg, int nelems,
+                                      enum dma_data_direction direction)
+{
+       dma_ops->sync_sg_for_cpu(dev, sg, nelems, direction);
+}
+
+static inline void dma_sync_sg_for_device(struct device *dev,
+                                         struct scatterlist *sg, int nelems,
+                                         enum dma_data_direction direction)
+{
+       if (dma_ops->sync_sg_for_device)
+               dma_ops->sync_sg_for_device(dev, sg, nelems, direction);
+}
+
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+                                                dma_addr_t dma_handle,
+                                                unsigned long offset,
+                                                size_t size,
+                                                enum dma_data_direction dir)
+{
+       dma_sync_single_for_cpu(dev, dma_handle+offset, size, dir);
+}
+
+static inline void dma_sync_single_range_for_device(struct device *dev,
+                                                   dma_addr_t dma_handle,
+                                                   unsigned long offset,
+                                                   size_t size,
+                                                   enum dma_data_direction dir)
+{
+       dma_sync_single_for_device(dev, dma_handle+offset, size, dir);
+}
+
+
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return (dma_addr == DMA_ERROR_CODE);
+}
+
+static inline int dma_get_cache_alignment(void)
+{
+       /*
+        * no easy way to get cache size on all processors, so return
+        * the maximum possible, to be safe
+        */
+       return (1 << INTERNODE_CACHE_SHIFT);
+}
+
 #endif
diff --git a/arch/sparc/include/asm/dma-mapping_32.h b/arch/sparc/include/asm/dma-mapping_32.h
deleted file mode 100644 (file)
index 8a57ea0..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef _ASM_SPARC_DMA_MAPPING_H
-#define _ASM_SPARC_DMA_MAPPING_H
-
-#include <linux/types.h>
-
-struct device;
-struct scatterlist;
-struct page;
-
-#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
-
-extern int dma_supported(struct device *dev, u64 mask);
-extern int dma_set_mask(struct device *dev, u64 dma_mask);
-extern void *dma_alloc_coherent(struct device *dev, size_t size,
-                               dma_addr_t *dma_handle, gfp_t flag);
-extern void dma_free_coherent(struct device *dev, size_t size,
-                             void *cpu_addr, dma_addr_t dma_handle);
-extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
-                                size_t size,
-                                enum dma_data_direction direction);
-extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-                            size_t size,
-                            enum dma_data_direction direction);
-extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
-                              unsigned long offset, size_t size,
-                              enum dma_data_direction direction);
-extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-                          size_t size, enum dma_data_direction direction);
-extern int dma_map_sg(struct device *dev, struct scatterlist *sg,
-                     int nents, enum dma_data_direction direction);
-extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-                        int nents, enum dma_data_direction direction);
-extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-                                   size_t size,
-                                   enum dma_data_direction direction);
-extern void dma_sync_single_for_device(struct device *dev,
-                                      dma_addr_t dma_handle,
-                                      size_t size,
-                                      enum dma_data_direction direction);
-extern void dma_sync_single_range_for_cpu(struct device *dev,
-                                         dma_addr_t dma_handle,
-                                         unsigned long offset,
-                                         size_t size,
-                                         enum dma_data_direction direction);
-extern void dma_sync_single_range_for_device(struct device *dev,
-                                            dma_addr_t dma_handle,
-                                            unsigned long offset, size_t size,
-                                            enum dma_data_direction direction);
-extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-                               int nelems, enum dma_data_direction direction);
-extern void dma_sync_sg_for_device(struct device *dev,
-                                  struct scatterlist *sg, int nelems,
-                                  enum dma_data_direction direction);
-extern int dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
-extern int dma_get_cache_alignment(void);
-
-#define dma_alloc_noncoherent  dma_alloc_coherent
-#define dma_free_noncoherent   dma_free_coherent
-
-#endif /* _ASM_SPARC_DMA_MAPPING_H */
diff --git a/arch/sparc/include/asm/dma-mapping_64.h b/arch/sparc/include/asm/dma-mapping_64.h
deleted file mode 100644 (file)
index bfa64f9..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-#ifndef _ASM_SPARC64_DMA_MAPPING_H
-#define _ASM_SPARC64_DMA_MAPPING_H
-
-#include <linux/scatterlist.h>
-#include <linux/mm.h>
-
-#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
-
-struct dma_ops {
-       void *(*alloc_coherent)(struct device *dev, size_t size,
-                               dma_addr_t *dma_handle, gfp_t flag);
-       void (*free_coherent)(struct device *dev, size_t size,
-                             void *cpu_addr, dma_addr_t dma_handle);
-       dma_addr_t (*map_single)(struct device *dev, void *cpu_addr,
-                                size_t size,
-                                enum dma_data_direction direction);
-       void (*unmap_single)(struct device *dev, dma_addr_t dma_addr,
-                            size_t size,
-                            enum dma_data_direction direction);
-       int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents,
-                     enum dma_data_direction direction);
-       void (*unmap_sg)(struct device *dev, struct scatterlist *sg,
-                        int nhwentries,
-                        enum dma_data_direction direction);
-       void (*sync_single_for_cpu)(struct device *dev,
-                                   dma_addr_t dma_handle, size_t size,
-                                   enum dma_data_direction direction);
-       void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg,
-                               int nelems,
-                               enum dma_data_direction direction);
-};
-extern const struct dma_ops *dma_ops;
-
-extern int dma_supported(struct device *dev, u64 mask);
-extern int dma_set_mask(struct device *dev, u64 dma_mask);
-
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-                                      dma_addr_t *dma_handle, gfp_t flag)
-{
-       return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
-}
-
-static inline void dma_free_coherent(struct device *dev, size_t size,
-                                    void *cpu_addr, dma_addr_t dma_handle)
-{
-       dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
-}
-
-static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
-                                       size_t size,
-                                       enum dma_data_direction direction)
-{
-       return dma_ops->map_single(dev, cpu_addr, size, direction);
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-                                   size_t size,
-                                   enum dma_data_direction direction)
-{
-       dma_ops->unmap_single(dev, dma_addr, size, direction);
-}
-
-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
-                                     unsigned long offset, size_t size,
-                                     enum dma_data_direction direction)
-{
-       return dma_ops->map_single(dev, page_address(page) + offset,
-                                  size, direction);
-}
-
-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-                                 size_t size,
-                                 enum dma_data_direction direction)
-{
-       dma_ops->unmap_single(dev, dma_address, size, direction);
-}
-
-static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
-                            int nents, enum dma_data_direction direction)
-{
-       return dma_ops->map_sg(dev, sg, nents, direction);
-}
-
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-                               int nents, enum dma_data_direction direction)
-{
-       dma_ops->unmap_sg(dev, sg, nents, direction);
-}
-
-static inline void dma_sync_single_for_cpu(struct device *dev,
-                                          dma_addr_t dma_handle, size_t size,
-                                          enum dma_data_direction direction)
-{
-       dma_ops->sync_single_for_cpu(dev, dma_handle, size, direction);
-}
-
-static inline void dma_sync_single_for_device(struct device *dev,
-                                             dma_addr_t dma_handle,
-                                             size_t size,
-                                             enum dma_data_direction direction)
-{
-       /* No flushing needed to sync cpu writes to the device.  */
-}
-
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
-                                                dma_addr_t dma_handle,
-                                                unsigned long offset,
-                                                size_t size,
-                                                enum dma_data_direction direction)
-{
-       dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
-}
-
-static inline void dma_sync_single_range_for_device(struct device *dev,
-                                                   dma_addr_t dma_handle,
-                                                   unsigned long offset,
-                                                   size_t size,
-                                                   enum dma_data_direction direction)
-{
-       /* No flushing needed to sync cpu writes to the device.  */
-}
-
-
-static inline void dma_sync_sg_for_cpu(struct device *dev,
-                                      struct scatterlist *sg, int nelems,
-                                      enum dma_data_direction direction)
-{
-       dma_ops->sync_sg_for_cpu(dev, sg, nelems, direction);
-}
-
-static inline void dma_sync_sg_for_device(struct device *dev,
-                                         struct scatterlist *sg, int nelems,
-                                         enum dma_data_direction direction)
-{
-       /* No flushing needed to sync cpu writes to the device.  */
-}
-
-static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       return (dma_addr == DMA_ERROR_CODE);
-}
-
-static inline int dma_get_cache_alignment(void)
-{
-       /* no easy way to get cache size on all processors, so return
-        * the maximum possible, to be safe */
-       return (1 << INTERNODE_CACHE_SHIFT);
-}
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-#define dma_is_consistent(d, h)        (1)
-
-#endif /* _ASM_SPARC64_DMA_MAPPING_H */
index d27716cd38c1ac0243a74104f3106850d24397b1..b0f18e9893db5a77cbc45e221a8159e3dc4f2fc5 100644 (file)
@@ -11,4 +11,15 @@ extern void _mcount(void);
 
 #endif
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+/* reloction of mcount call site is the same as the address */
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+       return addr;
+}
+
+struct dyn_arch_ftrace {
+};
+#endif /*  CONFIG_DYNAMIC_FTRACE */
+
 #endif /* _ASM_SPARC64_FTRACE */
index 1acc7272e537bca1bfe095ea24e518b32d837a9b..9faa046713fbaf3f6491a4dc3afca964849d9912 100644 (file)
@@ -71,7 +71,8 @@ struct mdesc_notifier_client {
 
 extern void mdesc_register_notifier(struct mdesc_notifier_client *client);
 
-extern void mdesc_fill_in_cpu_data(cpumask_t mask);
+extern void mdesc_fill_in_cpu_data(cpumask_t *mask);
+extern void mdesc_populate_present_mask(cpumask_t *mask);
 
 extern void sun4v_mdesc_init(void);
 
index bee64593023e2f34d0be046dcddd47d5e3167e60..007aafb4ae97e4914dbfeba584795680d41b6adf 100644 (file)
@@ -7,20 +7,16 @@ register unsigned long __local_per_cpu_offset asm("g5");
 
 #ifdef CONFIG_SMP
 
-extern void real_setup_per_cpu_areas(void);
+#include <asm/trap_block.h>
 
-extern unsigned long __per_cpu_base;
-extern unsigned long __per_cpu_shift;
 #define __per_cpu_offset(__cpu) \
-       (__per_cpu_base + ((unsigned long)(__cpu) << __per_cpu_shift))
+       (trap_block[(__cpu)].__per_cpu_base)
 #define per_cpu_offset(x) (__per_cpu_offset(x))
 
 #define __my_cpu_offset __local_per_cpu_offset
 
 #else /* ! SMP */
 
-#define real_setup_per_cpu_areas()             do { } while (0)
-
 #endif /* SMP */
 
 #include <asm-generic/percpu.h>
index 900d44714f8dd8525776a17cdd4e40e2d2bf7a3e..be8d7aaeb60d104563e4c88936da08d7c284828a 100644 (file)
@@ -86,6 +86,8 @@ extern int of_node_to_nid(struct device_node *dp);
 #endif
 
 extern void prom_build_devicetree(void);
+extern void of_populate_present_mask(void);
+extern void of_fill_in_cpu_data(void);
 
 /* Dummy ref counting routines - to be implemented later */
 static inline struct device_node *of_node_get(struct device_node *node)
diff --git a/arch/sparc/include/asm/trap_block.h b/arch/sparc/include/asm/trap_block.h
new file mode 100644 (file)
index 0000000..7e26b2d
--- /dev/null
@@ -0,0 +1,207 @@
+#ifndef _SPARC_TRAP_BLOCK_H
+#define _SPARC_TRAP_BLOCK_H
+
+#include <asm/hypervisor.h>
+#include <asm/asi.h>
+
+#ifndef __ASSEMBLY__
+
+/* Trap handling code needs to get at a few critical values upon
+ * trap entry and to process TSB misses.  These cannot be in the
+ * per_cpu() area as we really need to lock them into the TLB and
+ * thus make them part of the main kernel image.  As a result we
+ * try to make this as small as possible.
+ *
+ * This is padded out and aligned to 64-bytes to avoid false sharing
+ * on SMP.
+ */
+
+/* If you modify the size of this structure, please update
+ * TRAP_BLOCK_SZ_SHIFT below.
+ */
+struct thread_info;
+struct trap_per_cpu {
+/* D-cache line 1: Basic thread information, cpu and device mondo queues */
+       struct thread_info      *thread;
+       unsigned long           pgd_paddr;
+       unsigned long           cpu_mondo_pa;
+       unsigned long           dev_mondo_pa;
+
+/* D-cache line 2: Error Mondo Queue and kernel buffer pointers */
+       unsigned long           resum_mondo_pa;
+       unsigned long           resum_kernel_buf_pa;
+       unsigned long           nonresum_mondo_pa;
+       unsigned long           nonresum_kernel_buf_pa;
+
+/* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */
+       struct hv_fault_status  fault_info;
+
+/* Dcache line 7: Physical addresses of CPU send mondo block and CPU list.  */
+       unsigned long           cpu_mondo_block_pa;
+       unsigned long           cpu_list_pa;
+       unsigned long           tsb_huge;
+       unsigned long           tsb_huge_temp;
+
+/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size.  */
+       unsigned long           irq_worklist_pa;
+       unsigned int            cpu_mondo_qmask;
+       unsigned int            dev_mondo_qmask;
+       unsigned int            resum_qmask;
+       unsigned int            nonresum_qmask;
+       unsigned long           __per_cpu_base;
+} __attribute__((aligned(64)));
+extern struct trap_per_cpu trap_block[NR_CPUS];
+extern void init_cur_cpu_trap(struct thread_info *);
+extern void setup_tba(void);
+extern int ncpus_probed;
+
+extern unsigned long real_hard_smp_processor_id(void);
+
+struct cpuid_patch_entry {
+       unsigned int    addr;
+       unsigned int    cheetah_safari[4];
+       unsigned int    cheetah_jbus[4];
+       unsigned int    starfire[4];
+       unsigned int    sun4v[4];
+};
+extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
+
+struct sun4v_1insn_patch_entry {
+       unsigned int    addr;
+       unsigned int    insn;
+};
+extern struct sun4v_1insn_patch_entry __sun4v_1insn_patch,
+       __sun4v_1insn_patch_end;
+
+struct sun4v_2insn_patch_entry {
+       unsigned int    addr;
+       unsigned int    insns[2];
+};
+extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
+       __sun4v_2insn_patch_end;
+
+
+#endif /* !(__ASSEMBLY__) */
+
+#define TRAP_PER_CPU_THREAD            0x00
+#define TRAP_PER_CPU_PGD_PADDR         0x08
+#define TRAP_PER_CPU_CPU_MONDO_PA      0x10
+#define TRAP_PER_CPU_DEV_MONDO_PA      0x18
+#define TRAP_PER_CPU_RESUM_MONDO_PA    0x20
+#define TRAP_PER_CPU_RESUM_KBUF_PA     0x28
+#define TRAP_PER_CPU_NONRESUM_MONDO_PA 0x30
+#define TRAP_PER_CPU_NONRESUM_KBUF_PA  0x38
+#define TRAP_PER_CPU_FAULT_INFO                0x40
+#define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA        0xc0
+#define TRAP_PER_CPU_CPU_LIST_PA       0xc8
+#define TRAP_PER_CPU_TSB_HUGE          0xd0
+#define TRAP_PER_CPU_TSB_HUGE_TEMP     0xd8
+#define TRAP_PER_CPU_IRQ_WORKLIST_PA   0xe0
+#define TRAP_PER_CPU_CPU_MONDO_QMASK   0xe8
+#define TRAP_PER_CPU_DEV_MONDO_QMASK   0xec
+#define TRAP_PER_CPU_RESUM_QMASK       0xf0
+#define TRAP_PER_CPU_NONRESUM_QMASK    0xf4
+#define TRAP_PER_CPU_PER_CPU_BASE      0xf8
+
+#define TRAP_BLOCK_SZ_SHIFT            8
+
+#include <asm/scratchpad.h>
+
+#define __GET_CPUID(REG)                               \
+       /* Spitfire implementation (default). */        \
+661:   ldxa            [%g0] ASI_UPA_CONFIG, REG;      \
+       srlx            REG, 17, REG;                   \
+        and            REG, 0x1f, REG;                 \
+       nop;                                            \
+       .section        .cpuid_patch, "ax";             \
+       /* Instruction location. */                     \
+       .word           661b;                           \
+       /* Cheetah Safari implementation. */            \
+       ldxa            [%g0] ASI_SAFARI_CONFIG, REG;   \
+       srlx            REG, 17, REG;                   \
+       and             REG, 0x3ff, REG;                \
+       nop;                                            \
+       /* Cheetah JBUS implementation. */              \
+       ldxa            [%g0] ASI_JBUS_CONFIG, REG;     \
+       srlx            REG, 17, REG;                   \
+       and             REG, 0x1f, REG;                 \
+       nop;                                            \
+       /* Starfire implementation. */                  \
+       sethi           %hi(0x1fff40000d0 >> 9), REG;   \
+       sllx            REG, 9, REG;                    \
+       or              REG, 0xd0, REG;                 \
+       lduwa           [REG] ASI_PHYS_BYPASS_EC_E, REG;\
+       /* sun4v implementation. */                     \
+       mov             SCRATCHPAD_CPUID, REG;          \
+       ldxa            [REG] ASI_SCRATCHPAD, REG;      \
+       nop;                                            \
+       nop;                                            \
+       .previous;
+
+#ifdef CONFIG_SMP
+
+#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP)                \
+       __GET_CPUID(TMP)                        \
+       sethi   %hi(trap_block), DEST;          \
+       sllx    TMP, TRAP_BLOCK_SZ_SHIFT, TMP;  \
+       or      DEST, %lo(trap_block), DEST;    \
+       add     DEST, TMP, DEST;                \
+
+/* Clobbers TMP, current address space PGD phys address into DEST.  */
+#define TRAP_LOAD_PGD_PHYS(DEST, TMP)          \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       ldx     [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
+
+/* Clobbers TMP, loads local processor's IRQ work area into DEST.  */
+#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP)       \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
+
+/* Clobbers TMP, loads DEST with current thread info pointer.  */
+#define TRAP_LOAD_THREAD_REG(DEST, TMP)                \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       ldx     [DEST + TRAP_PER_CPU_THREAD], DEST;
+
+/* Given the current thread info pointer in THR, load the per-cpu
+ * area base of the current processor into DEST.  REG1, REG2, and REG3 are
+ * clobbered.
+ *
+ * You absolutely cannot use DEST as a temporary in this code.  The
+ * reason is that traps can happen during execution, and return from
+ * trap will load the fully resolved DEST per-cpu base.  This can corrupt
+ * the calculations done by the macro mid-stream.
+ */
+#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) \
+       lduh    [THR + TI_CPU], REG1;                   \
+       sethi   %hi(trap_block), REG2;                  \
+       sllx    REG1, TRAP_BLOCK_SZ_SHIFT, REG1;        \
+       or      REG2, %lo(trap_block), REG2;            \
+       add     REG2, REG1, REG2;                       \
+       ldx     [REG2 + TRAP_PER_CPU_PER_CPU_BASE], DEST;
+
+#else
+
+#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP)                \
+       sethi   %hi(trap_block), DEST;          \
+       or      DEST, %lo(trap_block), DEST;    \
+
+/* Uniprocessor versions, we know the cpuid is zero.  */
+#define TRAP_LOAD_PGD_PHYS(DEST, TMP)          \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       ldx     [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
+
+/* Clobbers TMP, loads local processor's IRQ work area into DEST.  */
+#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP)       \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
+
+#define TRAP_LOAD_THREAD_REG(DEST, TMP)                \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       ldx     [DEST + TRAP_PER_CPU_THREAD], DEST;
+
+/* No per-cpu areas on uniprocessor, so no need to load DEST.  */
+#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3)
+
+#endif /* !(CONFIG_SMP) */
+
+#endif /* _SPARC_TRAP_BLOCK_H */
index b8eb71ef31631794b3e9e2b6e4527d320d44857c..b2c406de7d4fd75e1d00aed701dd2d9807edbaa6 100644 (file)
 #define __NR_accept4           323
 #define __NR_preadv            324
 #define __NR_pwritev           325
+#define __NR_rt_tgsigqueueinfo 326
 
-#define NR_SYSCALLS            326
+#define NR_SYSCALLS            327
 
 #ifdef __32bit_syscall_numbers__
 /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
index 54742e58831c4d78e19bad176145e8ce0bae7d6b..475ce4696acd915d90cbc2e91440cfa469dcff8b 100644 (file)
@@ -37,6 +37,7 @@ obj-y                   += una_asm_$(BITS).o
 obj-$(CONFIG_SPARC32)   += muldiv.o
 obj-y                   += prom_common.o
 obj-y                   += prom_$(BITS).o
+obj-y                   += of_device_common.o
 obj-y                   += of_device_$(BITS).o
 obj-$(CONFIG_SPARC64)   += prom_irqtrans.o
 
@@ -54,6 +55,7 @@ obj-$(CONFIG_SPARC64)   += sstate.o
 obj-$(CONFIG_SPARC64)   += mdesc.o
 obj-$(CONFIG_SPARC64)  += pcr.o
 obj-$(CONFIG_SPARC64)  += nmi.o
+obj-$(CONFIG_SPARC64_SMP) += cpumap.o
 
 # sparc32 do not use GENERIC_HARDIRQS but uses the generic devres implementation
 obj-$(CONFIG_SPARC32)     += devres.o
diff --git a/arch/sparc/kernel/cpumap.c b/arch/sparc/kernel/cpumap.c
new file mode 100644 (file)
index 0000000..7430ed0
--- /dev/null
@@ -0,0 +1,431 @@
+/* cpumap.c: used for optimizing CPU assignment
+ *
+ * Copyright (C) 2009 Hong H. Pham <hong.pham@windriver.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cpumask.h>
+#include <linux/spinlock.h>
+#include <asm/cpudata.h>
+#include "cpumap.h"
+
+
+enum {
+       CPUINFO_LVL_ROOT = 0,
+       CPUINFO_LVL_NODE,
+       CPUINFO_LVL_CORE,
+       CPUINFO_LVL_PROC,
+       CPUINFO_LVL_MAX,
+};
+
+enum {
+       ROVER_NO_OP              = 0,
+       /* Increment rover every time level is visited */
+       ROVER_INC_ON_VISIT       = 1 << 0,
+       /* Increment parent's rover every time rover wraps around */
+       ROVER_INC_PARENT_ON_LOOP = 1 << 1,
+};
+
+struct cpuinfo_node {
+       int id;
+       int level;
+       int num_cpus;    /* Number of CPUs in this hierarchy */
+       int parent_index;
+       int child_start; /* Array index of the first child node */
+       int child_end;   /* Array index of the last child node */
+       int rover;       /* Child node iterator */
+};
+
+struct cpuinfo_level {
+       int start_index; /* Index of first node of a level in a cpuinfo tree */
+       int end_index;   /* Index of last node of a level in a cpuinfo tree */
+       int num_nodes;   /* Number of nodes in a level in a cpuinfo tree */
+};
+
+struct cpuinfo_tree {
+       int total_nodes;
+
+       /* Offsets into nodes[] for each level of the tree */
+       struct cpuinfo_level level[CPUINFO_LVL_MAX];
+       struct cpuinfo_node  nodes[0];
+};
+
+
+static struct cpuinfo_tree *cpuinfo_tree;
+
+static u16 cpu_distribution_map[NR_CPUS];
+static DEFINE_SPINLOCK(cpu_map_lock);
+
+
+/* Niagara optimized cpuinfo tree traversal. */
+static const int niagara_iterate_method[] = {
+       [CPUINFO_LVL_ROOT] = ROVER_NO_OP,
+
+       /* Strands (or virtual CPUs) within a core may not run concurrently
+        * on the Niagara, as instruction pipeline(s) are shared.  Distribute
+        * work to strands in different cores first for better concurrency.
+        * Go to next NUMA node when all cores are used.
+        */
+       [CPUINFO_LVL_NODE] = ROVER_INC_ON_VISIT|ROVER_INC_PARENT_ON_LOOP,
+
+       /* Strands are grouped together by proc_id in cpuinfo_sparc, i.e.
+        * a proc_id represents an instruction pipeline.  Distribute work to
+        * strands in different proc_id groups if the core has multiple
+        * instruction pipelines (e.g. the Niagara 2/2+ has two).
+        */
+       [CPUINFO_LVL_CORE] = ROVER_INC_ON_VISIT,
+
+       /* Pick the next strand in the proc_id group. */
+       [CPUINFO_LVL_PROC] = ROVER_INC_ON_VISIT,
+};
+
+/* Generic cpuinfo tree traversal.  Distribute work round robin across NUMA
+ * nodes.
+ */
+static const int generic_iterate_method[] = {
+       [CPUINFO_LVL_ROOT] = ROVER_INC_ON_VISIT,
+       [CPUINFO_LVL_NODE] = ROVER_NO_OP,
+       [CPUINFO_LVL_CORE] = ROVER_INC_PARENT_ON_LOOP,
+       [CPUINFO_LVL_PROC] = ROVER_INC_ON_VISIT|ROVER_INC_PARENT_ON_LOOP,
+};
+
+
+static int cpuinfo_id(int cpu, int level)
+{
+       int id;
+
+       switch (level) {
+       case CPUINFO_LVL_ROOT:
+               id = 0;
+               break;
+       case CPUINFO_LVL_NODE:
+               id = cpu_to_node(cpu);
+               break;
+       case CPUINFO_LVL_CORE:
+               id = cpu_data(cpu).core_id;
+               break;
+       case CPUINFO_LVL_PROC:
+               id = cpu_data(cpu).proc_id;
+               break;
+       default:
+               id = -EINVAL;
+       }
+       return id;
+}
+
+/*
+ * Enumerate the CPU information in __cpu_data to determine the start index,
+ * end index, and number of nodes for each level in the cpuinfo tree.  The
+ * total number of cpuinfo nodes required to build the tree is returned.
+ */
+static int enumerate_cpuinfo_nodes(struct cpuinfo_level *tree_level)
+{
+       int prev_id[CPUINFO_LVL_MAX];
+       int i, n, num_nodes;
+
+       for (i = CPUINFO_LVL_ROOT; i < CPUINFO_LVL_MAX; i++) {
+               struct cpuinfo_level *lv = &tree_level[i];
+
+               prev_id[i] = -1;
+               lv->start_index = lv->end_index = lv->num_nodes = 0;
+       }
+
+       num_nodes = 1; /* Include the root node */
+
+       for (i = 0; i < num_possible_cpus(); i++) {
+               if (!cpu_online(i))
+                       continue;
+
+               n = cpuinfo_id(i, CPUINFO_LVL_NODE);
+               if (n > prev_id[CPUINFO_LVL_NODE]) {
+                       tree_level[CPUINFO_LVL_NODE].num_nodes++;
+                       prev_id[CPUINFO_LVL_NODE] = n;
+                       num_nodes++;
+               }
+               n = cpuinfo_id(i, CPUINFO_LVL_CORE);
+               if (n > prev_id[CPUINFO_LVL_CORE]) {
+                       tree_level[CPUINFO_LVL_CORE].num_nodes++;
+                       prev_id[CPUINFO_LVL_CORE] = n;
+                       num_nodes++;
+               }
+               n = cpuinfo_id(i, CPUINFO_LVL_PROC);
+               if (n > prev_id[CPUINFO_LVL_PROC]) {
+                       tree_level[CPUINFO_LVL_PROC].num_nodes++;
+                       prev_id[CPUINFO_LVL_PROC] = n;
+                       num_nodes++;
+               }
+       }
+
+       tree_level[CPUINFO_LVL_ROOT].num_nodes = 1;
+
+       n = tree_level[CPUINFO_LVL_NODE].num_nodes;
+       tree_level[CPUINFO_LVL_NODE].start_index = 1;
+       tree_level[CPUINFO_LVL_NODE].end_index   = n;
+
+       n++;
+       tree_level[CPUINFO_LVL_CORE].start_index = n;
+       n += tree_level[CPUINFO_LVL_CORE].num_nodes;
+       tree_level[CPUINFO_LVL_CORE].end_index   = n - 1;
+
+       tree_level[CPUINFO_LVL_PROC].start_index = n;
+       n += tree_level[CPUINFO_LVL_PROC].num_nodes;
+       tree_level[CPUINFO_LVL_PROC].end_index   = n - 1;
+
+       return num_nodes;
+}
+
+/* Build a tree representation of the CPU hierarchy using the per CPU
+ * information in __cpu_data.  Entries in __cpu_data[0..NR_CPUS] are
+ * assumed to be sorted in ascending order based on node, core_id, and
+ * proc_id (in order of significance).
+ */
+static struct cpuinfo_tree *build_cpuinfo_tree(void)
+{
+       struct cpuinfo_tree *new_tree;
+       struct cpuinfo_node *node;
+       struct cpuinfo_level tmp_level[CPUINFO_LVL_MAX];
+       int num_cpus[CPUINFO_LVL_MAX];
+       int level_rover[CPUINFO_LVL_MAX];
+       int prev_id[CPUINFO_LVL_MAX];
+       int n, id, cpu, prev_cpu, last_cpu, level;
+
+       n = enumerate_cpuinfo_nodes(tmp_level);
+
+       new_tree = kzalloc(sizeof(struct cpuinfo_tree) +
+                          (sizeof(struct cpuinfo_node) * n), GFP_ATOMIC);
+       if (!new_tree)
+               return NULL;
+
+       new_tree->total_nodes = n;
+       memcpy(&new_tree->level, tmp_level, sizeof(tmp_level));
+
+       prev_cpu = cpu = first_cpu(cpu_online_map);
+
+       /* Initialize all levels in the tree with the first CPU */
+       for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT; level--) {
+               n = new_tree->level[level].start_index;
+
+               level_rover[level] = n;
+               node = &new_tree->nodes[n];
+
+               id = cpuinfo_id(cpu, level);
+               if (unlikely(id < 0)) {
+                       kfree(new_tree);
+                       return NULL;
+               }
+               node->id = id;
+               node->level = level;
+               node->num_cpus = 1;
+
+               node->parent_index = (level > CPUINFO_LVL_ROOT)
+                   ? new_tree->level[level - 1].start_index : -1;
+
+               node->child_start = node->child_end = node->rover =
+                   (level == CPUINFO_LVL_PROC)
+                   ? cpu : new_tree->level[level + 1].start_index;
+
+               prev_id[level] = node->id;
+               num_cpus[level] = 1;
+       }
+
+       for (last_cpu = (num_possible_cpus() - 1); last_cpu >= 0; last_cpu--) {
+               if (cpu_online(last_cpu))
+                       break;
+       }
+
+       while (++cpu <= last_cpu) {
+               if (!cpu_online(cpu))
+                       continue;
+
+               for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT;
+                    level--) {
+                       id = cpuinfo_id(cpu, level);
+                       if (unlikely(id < 0)) {
+                               kfree(new_tree);
+                               return NULL;
+                       }
+
+                       if ((id != prev_id[level]) || (cpu == last_cpu)) {
+                               prev_id[level] = id;
+                               node = &new_tree->nodes[level_rover[level]];
+                               node->num_cpus = num_cpus[level];
+                               num_cpus[level] = 1;
+
+                               if (cpu == last_cpu)
+                                       node->num_cpus++;
+
+                               /* Connect tree node to parent */
+                               if (level == CPUINFO_LVL_ROOT)
+                                       node->parent_index = -1;
+                               else
+                                       node->parent_index =
+                                           level_rover[level - 1];
+
+                               if (level == CPUINFO_LVL_PROC) {
+                                       node->child_end =
+                                           (cpu == last_cpu) ? cpu : prev_cpu;
+                               } else {
+                                       node->child_end =
+                                           level_rover[level + 1] - 1;
+                               }
+
+                               /* Initialize the next node in the same level */
+                               n = ++level_rover[level];
+                               if (n <= new_tree->level[level].end_index) {
+                                       node = &new_tree->nodes[n];
+                                       node->id = id;
+                                       node->level = level;
+
+                                       /* Connect node to child */
+                                       node->child_start = node->child_end =
+                                       node->rover =
+                                           (level == CPUINFO_LVL_PROC)
+                                           ? cpu : level_rover[level + 1];
+                               }
+                       } else
+                               num_cpus[level]++;
+               }
+               prev_cpu = cpu;
+       }
+
+       return new_tree;
+}
+
+static void increment_rover(struct cpuinfo_tree *t, int node_index,
+                            int root_index, const int *rover_inc_table)
+{
+       struct cpuinfo_node *node = &t->nodes[node_index];
+       int top_level, level;
+
+       top_level = t->nodes[root_index].level;
+       for (level = node->level; level >= top_level; level--) {
+               node->rover++;
+               if (node->rover <= node->child_end)
+                       return;
+
+               node->rover = node->child_start;
+               /* If parent's rover does not need to be adjusted, stop here. */
+               if ((level == top_level) ||
+                   !(rover_inc_table[level] & ROVER_INC_PARENT_ON_LOOP))
+                       return;
+
+               node = &t->nodes[node->parent_index];
+       }
+}
+
+static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)
+{
+       const int *rover_inc_table;
+       int level, new_index, index = root_index;
+
+       switch (sun4v_chip_type) {
+       case SUN4V_CHIP_NIAGARA1:
+       case SUN4V_CHIP_NIAGARA2:
+               rover_inc_table = niagara_iterate_method;
+               break;
+       default:
+               rover_inc_table = generic_iterate_method;
+       }
+
+       for (level = t->nodes[root_index].level; level < CPUINFO_LVL_MAX;
+            level++) {
+               new_index = t->nodes[index].rover;
+               if (rover_inc_table[level] & ROVER_INC_ON_VISIT)
+                       increment_rover(t, index, root_index, rover_inc_table);
+
+               index = new_index;
+       }
+       return index;
+}
+
+static void _cpu_map_rebuild(void)
+{
+       int i;
+
+       if (cpuinfo_tree) {
+               kfree(cpuinfo_tree);
+               cpuinfo_tree = NULL;
+       }
+
+       cpuinfo_tree = build_cpuinfo_tree();
+       if (!cpuinfo_tree)
+               return;
+
+       /* Build CPU distribution map that spans all online CPUs.  No need
+        * to check if the CPU is online, as that is done when the cpuinfo
+        * tree is being built.
+        */
+       for (i = 0; i < cpuinfo_tree->nodes[0].num_cpus; i++)
+               cpu_distribution_map[i] = iterate_cpu(cpuinfo_tree, 0);
+}
+
+/* Fallback if the cpuinfo tree could not be built.  CPU mapping is linear
+ * round robin.
+ */
+static int simple_map_to_cpu(unsigned int index)
+{
+       int i, end, cpu_rover;
+
+       cpu_rover = 0;
+       end = index % num_online_cpus();
+       for (i = 0; i < num_possible_cpus(); i++) {
+               if (cpu_online(cpu_rover)) {
+                       if (cpu_rover >= end)
+                               return cpu_rover;
+
+                       cpu_rover++;
+               }
+       }
+
+       /* Impossible, since num_online_cpus() <= num_possible_cpus() */
+       return first_cpu(cpu_online_map);
+}
+
+static int _map_to_cpu(unsigned int index)
+{
+       struct cpuinfo_node *root_node;
+
+       if (unlikely(!cpuinfo_tree)) {
+               _cpu_map_rebuild();
+               if (!cpuinfo_tree)
+                       return simple_map_to_cpu(index);
+       }
+
+       root_node = &cpuinfo_tree->nodes[0];
+#ifdef CONFIG_HOTPLUG_CPU
+       if (unlikely(root_node->num_cpus != num_online_cpus())) {
+               _cpu_map_rebuild();
+               if (!cpuinfo_tree)
+                       return simple_map_to_cpu(index);
+       }
+#endif
+       return cpu_distribution_map[index % root_node->num_cpus];
+}
+
+int map_to_cpu(unsigned int index)
+{
+       int mapped_cpu;
+       unsigned long flag;
+
+       spin_lock_irqsave(&cpu_map_lock, flag);
+       mapped_cpu = _map_to_cpu(index);
+
+#ifdef CONFIG_HOTPLUG_CPU
+       while (unlikely(!cpu_online(mapped_cpu)))
+               mapped_cpu = _map_to_cpu(index);
+#endif
+       spin_unlock_irqrestore(&cpu_map_lock, flag);
+       return mapped_cpu;
+}
+EXPORT_SYMBOL(map_to_cpu);
+
+void cpu_map_rebuild(void)
+{
+       unsigned long flag;
+
+       spin_lock_irqsave(&cpu_map_lock, flag);
+       _cpu_map_rebuild();
+       spin_unlock_irqrestore(&cpu_map_lock, flag);
+}
diff --git a/arch/sparc/kernel/cpumap.h b/arch/sparc/kernel/cpumap.h
new file mode 100644 (file)
index 0000000..e639880
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _CPUMAP_H
+#define _CPUMAP_H
+
+#ifdef CONFIG_SMP
+extern void cpu_map_rebuild(void);
+extern int  map_to_cpu(unsigned int index);
+#define cpu_map_init() cpu_map_rebuild()
+#else
+#define cpu_map_init() do {} while (0)
+static inline int map_to_cpu(unsigned int index)
+{
+       return raw_smp_processor_id();
+}
+#endif
+
+#endif
index ebc8403b035ee6b477a62254660e6db8fd48b5bc..524c32f97c555856809f3d9400d9fd76080aaa38 100644 (file)
@@ -35,8 +35,8 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
 }
 EXPORT_SYMBOL(dma_set_mask);
 
-void *dma_alloc_coherent(struct device *dev, size_t size,
-                        dma_addr_t *dma_handle, gfp_t flag)
+static void *dma32_alloc_coherent(struct device *dev, size_t size,
+                                 dma_addr_t *dma_handle, gfp_t flag)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type)
@@ -44,10 +44,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 #endif
        return sbus_alloc_consistent(dev, size, dma_handle);
 }
-EXPORT_SYMBOL(dma_alloc_coherent);
 
-void dma_free_coherent(struct device *dev, size_t size,
-                      void *cpu_addr, dma_addr_t dma_handle)
+static void dma32_free_coherent(struct device *dev, size_t size,
+                               void *cpu_addr, dma_addr_t dma_handle)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -58,38 +57,10 @@ void dma_free_coherent(struct device *dev, size_t size,
 #endif
        sbus_free_consistent(dev, size, cpu_addr, dma_handle);
 }
-EXPORT_SYMBOL(dma_free_coherent);
 
-dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
-                         size_t size, enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-       if (dev->bus == &pci_bus_type)
-               return pci_map_single(to_pci_dev(dev), cpu_addr,
-                                     size, (int)direction);
-#endif
-       return sbus_map_single(dev, cpu_addr, size, (int)direction);
-}
-EXPORT_SYMBOL(dma_map_single);
-
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-                     size_t size,
-                     enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-       if (dev->bus == &pci_bus_type) {
-               pci_unmap_single(to_pci_dev(dev), dma_addr,
-                                size, (int)direction);
-               return;
-       }
-#endif
-       sbus_unmap_single(dev, dma_addr, size, (int)direction);
-}
-EXPORT_SYMBOL(dma_unmap_single);
-
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
-                       unsigned long offset, size_t size,
-                       enum dma_data_direction direction)
+static dma_addr_t dma32_map_page(struct device *dev, struct page *page,
+                                unsigned long offset, size_t size,
+                                enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type)
@@ -99,10 +70,9 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page,
        return sbus_map_single(dev, page_address(page) + offset,
                               size, (int)direction);
 }
-EXPORT_SYMBOL(dma_map_page);
 
-void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-                   size_t size, enum dma_data_direction direction)
+static void dma32_unmap_page(struct device *dev, dma_addr_t dma_address,
+                            size_t size, enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -113,10 +83,9 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
 #endif
        sbus_unmap_single(dev, dma_address, size, (int)direction);
 }
-EXPORT_SYMBOL(dma_unmap_page);
 
-int dma_map_sg(struct device *dev, struct scatterlist *sg,
-                            int nents, enum dma_data_direction direction)
+static int dma32_map_sg(struct device *dev, struct scatterlist *sg,
+                       int nents, enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type)
@@ -124,10 +93,9 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg,
 #endif
        return sbus_map_sg(dev, sg, nents, direction);
 }
-EXPORT_SYMBOL(dma_map_sg);
 
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-                 int nents, enum dma_data_direction direction)
+void dma32_unmap_sg(struct device *dev, struct scatterlist *sg,
+                   int nents, enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -137,10 +105,10 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
 #endif
        sbus_unmap_sg(dev, sg, nents, (int)direction);
 }
-EXPORT_SYMBOL(dma_unmap_sg);
 
-void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-                            size_t size, enum dma_data_direction direction)
+static void dma32_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                                     size_t size,
+                                     enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -151,10 +119,10 @@ void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
 #endif
        sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction);
 }
-EXPORT_SYMBOL(dma_sync_single_for_cpu);
 
-void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-                               size_t size, enum dma_data_direction direction)
+static void dma32_sync_single_for_device(struct device *dev,
+                                        dma_addr_t dma_handle, size_t size,
+                                        enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -165,28 +133,9 @@ void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
 #endif
        sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction);
 }
-EXPORT_SYMBOL(dma_sync_single_for_device);
-
-void dma_sync_single_range_for_cpu(struct device *dev,
-                                  dma_addr_t dma_handle,
-                                  unsigned long offset,
-                                  size_t size,
-                                  enum dma_data_direction direction)
-{
-       dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
-}
-EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
-
-void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-                                     unsigned long offset, size_t size,
-                                     enum dma_data_direction direction)
-{
-       dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
-}
-EXPORT_SYMBOL(dma_sync_single_range_for_device);
 
-void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-                        int nelems, enum dma_data_direction direction)
+static void dma32_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                                 int nelems, enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -197,11 +146,10 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
 #endif
        BUG();
 }
-EXPORT_SYMBOL(dma_sync_sg_for_cpu);
 
-void dma_sync_sg_for_device(struct device *dev,
-                           struct scatterlist *sg, int nelems,
-                           enum dma_data_direction direction)
+static void dma32_sync_sg_for_device(struct device *dev,
+                                    struct scatterlist *sg, int nelems,
+                                    enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -212,16 +160,19 @@ void dma_sync_sg_for_device(struct device *dev,
 #endif
        BUG();
 }
-EXPORT_SYMBOL(dma_sync_sg_for_device);
 
-int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       return (dma_addr == DMA_ERROR_CODE);
-}
-EXPORT_SYMBOL(dma_mapping_error);
-
-int dma_get_cache_alignment(void)
-{
-       return 32;
-}
-EXPORT_SYMBOL(dma_get_cache_alignment);
+static const struct dma_ops dma32_dma_ops = {
+       .alloc_coherent         = dma32_alloc_coherent,
+       .free_coherent          = dma32_free_coherent,
+       .map_page               = dma32_map_page,
+       .unmap_page             = dma32_unmap_page,
+       .map_sg                 = dma32_map_sg,
+       .unmap_sg               = dma32_unmap_sg,
+       .sync_single_for_cpu    = dma32_sync_single_for_cpu,
+       .sync_single_for_device = dma32_sync_single_for_device,
+       .sync_sg_for_cpu        = dma32_sync_sg_for_cpu,
+       .sync_sg_for_device     = dma32_sync_sg_for_device,
+};
+
+const struct dma_ops *dma_ops = &dma32_dma_ops;
+EXPORT_SYMBOL(dma_ops);
index 90350f838f05efa92a9739d4e4a03079f5f0ae55..4a700f4b79cebf068cba0c82ea22dcf6602ba74b 100644 (file)
@@ -544,7 +544,8 @@ static int __cpuinit dr_cpu_configure(struct ds_info *dp,
                             resp_len, ncpus, mask,
                             DR_CPU_STAT_CONFIGURED);
 
-       mdesc_fill_in_cpu_data(*mask);
+       mdesc_populate_present_mask(mask);
+       mdesc_fill_in_cpu_data(mask);
 
        for_each_cpu_mask(cpu, *mask) {
                int err;
index d0218e73f9820b6a478837df8dcd2869f233dcbd..d3b1a3076569890724fdc58a77fd1949ca96a684 100644 (file)
@@ -7,14 +7,10 @@
 
 #include <asm/ftrace.h>
 
+#ifdef CONFIG_DYNAMIC_FTRACE
 static const u32 ftrace_nop = 0x01000000;
 
-unsigned char *ftrace_nop_replace(void)
-{
-       return (char *)&ftrace_nop;
-}
-
-unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
+static u32 ftrace_call_replace(unsigned long ip, unsigned long addr)
 {
        static u32 call;
        s32 off;
@@ -22,15 +18,11 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
        off = ((s32)addr - (s32)ip);
        call = 0x40000000 | ((u32)off >> 2);
 
-       return (unsigned char *) &call;
+       return call;
 }
 
-int
-ftrace_modify_code(unsigned long ip, unsigned char *old_code,
-                  unsigned char *new_code)
+static int ftrace_modify_code(unsigned long ip, u32 old, u32 new)
 {
-       u32 old = *(u32 *)old_code;
-       u32 new = *(u32 *)new_code;
        u32 replaced;
        int faulted;
 
@@ -59,18 +51,43 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
        return faulted;
 }
 
+int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr)
+{
+       unsigned long ip = rec->ip;
+       u32 old, new;
+
+       old = ftrace_call_replace(ip, addr);
+       new = ftrace_nop;
+       return ftrace_modify_code(ip, old, new);
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+       unsigned long ip = rec->ip;
+       u32 old, new;
+
+       old = ftrace_nop;
+       new = ftrace_call_replace(ip, addr);
+       return ftrace_modify_code(ip, old, new);
+}
+
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
        unsigned long ip = (unsigned long)(&ftrace_call);
-       unsigned char old[MCOUNT_INSN_SIZE], *new;
+       u32 old, new;
 
-       memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
+       old = *(u32 *) &ftrace_call;
        new = ftrace_call_replace(ip, (unsigned long)func);
        return ftrace_modify_code(ip, old, new);
 }
 
 int __init ftrace_dyn_arch_init(void *data)
 {
-       ftrace_mcount_set(data);
+       unsigned long *p = data;
+
+       *p = 0;
+
        return 0;
 }
+#endif
+
index 91bf4c7f79b9c6c6acc90fe0ecbb90f503e6a1d5..f8f21050448b8963bc25e23e87a3a4f816bbbea6 100644 (file)
@@ -641,28 +641,6 @@ tlb_fixup_done:
        /* Not reached... */
 
 1:
-       /* If we boot on a non-zero cpu, all of the per-cpu
-        * variable references we make before setting up the
-        * per-cpu areas will use a bogus offset.  Put a
-        * compensating factor into __per_cpu_base to handle
-        * this cleanly.
-        *
-        * What the per-cpu code calculates is:
-        *
-        *      __per_cpu_base + (cpu << __per_cpu_shift)
-        *
-        * These two variables are zero initially, so to
-        * make it all cancel out to zero we need to put
-        * "0 - (cpu << 0)" into __per_cpu_base so that the
-        * above formula evaluates to zero.
-        *
-        * We cannot even perform a printk() until this stuff
-        * is setup as that calls cpu_clock() which uses
-        * per-cpu variables.
-        */
-       sub     %g0, %o0, %o1
-       sethi   %hi(__per_cpu_base), %o2
-       stx     %o1, [%o2 + %lo(__per_cpu_base)]
 #else
        mov     0, %o0
 #endif
index d8900e1d5aad0cbd2253079e0ef927c9465e4fe5..0aeaefe696b9110733f2ceb6af333c7d0a33ab56 100644 (file)
@@ -351,8 +351,9 @@ static void dma_4u_free_coherent(struct device *dev, size_t size,
                free_pages((unsigned long)cpu, order);
 }
 
-static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz,
-                                   enum dma_data_direction direction)
+static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
+                                 unsigned long offset, size_t sz,
+                                 enum dma_data_direction direction)
 {
        struct iommu *iommu;
        struct strbuf *strbuf;
@@ -368,7 +369,7 @@ static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz,
        if (unlikely(direction == DMA_NONE))
                goto bad_no_ctx;
 
-       oaddr = (unsigned long)ptr;
+       oaddr = (unsigned long)(page_address(page) + offset);
        npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
        npages >>= IO_PAGE_SHIFT;
 
@@ -472,8 +473,8 @@ do_flush_sync:
                       vaddr, ctx, npages);
 }
 
-static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr,
-                               size_t sz, enum dma_data_direction direction)
+static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr,
+                             size_t sz, enum dma_data_direction direction)
 {
        struct iommu *iommu;
        struct strbuf *strbuf;
@@ -824,8 +825,8 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev,
 static const struct dma_ops sun4u_dma_ops = {
        .alloc_coherent         = dma_4u_alloc_coherent,
        .free_coherent          = dma_4u_free_coherent,
-       .map_single             = dma_4u_map_single,
-       .unmap_single           = dma_4u_unmap_single,
+       .map_page               = dma_4u_map_page,
+       .unmap_page             = dma_4u_unmap_page,
        .map_sg                 = dma_4u_map_sg,
        .unmap_sg               = dma_4u_unmap_sg,
        .sync_single_for_cpu    = dma_4u_sync_single_for_cpu,
index e5e78f9cfc95d7104ede2ab767fdd1e5401f623c..bd075054942bd900fecb66516b40d02c95becd0e 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/cacheflush.h>
 
 #include "entry.h"
+#include "cpumap.h"
 
 #define NUM_IVECS      (IMAP_INR + 1)
 
@@ -256,35 +257,13 @@ static int irq_choose_cpu(unsigned int virt_irq)
        int cpuid;
 
        cpumask_copy(&mask, irq_desc[virt_irq].affinity);
-       if (cpus_equal(mask, CPU_MASK_ALL)) {
-               static int irq_rover;
-               static DEFINE_SPINLOCK(irq_rover_lock);
-               unsigned long flags;
-
-               /* Round-robin distribution... */
-       do_round_robin:
-               spin_lock_irqsave(&irq_rover_lock, flags);
-
-               while (!cpu_online(irq_rover)) {
-                       if (++irq_rover >= nr_cpu_ids)
-                               irq_rover = 0;
-               }
-               cpuid = irq_rover;
-               do {
-                       if (++irq_rover >= nr_cpu_ids)
-                               irq_rover = 0;
-               } while (!cpu_online(irq_rover));
-
-               spin_unlock_irqrestore(&irq_rover_lock, flags);
+       if (cpus_equal(mask, cpu_online_map)) {
+               cpuid = map_to_cpu(virt_irq);
        } else {
                cpumask_t tmp;
 
                cpus_and(tmp, cpu_online_map, mask);
-
-               if (cpus_empty(tmp))
-                       goto do_round_robin;
-
-               cpuid = first_cpu(tmp);
+               cpuid = cpus_empty(tmp) ? map_to_cpu(virt_irq) : first_cpu(tmp);
        }
 
        return cpuid;
index f0e6ed23a468ec10c6b7ba78ad8d5890295f7f82..938da19dc06527d755d7ce0a9cc8171b39f654c7 100644 (file)
@@ -574,7 +574,7 @@ static void __init report_platform_properties(void)
        mdesc_release(hp);
 }
 
-static void __devinit fill_in_one_cache(cpuinfo_sparc *c,
+static void __cpuinit fill_in_one_cache(cpuinfo_sparc *c,
                                        struct mdesc_handle *hp,
                                        u64 mp)
 {
@@ -619,8 +619,7 @@ static void __devinit fill_in_one_cache(cpuinfo_sparc *c,
        }
 }
 
-static void __devinit mark_core_ids(struct mdesc_handle *hp, u64 mp,
-                                   int core_id)
+static void __cpuinit mark_core_ids(struct mdesc_handle *hp, u64 mp, int core_id)
 {
        u64 a;
 
@@ -653,7 +652,7 @@ static void __devinit mark_core_ids(struct mdesc_handle *hp, u64 mp,
        }
 }
 
-static void __devinit set_core_ids(struct mdesc_handle *hp)
+static void __cpuinit set_core_ids(struct mdesc_handle *hp)
 {
        int idx;
        u64 mp;
@@ -678,8 +677,7 @@ static void __devinit set_core_ids(struct mdesc_handle *hp)
        }
 }
 
-static void __devinit mark_proc_ids(struct mdesc_handle *hp, u64 mp,
-                                   int proc_id)
+static void __cpuinit mark_proc_ids(struct mdesc_handle *hp, u64 mp, int proc_id)
 {
        u64 a;
 
@@ -698,8 +696,7 @@ static void __devinit mark_proc_ids(struct mdesc_handle *hp, u64 mp,
        }
 }
 
-static void __devinit __set_proc_ids(struct mdesc_handle *hp,
-                                    const char *exec_unit_name)
+static void __cpuinit __set_proc_ids(struct mdesc_handle *hp, const char *exec_unit_name)
 {
        int idx;
        u64 mp;
@@ -720,13 +717,13 @@ static void __devinit __set_proc_ids(struct mdesc_handle *hp,
        }
 }
 
-static void __devinit set_proc_ids(struct mdesc_handle *hp)
+static void __cpuinit set_proc_ids(struct mdesc_handle *hp)
 {
        __set_proc_ids(hp, "exec_unit");
        __set_proc_ids(hp, "exec-unit");
 }
 
-static void __devinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
+static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
                                         unsigned char def)
 {
        u64 val;
@@ -745,7 +742,7 @@ use_default:
        *mask = ((1U << def) * 64U) - 1U;
 }
 
-static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
+static void __cpuinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
                                     struct trap_per_cpu *tb)
 {
        const u64 *val;
@@ -763,23 +760,15 @@ static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
        get_one_mondo_bits(val, &tb->nonresum_qmask, 2);
 }
 
-void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask)
+static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handle *, u64, int, void *), void *arg, cpumask_t *mask)
 {
        struct mdesc_handle *hp = mdesc_grab();
+       void *ret = NULL;
        u64 mp;
 
-       ncpus_probed = 0;
        mdesc_for_each_node_by_name(hp, mp, "cpu") {
                const u64 *id = mdesc_get_property(hp, mp, "id", NULL);
-               const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL);
-               struct trap_per_cpu *tb;
-               cpuinfo_sparc *c;
-               int cpuid;
-               u64 a;
-
-               ncpus_probed++;
-
-               cpuid = *id;
+               int cpuid = *id;
 
 #ifdef CONFIG_SMP
                if (cpuid >= NR_CPUS) {
@@ -788,62 +777,104 @@ void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask)
                               cpuid, NR_CPUS);
                        continue;
                }
-               if (!cpu_isset(cpuid, mask))
+               if (!cpu_isset(cpuid, *mask))
                        continue;
-#else
-               /* On uniprocessor we only want the values for the
-                * real physical cpu the kernel booted onto, however
-                * cpu_data() only has one entry at index 0.
-                */
-               if (cpuid != real_hard_smp_processor_id())
-                       continue;
-               cpuid = 0;
 #endif
 
-               c = &cpu_data(cpuid);
-               c->clock_tick = *cfreq;
+               ret = func(hp, mp, cpuid, arg);
+               if (ret)
+                       goto out;
+       }
+out:
+       mdesc_release(hp);
+       return ret;
+}
 
-               tb = &trap_block[cpuid];
-               get_mondo_data(hp, mp, tb);
+static void * __cpuinit record_one_cpu(struct mdesc_handle *hp, u64 mp, int cpuid, void *arg)
+{
+       ncpus_probed++;
+#ifdef CONFIG_SMP
+       set_cpu_present(cpuid, true);
+#endif
+       return NULL;
+}
 
-               mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
-                       u64 j, t = mdesc_arc_target(hp, a);
-                       const char *t_name;
+void __cpuinit mdesc_populate_present_mask(cpumask_t *mask)
+{
+       if (tlb_type != hypervisor)
+               return;
 
-                       t_name = mdesc_node_name(hp, t);
-                       if (!strcmp(t_name, "cache")) {
-                               fill_in_one_cache(c, hp, t);
-                               continue;
-                       }
+       ncpus_probed = 0;
+       mdesc_iterate_over_cpus(record_one_cpu, NULL, mask);
+}
 
-                       mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) {
-                               u64 n = mdesc_arc_target(hp, j);
-                               const char *n_name;
+static void * __cpuinit fill_in_one_cpu(struct mdesc_handle *hp, u64 mp, int cpuid, void *arg)
+{
+       const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL);
+       struct trap_per_cpu *tb;
+       cpuinfo_sparc *c;
+       u64 a;
 
-                               n_name = mdesc_node_name(hp, n);
-                               if (!strcmp(n_name, "cache"))
-                                       fill_in_one_cache(c, hp, n);
-                       }
+#ifndef CONFIG_SMP
+       /* On uniprocessor we only want the values for the
+        * real physical cpu the kernel booted onto, however
+        * cpu_data() only has one entry at index 0.
+        */
+       if (cpuid != real_hard_smp_processor_id())
+               return NULL;
+       cpuid = 0;
+#endif
+
+       c = &cpu_data(cpuid);
+       c->clock_tick = *cfreq;
+
+       tb = &trap_block[cpuid];
+       get_mondo_data(hp, mp, tb);
+
+       mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
+               u64 j, t = mdesc_arc_target(hp, a);
+               const char *t_name;
+
+               t_name = mdesc_node_name(hp, t);
+               if (!strcmp(t_name, "cache")) {
+                       fill_in_one_cache(c, hp, t);
+                       continue;
                }
 
-#ifdef CONFIG_SMP
-               cpu_set(cpuid, cpu_present_map);
-#endif
+               mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) {
+                       u64 n = mdesc_arc_target(hp, j);
+                       const char *n_name;
 
-               c->core_id = 0;
-               c->proc_id = -1;
+                       n_name = mdesc_node_name(hp, n);
+                       if (!strcmp(n_name, "cache"))
+                               fill_in_one_cache(c, hp, n);
+               }
        }
 
+       c->core_id = 0;
+       c->proc_id = -1;
+
+       return NULL;
+}
+
+void __cpuinit mdesc_fill_in_cpu_data(cpumask_t *mask)
+{
+       struct mdesc_handle *hp;
+
+       mdesc_iterate_over_cpus(fill_in_one_cpu, NULL, mask);
+
 #ifdef CONFIG_SMP
        sparc64_multi_core = 1;
 #endif
 
+       hp = mdesc_grab();
+
        set_core_ids(hp);
        set_proc_ids(hp);
 
-       smp_fill_in_sib_core_maps();
-
        mdesc_release(hp);
+
+       smp_fill_in_sib_core_maps();
 }
 
 static ssize_t mdesc_read(struct file *file, char __user *buf,
@@ -887,7 +918,6 @@ void __init sun4v_mdesc_init(void)
 {
        struct mdesc_handle *hp;
        unsigned long len, real_len, status;
-       cpumask_t mask;
 
        (void) sun4v_mach_desc(0UL, 0UL, &len);
 
@@ -911,7 +941,4 @@ void __init sun4v_mdesc_init(void)
        cur_mdesc = hp;
 
        report_platform_properties();
-
-       cpus_setall(mask);
-       mdesc_fill_in_cpu_data(mask);
 }
index c8f14c1dc5214da6b99a781f0bc58d963e144fae..90396702ea2c459e75739fe7b91f8ce9557de125 100644 (file)
 #include <linux/mod_devicetable.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/irq.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 
-static int node_match(struct device *dev, void *data)
-{
-       struct of_device *op = to_of_device(dev);
-       struct device_node *dp = data;
-
-       return (op->node == dp);
-}
-
-struct of_device *of_find_device_by_node(struct device_node *dp)
-{
-       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
-                                            dp, node_match);
-
-       if (dev)
-               return to_of_device(dev);
-
-       return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_node);
-
-unsigned int irq_of_parse_and_map(struct device_node *node, int index)
-{
-       struct of_device *op = of_find_device_by_node(node);
-
-       if (!op || index >= op->num_irqs)
-               return 0;
-
-       return op->irqs[index];
-}
-EXPORT_SYMBOL(irq_of_parse_and_map);
-
-/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
- * BUS and propagate to all child of_device objects.
- */
-void of_propagate_archdata(struct of_device *bus)
-{
-       struct dev_archdata *bus_sd = &bus->dev.archdata;
-       struct device_node *bus_dp = bus->node;
-       struct device_node *dp;
-
-       for (dp = bus_dp->child; dp; dp = dp->sibling) {
-               struct of_device *op = of_find_device_by_node(dp);
-
-               op->dev.archdata.iommu = bus_sd->iommu;
-               op->dev.archdata.stc = bus_sd->stc;
-               op->dev.archdata.host_controller = bus_sd->host_controller;
-               op->dev.archdata.numa_node = bus_sd->numa_node;
-
-               if (dp->child)
-                       of_propagate_archdata(op);
-       }
-}
-
-struct bus_type of_platform_bus_type;
-EXPORT_SYMBOL(of_platform_bus_type);
-
-static inline u64 of_read_addr(const u32 *cell, int size)
-{
-       u64 r = 0;
-       while (size--)
-               r = (r << 32) | *(cell++);
-       return r;
-}
-
-static void __init get_cells(struct device_node *dp,
-                            int *addrc, int *sizec)
-{
-       if (addrc)
-               *addrc = of_n_addr_cells(dp);
-       if (sizec)
-               *sizec = of_n_size_cells(dp);
-}
-
-/* Max address size we deal with */
-#define OF_MAX_ADDR_CELLS      4
-
-struct of_bus {
-       const char      *name;
-       const char      *addr_prop_name;
-       int             (*match)(struct device_node *parent);
-       void            (*count_cells)(struct device_node *child,
-                                      int *addrc, int *sizec);
-       int             (*map)(u32 *addr, const u32 *range,
-                              int na, int ns, int pna);
-       unsigned long   (*get_flags)(const u32 *addr, unsigned long);
-};
-
-/*
- * Default translator (generic bus)
- */
-
-static void of_bus_default_count_cells(struct device_node *dev,
-                                      int *addrc, int *sizec)
-{
-       get_cells(dev, addrc, sizec);
-}
-
-/* Make sure the least significant 64-bits are in-range.  Even
- * for 3 or 4 cell values it is a good enough approximation.
- */
-static int of_out_of_range(const u32 *addr, const u32 *base,
-                          const u32 *size, int na, int ns)
-{
-       u64 a = of_read_addr(addr, na);
-       u64 b = of_read_addr(base, na);
-
-       if (a < b)
-               return 1;
-
-       b += of_read_addr(size, ns);
-       if (a >= b)
-               return 1;
-
-       return 0;
-}
-
-static int of_bus_default_map(u32 *addr, const u32 *range,
-                             int na, int ns, int pna)
-{
-       u32 result[OF_MAX_ADDR_CELLS];
-       int i;
-
-       if (ns > 2) {
-               printk("of_device: Cannot handle size cells (%d) > 2.", ns);
-               return -EINVAL;
-       }
-
-       if (of_out_of_range(addr, range, range + na + pna, na, ns))
-               return -EINVAL;
-
-       /* Start with the parent range base.  */
-       memcpy(result, range + na, pna * 4);
-
-       /* Add in the child address offset.  */
-       for (i = 0; i < na; i++)
-               result[pna - 1 - i] +=
-                       (addr[na - 1 - i] -
-                        range[na - 1 - i]);
-
-       memcpy(addr, result, pna * 4);
-
-       return 0;
-}
-
-static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags)
-{
-       if (flags)
-               return flags;
-       return IORESOURCE_MEM;
-}
+#include "of_device_common.h"
 
 /*
  * PCI bus specific translator
@@ -240,47 +92,6 @@ static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags)
        return flags;
 }
 
-/*
- * SBUS bus specific translator
- */
-
-static int of_bus_sbus_match(struct device_node *np)
-{
-       struct device_node *dp = np;
-
-       while (dp) {
-               if (!strcmp(dp->name, "sbus") ||
-                   !strcmp(dp->name, "sbi"))
-                       return 1;
-
-               /* Have a look at use_1to1_mapping().  We're trying
-                * to match SBUS if that's the top-level bus and we
-                * don't have some intervening real bus that provides
-                * ranges based translations.
-                */
-               if (of_find_property(dp, "ranges", NULL) != NULL)
-                       break;
-
-               dp = dp->parent;
-       }
-
-       return 0;
-}
-
-static void of_bus_sbus_count_cells(struct device_node *child,
-                                  int *addrc, int *sizec)
-{
-       if (addrc)
-               *addrc = 2;
-       if (sizec)
-               *sizec = 1;
-}
-
-static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
-       return of_bus_default_map(addr, range, na, ns, pna);
-}
-
 static unsigned long of_bus_sbus_get_flags(const u32 *addr, unsigned long flags)
 {
        return IORESOURCE_MEM;
@@ -307,7 +118,7 @@ static struct of_bus of_busses[] = {
                .addr_prop_name = "reg",
                .match = of_bus_sbus_match,
                .count_cells = of_bus_sbus_count_cells,
-               .map = of_bus_sbus_map,
+               .map = of_bus_default_map,
                .get_flags = of_bus_sbus_get_flags,
        },
        /* Default */
index 5ac287ac03def46bd50d290467e76239dbfb9ef9..881947e59e955468cbc4ea0e09794a70c3c519e9 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 
+#include "of_device_common.h"
+
 void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name)
 {
        unsigned long ret = res->start + offset;
@@ -35,156 +37,6 @@ void of_iounmap(struct resource *res, void __iomem *base, unsigned long size)
 }
 EXPORT_SYMBOL(of_iounmap);
 
-static int node_match(struct device *dev, void *data)
-{
-       struct of_device *op = to_of_device(dev);
-       struct device_node *dp = data;
-
-       return (op->node == dp);
-}
-
-struct of_device *of_find_device_by_node(struct device_node *dp)
-{
-       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
-                                            dp, node_match);
-
-       if (dev)
-               return to_of_device(dev);
-
-       return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_node);
-
-unsigned int irq_of_parse_and_map(struct device_node *node, int index)
-{
-       struct of_device *op = of_find_device_by_node(node);
-
-       if (!op || index >= op->num_irqs)
-               return 0;
-
-       return op->irqs[index];
-}
-EXPORT_SYMBOL(irq_of_parse_and_map);
-
-/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
- * BUS and propagate to all child of_device objects.
- */
-void of_propagate_archdata(struct of_device *bus)
-{
-       struct dev_archdata *bus_sd = &bus->dev.archdata;
-       struct device_node *bus_dp = bus->node;
-       struct device_node *dp;
-
-       for (dp = bus_dp->child; dp; dp = dp->sibling) {
-               struct of_device *op = of_find_device_by_node(dp);
-
-               op->dev.archdata.iommu = bus_sd->iommu;
-               op->dev.archdata.stc = bus_sd->stc;
-               op->dev.archdata.host_controller = bus_sd->host_controller;
-               op->dev.archdata.numa_node = bus_sd->numa_node;
-
-               if (dp->child)
-                       of_propagate_archdata(op);
-       }
-}
-
-struct bus_type of_platform_bus_type;
-EXPORT_SYMBOL(of_platform_bus_type);
-
-static inline u64 of_read_addr(const u32 *cell, int size)
-{
-       u64 r = 0;
-       while (size--)
-               r = (r << 32) | *(cell++);
-       return r;
-}
-
-static void get_cells(struct device_node *dp, int *addrc, int *sizec)
-{
-       if (addrc)
-               *addrc = of_n_addr_cells(dp);
-       if (sizec)
-               *sizec = of_n_size_cells(dp);
-}
-
-/* Max address size we deal with */
-#define OF_MAX_ADDR_CELLS      4
-
-struct of_bus {
-       const char      *name;
-       const char      *addr_prop_name;
-       int             (*match)(struct device_node *parent);
-       void            (*count_cells)(struct device_node *child,
-                                      int *addrc, int *sizec);
-       int             (*map)(u32 *addr, const u32 *range,
-                              int na, int ns, int pna);
-       unsigned long   (*get_flags)(const u32 *addr, unsigned long);
-};
-
-/*
- * Default translator (generic bus)
- */
-
-static void of_bus_default_count_cells(struct device_node *dev,
-                                      int *addrc, int *sizec)
-{
-       get_cells(dev, addrc, sizec);
-}
-
-/* Make sure the least significant 64-bits are in-range.  Even
- * for 3 or 4 cell values it is a good enough approximation.
- */
-static int of_out_of_range(const u32 *addr, const u32 *base,
-                          const u32 *size, int na, int ns)
-{
-       u64 a = of_read_addr(addr, na);
-       u64 b = of_read_addr(base, na);
-
-       if (a < b)
-               return 1;
-
-       b += of_read_addr(size, ns);
-       if (a >= b)
-               return 1;
-
-       return 0;
-}
-
-static int of_bus_default_map(u32 *addr, const u32 *range,
-                             int na, int ns, int pna)
-{
-       u32 result[OF_MAX_ADDR_CELLS];
-       int i;
-
-       if (ns > 2) {
-               printk("of_device: Cannot handle size cells (%d) > 2.", ns);
-               return -EINVAL;
-       }
-
-       if (of_out_of_range(addr, range, range + na + pna, na, ns))
-               return -EINVAL;
-
-       /* Start with the parent range base.  */
-       memcpy(result, range + na, pna * 4);
-
-       /* Add in the child address offset.  */
-       for (i = 0; i < na; i++)
-               result[pna - 1 - i] +=
-                       (addr[na - 1 - i] -
-                        range[na - 1 - i]);
-
-       memcpy(addr, result, pna * 4);
-
-       return 0;
-}
-
-static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags)
-{
-       if (flags)
-               return flags;
-       return IORESOURCE_MEM;
-}
-
 /*
  * PCI bus specific translator
  */
@@ -294,42 +146,6 @@ static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags)
        return flags;
 }
 
-/*
- * SBUS bus specific translator
- */
-
-static int of_bus_sbus_match(struct device_node *np)
-{
-       struct device_node *dp = np;
-
-       while (dp) {
-               if (!strcmp(dp->name, "sbus") ||
-                   !strcmp(dp->name, "sbi"))
-                       return 1;
-
-               /* Have a look at use_1to1_mapping().  We're trying
-                * to match SBUS if that's the top-level bus and we
-                * don't have some intervening real bus that provides
-                * ranges based translations.
-                */
-               if (of_find_property(dp, "ranges", NULL) != NULL)
-                       break;
-
-               dp = dp->parent;
-       }
-
-       return 0;
-}
-
-static void of_bus_sbus_count_cells(struct device_node *child,
-                                  int *addrc, int *sizec)
-{
-       if (addrc)
-               *addrc = 2;
-       if (sizec)
-               *sizec = 1;
-}
-
 /*
  * FHC/Central bus specific translator.
  *
diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c
new file mode 100644 (file)
index 0000000..cb8eb79
--- /dev/null
@@ -0,0 +1,174 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include "of_device_common.h"
+
+static int node_match(struct device *dev, void *data)
+{
+       struct of_device *op = to_of_device(dev);
+       struct device_node *dp = data;
+
+       return (op->node == dp);
+}
+
+struct of_device *of_find_device_by_node(struct device_node *dp)
+{
+       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
+                                            dp, node_match);
+
+       if (dev)
+               return to_of_device(dev);
+
+       return NULL;
+}
+EXPORT_SYMBOL(of_find_device_by_node);
+
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+       struct of_device *op = of_find_device_by_node(node);
+
+       if (!op || index >= op->num_irqs)
+               return 0;
+
+       return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+       struct dev_archdata *bus_sd = &bus->dev.archdata;
+       struct device_node *bus_dp = bus->node;
+       struct device_node *dp;
+
+       for (dp = bus_dp->child; dp; dp = dp->sibling) {
+               struct of_device *op = of_find_device_by_node(dp);
+
+               op->dev.archdata.iommu = bus_sd->iommu;
+               op->dev.archdata.stc = bus_sd->stc;
+               op->dev.archdata.host_controller = bus_sd->host_controller;
+               op->dev.archdata.numa_node = bus_sd->numa_node;
+
+               if (dp->child)
+                       of_propagate_archdata(op);
+       }
+}
+
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
+
+static void get_cells(struct device_node *dp, int *addrc, int *sizec)
+{
+       if (addrc)
+               *addrc = of_n_addr_cells(dp);
+       if (sizec)
+               *sizec = of_n_size_cells(dp);
+}
+
+/*
+ * Default translator (generic bus)
+ */
+
+void of_bus_default_count_cells(struct device_node *dev, int *addrc, int *sizec)
+{
+       get_cells(dev, addrc, sizec);
+}
+
+/* Make sure the least significant 64-bits are in-range.  Even
+ * for 3 or 4 cell values it is a good enough approximation.
+ */
+int of_out_of_range(const u32 *addr, const u32 *base,
+                   const u32 *size, int na, int ns)
+{
+       u64 a = of_read_addr(addr, na);
+       u64 b = of_read_addr(base, na);
+
+       if (a < b)
+               return 1;
+
+       b += of_read_addr(size, ns);
+       if (a >= b)
+               return 1;
+
+       return 0;
+}
+
+int of_bus_default_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+{
+       u32 result[OF_MAX_ADDR_CELLS];
+       int i;
+
+       if (ns > 2) {
+               printk("of_device: Cannot handle size cells (%d) > 2.", ns);
+               return -EINVAL;
+       }
+
+       if (of_out_of_range(addr, range, range + na + pna, na, ns))
+               return -EINVAL;
+
+       /* Start with the parent range base.  */
+       memcpy(result, range + na, pna * 4);
+
+       /* Add in the child address offset.  */
+       for (i = 0; i < na; i++)
+               result[pna - 1 - i] +=
+                       (addr[na - 1 - i] -
+                        range[na - 1 - i]);
+
+       memcpy(addr, result, pna * 4);
+
+       return 0;
+}
+
+unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags)
+{
+       if (flags)
+               return flags;
+       return IORESOURCE_MEM;
+}
+
+/*
+ * SBUS bus specific translator
+ */
+
+int of_bus_sbus_match(struct device_node *np)
+{
+       struct device_node *dp = np;
+
+       while (dp) {
+               if (!strcmp(dp->name, "sbus") ||
+                   !strcmp(dp->name, "sbi"))
+                       return 1;
+
+               /* Have a look at use_1to1_mapping().  We're trying
+                * to match SBUS if that's the top-level bus and we
+                * don't have some intervening real bus that provides
+                * ranges based translations.
+                */
+               if (of_find_property(dp, "ranges", NULL) != NULL)
+                       break;
+
+               dp = dp->parent;
+       }
+
+       return 0;
+}
+
+void of_bus_sbus_count_cells(struct device_node *child, int *addrc, int *sizec)
+{
+       if (addrc)
+               *addrc = 2;
+       if (sizec)
+               *sizec = 1;
+}
diff --git a/arch/sparc/kernel/of_device_common.h b/arch/sparc/kernel/of_device_common.h
new file mode 100644 (file)
index 0000000..cdfd239
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _OF_DEVICE_COMMON_H
+#define _OF_DEVICE_COMMON_H
+
+static inline u64 of_read_addr(const u32 *cell, int size)
+{
+       u64 r = 0;
+       while (size--)
+               r = (r << 32) | *(cell++);
+       return r;
+}
+
+void of_bus_default_count_cells(struct device_node *dev, int *addrc,
+                               int *sizec);
+int of_out_of_range(const u32 *addr, const u32 *base,
+                   const u32 *size, int na, int ns);
+int of_bus_default_map(u32 *addr, const u32 *range, int na, int ns, int pna);
+unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags);
+
+int of_bus_sbus_match(struct device_node *np);
+void of_bus_sbus_count_cells(struct device_node *child, int *addrc, int *sizec);
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS      4
+
+struct of_bus {
+       const char      *name;
+       const char      *addr_prop_name;
+       int             (*match)(struct device_node *parent);
+       void            (*count_cells)(struct device_node *child,
+                                      int *addrc, int *sizec);
+       int             (*map)(u32 *addr, const u32 *range,
+                              int na, int ns, int pna);
+       unsigned long   (*get_flags)(const u32 *addr, unsigned long);
+};
+
+#endif /* _OF_DEVICE_COMMON_H */
index 5db5ebed35da0083370e16a932d9478e20f4cfe1..2485eaa231019676eb1780bfe9f5ff3965394540 100644 (file)
@@ -230,8 +230,9 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
                free_pages((unsigned long)cpu, order);
 }
 
-static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz,
-                                   enum dma_data_direction direction)
+static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
+                                 unsigned long offset, size_t sz,
+                                 enum dma_data_direction direction)
 {
        struct iommu *iommu;
        unsigned long flags, npages, oaddr;
@@ -245,7 +246,7 @@ static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz,
        if (unlikely(direction == DMA_NONE))
                goto bad;
 
-       oaddr = (unsigned long)ptr;
+       oaddr = (unsigned long)(page_address(page) + offset);
        npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
        npages >>= IO_PAGE_SHIFT;
 
@@ -294,8 +295,8 @@ iommu_map_fail:
        return DMA_ERROR_CODE;
 }
 
-static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr,
-                               size_t sz, enum dma_data_direction direction)
+static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr,
+                             size_t sz, enum dma_data_direction direction)
 {
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
@@ -537,8 +538,8 @@ static void dma_4v_sync_sg_for_cpu(struct device *dev,
 static const struct dma_ops sun4v_dma_ops = {
        .alloc_coherent                 = dma_4v_alloc_coherent,
        .free_coherent                  = dma_4v_free_coherent,
-       .map_single                     = dma_4v_map_single,
-       .unmap_single                   = dma_4v_unmap_single,
+       .map_page                       = dma_4v_map_page,
+       .unmap_page                     = dma_4v_unmap_page,
        .map_sg                         = dma_4v_map_sg,
        .unmap_sg                       = dma_4v_unmap_sg,
        .sync_single_for_cpu            = dma_4v_sync_single_for_cpu,
index bb0f0fda6cab4a4686cbb031a0864c45e3df346a..453397fe5e14035fbc980689d844e5673312d4a3 100644 (file)
@@ -22,7 +22,6 @@ static inline int is_root_node(const struct device_node *dp)
 
 extern char *build_path_component(struct device_node *dp);
 extern void of_console_init(void);
-extern void of_fill_in_cpu_data(void);
 
 extern unsigned int prom_early_allocated;
 
index ca55c7012f7751d4338a1c6fc1153124ef0f6966..fb06ac2bd38ffbb198080dc9006775fdab0b55f1 100644 (file)
@@ -374,75 +374,26 @@ static const char *get_mid_prop(void)
        return (tlb_type == spitfire ? "upa-portid" : "portid");
 }
 
-struct device_node *of_find_node_by_cpuid(int cpuid)
-{
-       struct device_node *dp;
-       const char *mid_prop = get_mid_prop();
-
-       for_each_node_by_type(dp, "cpu") {
-               int id = of_getintprop_default(dp, mid_prop, -1);
-               const char *this_mid_prop = mid_prop;
-
-               if (id < 0) {
-                       this_mid_prop = "cpuid";
-                       id = of_getintprop_default(dp, this_mid_prop, -1);
-               }
-
-               if (id < 0) {
-                       prom_printf("OF: Serious problem, cpu lacks "
-                                   "%s property", this_mid_prop);
-                       prom_halt();
-               }
-               if (cpuid == id)
-                       return dp;
-       }
-       return NULL;
-}
-
-void __init of_fill_in_cpu_data(void)
+static void *of_iterate_over_cpus(void *(*func)(struct device_node *, int, int), int arg)
 {
        struct device_node *dp;
        const char *mid_prop;
 
-       if (tlb_type == hypervisor)
-               return;
-
        mid_prop = get_mid_prop();
-       ncpus_probed = 0;
        for_each_node_by_type(dp, "cpu") {
                int cpuid = of_getintprop_default(dp, mid_prop, -1);
                const char *this_mid_prop = mid_prop;
-               struct device_node *portid_parent;
-               int portid = -1;
+               void *ret;
 
-               portid_parent = NULL;
                if (cpuid < 0) {
                        this_mid_prop = "cpuid";
                        cpuid = of_getintprop_default(dp, this_mid_prop, -1);
-                       if (cpuid >= 0) {
-                               int limit = 2;
-
-                               portid_parent = dp;
-                               while (limit--) {
-                                       portid_parent = portid_parent->parent;
-                                       if (!portid_parent)
-                                               break;
-                                       portid = of_getintprop_default(portid_parent,
-                                                                      "portid", -1);
-                                       if (portid >= 0)
-                                               break;
-                               }
-                       }
                }
-
                if (cpuid < 0) {
                        prom_printf("OF: Serious problem, cpu lacks "
                                    "%s property", this_mid_prop);
                        prom_halt();
                }
-
-               ncpus_probed++;
-
 #ifdef CONFIG_SMP
                if (cpuid >= NR_CPUS) {
                        printk(KERN_WARNING "Ignoring CPU %d which is "
@@ -450,79 +401,142 @@ void __init of_fill_in_cpu_data(void)
                               cpuid, NR_CPUS);
                        continue;
                }
-#else
-               /* On uniprocessor we only want the values for the
-                * real physical cpu the kernel booted onto, however
-                * cpu_data() only has one entry at index 0.
-                */
-               if (cpuid != real_hard_smp_processor_id())
-                       continue;
-               cpuid = 0;
 #endif
+               ret = func(dp, cpuid, arg);
+               if (ret)
+                       return ret;
+       }
+       return NULL;
+}
 
-               cpu_data(cpuid).clock_tick =
-                       of_getintprop_default(dp, "clock-frequency", 0);
-
-               if (portid_parent) {
-                       cpu_data(cpuid).dcache_size =
-                               of_getintprop_default(dp, "l1-dcache-size",
-                                                     16 * 1024);
-                       cpu_data(cpuid).dcache_line_size =
-                               of_getintprop_default(dp, "l1-dcache-line-size",
-                                                     32);
-                       cpu_data(cpuid).icache_size =
-                               of_getintprop_default(dp, "l1-icache-size",
-                                                     8 * 1024);
-                       cpu_data(cpuid).icache_line_size =
-                               of_getintprop_default(dp, "l1-icache-line-size",
-                                                     32);
-                       cpu_data(cpuid).ecache_size =
-                               of_getintprop_default(dp, "l2-cache-size", 0);
-                       cpu_data(cpuid).ecache_line_size =
-                               of_getintprop_default(dp, "l2-cache-line-size", 0);
-                       if (!cpu_data(cpuid).ecache_size ||
-                           !cpu_data(cpuid).ecache_line_size) {
-                               cpu_data(cpuid).ecache_size =
-                                       of_getintprop_default(portid_parent,
-                                                             "l2-cache-size",
-                                                             (4 * 1024 * 1024));
-                               cpu_data(cpuid).ecache_line_size =
-                                       of_getintprop_default(portid_parent,
-                                                             "l2-cache-line-size", 64);
-                       }
-
-                       cpu_data(cpuid).core_id = portid + 1;
-                       cpu_data(cpuid).proc_id = portid;
+static void *check_cpu_node(struct device_node *dp, int cpuid, int id)
+{
+       if (id == cpuid)
+               return dp;
+       return NULL;
+}
+
+struct device_node *of_find_node_by_cpuid(int cpuid)
+{
+       return of_iterate_over_cpus(check_cpu_node, cpuid);
+}
+
+static void *record_one_cpu(struct device_node *dp, int cpuid, int arg)
+{
+       ncpus_probed++;
 #ifdef CONFIG_SMP
-                       sparc64_multi_core = 1;
+       set_cpu_present(cpuid, true);
+       set_cpu_possible(cpuid, true);
 #endif
-               } else {
-                       cpu_data(cpuid).dcache_size =
-                               of_getintprop_default(dp, "dcache-size", 16 * 1024);
-                       cpu_data(cpuid).dcache_line_size =
-                               of_getintprop_default(dp, "dcache-line-size", 32);
+       return NULL;
+}
 
-                       cpu_data(cpuid).icache_size =
-                               of_getintprop_default(dp, "icache-size", 16 * 1024);
-                       cpu_data(cpuid).icache_line_size =
-                               of_getintprop_default(dp, "icache-line-size", 32);
+void __init of_populate_present_mask(void)
+{
+       if (tlb_type == hypervisor)
+               return;
+
+       ncpus_probed = 0;
+       of_iterate_over_cpus(record_one_cpu, 0);
+}
 
+static void *fill_in_one_cpu(struct device_node *dp, int cpuid, int arg)
+{
+       struct device_node *portid_parent = NULL;
+       int portid = -1;
+
+       if (of_find_property(dp, "cpuid", NULL)) {
+               int limit = 2;
+
+               portid_parent = dp;
+               while (limit--) {
+                       portid_parent = portid_parent->parent;
+                       if (!portid_parent)
+                               break;
+                       portid = of_getintprop_default(portid_parent,
+                                                      "portid", -1);
+                       if (portid >= 0)
+                               break;
+               }
+       }
+
+#ifndef CONFIG_SMP
+       /* On uniprocessor we only want the values for the
+        * real physical cpu the kernel booted onto, however
+        * cpu_data() only has one entry at index 0.
+        */
+       if (cpuid != real_hard_smp_processor_id())
+               return NULL;
+       cpuid = 0;
+#endif
+
+       cpu_data(cpuid).clock_tick =
+               of_getintprop_default(dp, "clock-frequency", 0);
+
+       if (portid_parent) {
+               cpu_data(cpuid).dcache_size =
+                       of_getintprop_default(dp, "l1-dcache-size",
+                                             16 * 1024);
+               cpu_data(cpuid).dcache_line_size =
+                       of_getintprop_default(dp, "l1-dcache-line-size",
+                                             32);
+               cpu_data(cpuid).icache_size =
+                       of_getintprop_default(dp, "l1-icache-size",
+                                             8 * 1024);
+               cpu_data(cpuid).icache_line_size =
+                       of_getintprop_default(dp, "l1-icache-line-size",
+                                             32);
+               cpu_data(cpuid).ecache_size =
+                       of_getintprop_default(dp, "l2-cache-size", 0);
+               cpu_data(cpuid).ecache_line_size =
+                       of_getintprop_default(dp, "l2-cache-line-size", 0);
+               if (!cpu_data(cpuid).ecache_size ||
+                   !cpu_data(cpuid).ecache_line_size) {
                        cpu_data(cpuid).ecache_size =
-                               of_getintprop_default(dp, "ecache-size",
+                               of_getintprop_default(portid_parent,
+                                                     "l2-cache-size",
                                                      (4 * 1024 * 1024));
                        cpu_data(cpuid).ecache_line_size =
-                               of_getintprop_default(dp, "ecache-line-size", 64);
-
-                       cpu_data(cpuid).core_id = 0;
-                       cpu_data(cpuid).proc_id = -1;
+                               of_getintprop_default(portid_parent,
+                                                     "l2-cache-line-size", 64);
                }
 
+               cpu_data(cpuid).core_id = portid + 1;
+               cpu_data(cpuid).proc_id = portid;
 #ifdef CONFIG_SMP
-               set_cpu_present(cpuid, true);
-               set_cpu_possible(cpuid, true);
+               sparc64_multi_core = 1;
 #endif
+       } else {
+               cpu_data(cpuid).dcache_size =
+                       of_getintprop_default(dp, "dcache-size", 16 * 1024);
+               cpu_data(cpuid).dcache_line_size =
+                       of_getintprop_default(dp, "dcache-line-size", 32);
+
+               cpu_data(cpuid).icache_size =
+                       of_getintprop_default(dp, "icache-size", 16 * 1024);
+               cpu_data(cpuid).icache_line_size =
+                       of_getintprop_default(dp, "icache-line-size", 32);
+
+               cpu_data(cpuid).ecache_size =
+                       of_getintprop_default(dp, "ecache-size",
+                                             (4 * 1024 * 1024));
+               cpu_data(cpuid).ecache_line_size =
+                       of_getintprop_default(dp, "ecache-line-size", 64);
+
+               cpu_data(cpuid).core_id = 0;
+               cpu_data(cpuid).proc_id = -1;
        }
 
+       return NULL;
+}
+
+void __init of_fill_in_cpu_data(void)
+{
+       if (tlb_type == hypervisor)
+               return;
+
+       of_iterate_over_cpus(fill_in_one_cpu, 0);
+
        smp_fill_in_sib_core_maps();
 }
 
index ff7b591c8946d1ad5f849f0956e4452037f78e66..0fb5789d43c82e84977757251ad78a6fa834d9b5 100644 (file)
@@ -313,6 +313,4 @@ void __init prom_build_devicetree(void)
 
        printk("PROM: Built device tree with %u bytes of memory.\n",
               prom_early_allocated);
-
-       of_fill_in_cpu_data();
 }
index f7642e5a94dbdcd4b45d48b7391b2f01a5b14c64..fa44eaf8d897b1f110e96d7e48ce8fdea686212f 100644 (file)
@@ -20,7 +20,8 @@
 #include <linux/cache.h>
 #include <linux/jiffies.h>
 #include <linux/profile.h>
-#include <linux/lmb.h>
+#include <linux/bootmem.h>
+#include <linux/vmalloc.h>
 #include <linux/cpu.h>
 
 #include <asm/head.h>
@@ -47,6 +48,8 @@
 #include <asm/ldc.h>
 #include <asm/hypervisor.h>
 
+#include "cpumap.h"
+
 int sparc64_multi_core __read_mostly;
 
 DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE;
@@ -278,7 +281,7 @@ static unsigned long kimage_addr_to_ra(void *p)
        return kern_base + (val - KERNBASE);
 }
 
-static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg)
+static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg, void **descrp)
 {
        extern unsigned long sparc64_ttable_tl0;
        extern unsigned long kern_locked_tte_data;
@@ -298,12 +301,12 @@ static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread
                       "hvtramp_descr.\n");
                return;
        }
+       *descrp = hdesc;
 
        hdesc->cpu = cpu;
        hdesc->num_mappings = num_kernel_image_mappings;
 
        tb = &trap_block[cpu];
-       tb->hdesc = hdesc;
 
        hdesc->fault_info_va = (unsigned long) &tb->fault_info;
        hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info);
@@ -341,12 +344,12 @@ static struct thread_info *cpu_new_thread = NULL;
 
 static int __cpuinit smp_boot_one_cpu(unsigned int cpu)
 {
-       struct trap_per_cpu *tb = &trap_block[cpu];
        unsigned long entry =
                (unsigned long)(&sparc64_cpu_startup);
        unsigned long cookie =
                (unsigned long)(&cpu_new_thread);
        struct task_struct *p;
+       void *descr = NULL;
        int timeout, ret;
 
        p = fork_idle(cpu);
@@ -359,7 +362,8 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu)
 #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
                if (ldom_domaining_enabled)
                        ldom_startcpu_cpuid(cpu,
-                                           (unsigned long) cpu_new_thread);
+                                           (unsigned long) cpu_new_thread,
+                                           &descr);
                else
 #endif
                        prom_startcpu_cpuid(cpu, entry, cookie);
@@ -383,10 +387,7 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu)
        }
        cpu_new_thread = NULL;
 
-       if (tb->hdesc) {
-               kfree(tb->hdesc);
-               tb->hdesc = NULL;
-       }
+       kfree(descr);
 
        return ret;
 }
@@ -1315,6 +1316,8 @@ int __cpu_disable(void)
        cpu_clear(cpu, cpu_online_map);
        ipi_call_unlock();
 
+       cpu_map_rebuild();
+
        return 0;
 }
 
@@ -1373,36 +1376,171 @@ void smp_send_stop(void)
 {
 }
 
-unsigned long __per_cpu_base __read_mostly;
-unsigned long __per_cpu_shift __read_mostly;
+/**
+ * pcpu_alloc_bootmem - NUMA friendly alloc_bootmem wrapper for percpu
+ * @cpu: cpu to allocate for
+ * @size: size allocation in bytes
+ * @align: alignment
+ *
+ * Allocate @size bytes aligned at @align for cpu @cpu.  This wrapper
+ * does the right thing for NUMA regardless of the current
+ * configuration.
+ *
+ * RETURNS:
+ * Pointer to the allocated area on success, NULL on failure.
+ */
+static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size,
+                                       unsigned long align)
+{
+       const unsigned long goal = __pa(MAX_DMA_ADDRESS);
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+       int node = cpu_to_node(cpu);
+       void *ptr;
+
+       if (!node_online(node) || !NODE_DATA(node)) {
+               ptr = __alloc_bootmem(size, align, goal);
+               pr_info("cpu %d has no node %d or node-local memory\n",
+                       cpu, node);
+               pr_debug("per cpu data for cpu%d %lu bytes at %016lx\n",
+                        cpu, size, __pa(ptr));
+       } else {
+               ptr = __alloc_bootmem_node(NODE_DATA(node),
+                                          size, align, goal);
+               pr_debug("per cpu data for cpu%d %lu bytes on node%d at "
+                        "%016lx\n", cpu, size, node, __pa(ptr));
+       }
+       return ptr;
+#else
+       return __alloc_bootmem(size, align, goal);
+#endif
+}
 
-EXPORT_SYMBOL(__per_cpu_base);
-EXPORT_SYMBOL(__per_cpu_shift);
+static size_t pcpur_size __initdata;
+static void **pcpur_ptrs __initdata;
 
-void __init real_setup_per_cpu_areas(void)
+static struct page * __init pcpur_get_page(unsigned int cpu, int pageno)
 {
-       unsigned long paddr, goal, size, i;
-       char *ptr;
+       size_t off = (size_t)pageno << PAGE_SHIFT;
 
-       /* Copy section for each CPU (we discard the original) */
-       goal = PERCPU_ENOUGH_ROOM;
+       if (off >= pcpur_size)
+               return NULL;
 
-       __per_cpu_shift = PAGE_SHIFT;
-       for (size = PAGE_SIZE; size < goal; size <<= 1UL)
-               __per_cpu_shift++;
+       return virt_to_page(pcpur_ptrs[cpu] + off);
+}
+
+#define PCPU_CHUNK_SIZE (4UL * 1024UL * 1024UL)
+
+static void __init pcpu_map_range(unsigned long start, unsigned long end,
+                                 struct page *page)
+{
+       unsigned long pfn = page_to_pfn(page);
+       unsigned long pte_base;
+
+       BUG_ON((pfn<<PAGE_SHIFT)&(PCPU_CHUNK_SIZE - 1UL));
+
+       pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4U |
+                   _PAGE_CP_4U | _PAGE_CV_4U |
+                   _PAGE_P_4U | _PAGE_W_4U);
+       if (tlb_type == hypervisor)
+               pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4V |
+                           _PAGE_CP_4V | _PAGE_CV_4V |
+                           _PAGE_P_4V | _PAGE_W_4V);
+
+       while (start < end) {
+               pgd_t *pgd = pgd_offset_k(start);
+               unsigned long this_end;
+               pud_t *pud;
+               pmd_t *pmd;
+               pte_t *pte;
+
+               pud = pud_offset(pgd, start);
+               if (pud_none(*pud)) {
+                       pmd_t *new;
+
+                       new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
+                       pud_populate(&init_mm, pud, new);
+               }
+
+               pmd = pmd_offset(pud, start);
+               if (!pmd_present(*pmd)) {
+                       pte_t *new;
+
+                       new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
+                       pmd_populate_kernel(&init_mm, pmd, new);
+               }
 
-       paddr = lmb_alloc(size * NR_CPUS, PAGE_SIZE);
-       if (!paddr) {
-               prom_printf("Cannot allocate per-cpu memory.\n");
-               prom_halt();
+               pte = pte_offset_kernel(pmd, start);
+               this_end = (start + PMD_SIZE) & PMD_MASK;
+               if (this_end > end)
+                       this_end = end;
+
+               while (start < this_end) {
+                       unsigned long paddr = pfn << PAGE_SHIFT;
+
+                       pte_val(*pte) = (paddr | pte_base);
+
+                       start += PAGE_SIZE;
+                       pte++;
+                       pfn++;
+               }
+       }
+}
+
+void __init setup_per_cpu_areas(void)
+{
+       size_t dyn_size, static_size = __per_cpu_end - __per_cpu_start;
+       static struct vm_struct vm;
+       unsigned long delta, cpu;
+       size_t pcpu_unit_size;
+       size_t ptrs_size;
+
+       pcpur_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE +
+                              PERCPU_DYNAMIC_RESERVE);
+       dyn_size = pcpur_size - static_size - PERCPU_MODULE_RESERVE;
+
+
+       ptrs_size = PFN_ALIGN(num_possible_cpus() * sizeof(pcpur_ptrs[0]));
+       pcpur_ptrs = alloc_bootmem(ptrs_size);
+
+       for_each_possible_cpu(cpu) {
+               pcpur_ptrs[cpu] = pcpu_alloc_bootmem(cpu, PCPU_CHUNK_SIZE,
+                                                    PCPU_CHUNK_SIZE);
+
+               free_bootmem(__pa(pcpur_ptrs[cpu] + pcpur_size),
+                            PCPU_CHUNK_SIZE - pcpur_size);
+
+               memcpy(pcpur_ptrs[cpu], __per_cpu_load, static_size);
        }
 
-       ptr = __va(paddr);
-       __per_cpu_base = ptr - __per_cpu_start;
+       /* allocate address and map */
+       vm.flags = VM_ALLOC;
+       vm.size = num_possible_cpus() * PCPU_CHUNK_SIZE;
+       vm_area_register_early(&vm, PCPU_CHUNK_SIZE);
+
+       for_each_possible_cpu(cpu) {
+               unsigned long start = (unsigned long) vm.addr;
+               unsigned long end;
+
+               start += cpu * PCPU_CHUNK_SIZE;
+               end = start + PCPU_CHUNK_SIZE;
+               pcpu_map_range(start, end, virt_to_page(pcpur_ptrs[cpu]));
+       }
 
-       for (i = 0; i < NR_CPUS; i++, ptr += size)
-               memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+       pcpu_unit_size = pcpu_setup_first_chunk(pcpur_get_page, static_size,
+                                               PERCPU_MODULE_RESERVE, dyn_size,
+                                               PCPU_CHUNK_SIZE, vm.addr, NULL);
+
+       free_bootmem(__pa(pcpur_ptrs), ptrs_size);
+
+       delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
+       for_each_possible_cpu(cpu) {
+               __per_cpu_offset(cpu) = delta + cpu * pcpu_unit_size;
+       }
 
        /* Setup %g5 for the boot cpu.  */
        __local_per_cpu_offset = __per_cpu_offset(smp_processor_id());
+
+       of_fill_in_cpu_data();
+       if (tlb_type == hypervisor)
+               mdesc_fill_in_cpu_data(cpu_all_mask);
 }
index 00ec3b15f38ceb4e53332b085bd437cdedab5ba8..690901657291db9f641bc17a9c45cd26f542c8fa 100644 (file)
@@ -81,4 +81,6 @@ sys_call_table:
 /*305*/        .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
 /*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
 /*315*/        .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
-/*320*/        .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv, sys_pwritev
+/*320*/        .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
+/*325*/        .long sys_pwritev, sys_rt_tgsigqueueinfo
+
index 82b5bf85b9d2b2137bcaedda89ffe472dd06650e..6b3ee88e253c22035d5d0f80f39c472e59219dd1 100644 (file)
@@ -82,7 +82,8 @@ sys_call_table32:
        .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
 /*310*/        .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate
        .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1
-/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv, compat_sys_pwritev
+/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv
+       .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo
 
 #endif /* CONFIG_COMPAT */
 
@@ -156,4 +157,5 @@ sys_call_table:
        .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
 /*310*/        .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
        .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
-/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv, sys_pwritev
+/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
+       .word sys_pwritev, sys_rt_tgsigqueueinfo
index d809c4ebb48f44120f682272e00664bfbfd7cea6..10f7bb9fc1404e77a6eb542dec98285e98762162 100644 (file)
@@ -2509,6 +2509,7 @@ void do_getpsr(struct pt_regs *regs)
 }
 
 struct trap_per_cpu trap_block[NR_CPUS];
+EXPORT_SYMBOL(trap_block);
 
 /* This can get invoked before sched_init() so play it super safe
  * and use hard_smp_processor_id().
@@ -2530,84 +2531,97 @@ extern void tsb_config_offsets_are_bolixed_dave(void);
 void __init trap_init(void)
 {
        /* Compile time sanity check. */
-       if (TI_TASK != offsetof(struct thread_info, task) ||
-           TI_FLAGS != offsetof(struct thread_info, flags) ||
-           TI_CPU != offsetof(struct thread_info, cpu) ||
-           TI_FPSAVED != offsetof(struct thread_info, fpsaved) ||
-           TI_KSP != offsetof(struct thread_info, ksp) ||
-           TI_FAULT_ADDR != offsetof(struct thread_info, fault_address) ||
-           TI_KREGS != offsetof(struct thread_info, kregs) ||
-           TI_UTRAPS != offsetof(struct thread_info, utraps) ||
-           TI_EXEC_DOMAIN != offsetof(struct thread_info, exec_domain) ||
-           TI_REG_WINDOW != offsetof(struct thread_info, reg_window) ||
-           TI_RWIN_SPTRS != offsetof(struct thread_info, rwbuf_stkptrs) ||
-           TI_GSR != offsetof(struct thread_info, gsr) ||
-           TI_XFSR != offsetof(struct thread_info, xfsr) ||
-           TI_USER_CNTD0 != offsetof(struct thread_info, user_cntd0) ||
-           TI_USER_CNTD1 != offsetof(struct thread_info, user_cntd1) ||
-           TI_KERN_CNTD0 != offsetof(struct thread_info, kernel_cntd0) ||
-           TI_KERN_CNTD1 != offsetof(struct thread_info, kernel_cntd1) ||
-           TI_PCR != offsetof(struct thread_info, pcr_reg) ||
-           TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) ||
-           TI_NEW_CHILD != offsetof(struct thread_info, new_child) ||
-           TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) ||
-           TI_RESTART_BLOCK != offsetof(struct thread_info, restart_block) ||
-           TI_KUNA_REGS != offsetof(struct thread_info, kern_una_regs) ||
-           TI_KUNA_INSN != offsetof(struct thread_info, kern_una_insn) ||
-           TI_FPREGS != offsetof(struct thread_info, fpregs) ||
-           (TI_FPREGS & (64 - 1)))
-               thread_info_offsets_are_bolixed_dave();
-
-       if (TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu, thread) ||
-           (TRAP_PER_CPU_PGD_PADDR !=
-            offsetof(struct trap_per_cpu, pgd_paddr)) ||
-           (TRAP_PER_CPU_CPU_MONDO_PA !=
-            offsetof(struct trap_per_cpu, cpu_mondo_pa)) ||
-           (TRAP_PER_CPU_DEV_MONDO_PA !=
-            offsetof(struct trap_per_cpu, dev_mondo_pa)) ||
-           (TRAP_PER_CPU_RESUM_MONDO_PA !=
-            offsetof(struct trap_per_cpu, resum_mondo_pa)) ||
-           (TRAP_PER_CPU_RESUM_KBUF_PA !=
-            offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) ||
-           (TRAP_PER_CPU_NONRESUM_MONDO_PA !=
-            offsetof(struct trap_per_cpu, nonresum_mondo_pa)) ||
-           (TRAP_PER_CPU_NONRESUM_KBUF_PA !=
-            offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) ||
-           (TRAP_PER_CPU_FAULT_INFO !=
-            offsetof(struct trap_per_cpu, fault_info)) ||
-           (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA !=
-            offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) ||
-           (TRAP_PER_CPU_CPU_LIST_PA !=
-            offsetof(struct trap_per_cpu, cpu_list_pa)) ||
-           (TRAP_PER_CPU_TSB_HUGE !=
-            offsetof(struct trap_per_cpu, tsb_huge)) ||
-           (TRAP_PER_CPU_TSB_HUGE_TEMP !=
-            offsetof(struct trap_per_cpu, tsb_huge_temp)) ||
-           (TRAP_PER_CPU_IRQ_WORKLIST_PA !=
-            offsetof(struct trap_per_cpu, irq_worklist_pa)) ||
-           (TRAP_PER_CPU_CPU_MONDO_QMASK !=
-            offsetof(struct trap_per_cpu, cpu_mondo_qmask)) ||
-           (TRAP_PER_CPU_DEV_MONDO_QMASK !=
-            offsetof(struct trap_per_cpu, dev_mondo_qmask)) ||
-           (TRAP_PER_CPU_RESUM_QMASK !=
-            offsetof(struct trap_per_cpu, resum_qmask)) ||
-           (TRAP_PER_CPU_NONRESUM_QMASK !=
-            offsetof(struct trap_per_cpu, nonresum_qmask)))
-               trap_per_cpu_offsets_are_bolixed_dave();
-
-       if ((TSB_CONFIG_TSB !=
-            offsetof(struct tsb_config, tsb)) ||
-           (TSB_CONFIG_RSS_LIMIT !=
-            offsetof(struct tsb_config, tsb_rss_limit)) ||
-           (TSB_CONFIG_NENTRIES !=
-            offsetof(struct tsb_config, tsb_nentries)) ||
-           (TSB_CONFIG_REG_VAL !=
-            offsetof(struct tsb_config, tsb_reg_val)) ||
-           (TSB_CONFIG_MAP_VADDR !=
-            offsetof(struct tsb_config, tsb_map_vaddr)) ||
-           (TSB_CONFIG_MAP_PTE !=
-            offsetof(struct tsb_config, tsb_map_pte)))
-               tsb_config_offsets_are_bolixed_dave();
+       BUILD_BUG_ON(TI_TASK != offsetof(struct thread_info, task) ||
+                    TI_FLAGS != offsetof(struct thread_info, flags) ||
+                    TI_CPU != offsetof(struct thread_info, cpu) ||
+                    TI_FPSAVED != offsetof(struct thread_info, fpsaved) ||
+                    TI_KSP != offsetof(struct thread_info, ksp) ||
+                    TI_FAULT_ADDR != offsetof(struct thread_info,
+                                              fault_address) ||
+                    TI_KREGS != offsetof(struct thread_info, kregs) ||
+                    TI_UTRAPS != offsetof(struct thread_info, utraps) ||
+                    TI_EXEC_DOMAIN != offsetof(struct thread_info,
+                                               exec_domain) ||
+                    TI_REG_WINDOW != offsetof(struct thread_info,
+                                              reg_window) ||
+                    TI_RWIN_SPTRS != offsetof(struct thread_info,
+                                              rwbuf_stkptrs) ||
+                    TI_GSR != offsetof(struct thread_info, gsr) ||
+                    TI_XFSR != offsetof(struct thread_info, xfsr) ||
+                    TI_USER_CNTD0 != offsetof(struct thread_info,
+                                              user_cntd0) ||
+                    TI_USER_CNTD1 != offsetof(struct thread_info,
+                                              user_cntd1) ||
+                    TI_KERN_CNTD0 != offsetof(struct thread_info,
+                                              kernel_cntd0) ||
+                    TI_KERN_CNTD1 != offsetof(struct thread_info,
+                                              kernel_cntd1) ||
+                    TI_PCR != offsetof(struct thread_info, pcr_reg) ||
+                    TI_PRE_COUNT != offsetof(struct thread_info,
+                                             preempt_count) ||
+                    TI_NEW_CHILD != offsetof(struct thread_info, new_child) ||
+                    TI_SYS_NOERROR != offsetof(struct thread_info,
+                                               syscall_noerror) ||
+                    TI_RESTART_BLOCK != offsetof(struct thread_info,
+                                                 restart_block) ||
+                    TI_KUNA_REGS != offsetof(struct thread_info,
+                                             kern_una_regs) ||
+                    TI_KUNA_INSN != offsetof(struct thread_info,
+                                             kern_una_insn) ||
+                    TI_FPREGS != offsetof(struct thread_info, fpregs) ||
+                    (TI_FPREGS & (64 - 1)));
+
+       BUILD_BUG_ON(TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu,
+                                                    thread) ||
+                    (TRAP_PER_CPU_PGD_PADDR !=
+                     offsetof(struct trap_per_cpu, pgd_paddr)) ||
+                    (TRAP_PER_CPU_CPU_MONDO_PA !=
+                     offsetof(struct trap_per_cpu, cpu_mondo_pa)) ||
+                    (TRAP_PER_CPU_DEV_MONDO_PA !=
+                     offsetof(struct trap_per_cpu, dev_mondo_pa)) ||
+                    (TRAP_PER_CPU_RESUM_MONDO_PA !=
+                     offsetof(struct trap_per_cpu, resum_mondo_pa)) ||
+                    (TRAP_PER_CPU_RESUM_KBUF_PA !=
+                     offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) ||
+                    (TRAP_PER_CPU_NONRESUM_MONDO_PA !=
+                     offsetof(struct trap_per_cpu, nonresum_mondo_pa)) ||
+                    (TRAP_PER_CPU_NONRESUM_KBUF_PA !=
+                     offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) ||
+                    (TRAP_PER_CPU_FAULT_INFO !=
+                     offsetof(struct trap_per_cpu, fault_info)) ||
+                    (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA !=
+                     offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) ||
+                    (TRAP_PER_CPU_CPU_LIST_PA !=
+                     offsetof(struct trap_per_cpu, cpu_list_pa)) ||
+                    (TRAP_PER_CPU_TSB_HUGE !=
+                     offsetof(struct trap_per_cpu, tsb_huge)) ||
+                    (TRAP_PER_CPU_TSB_HUGE_TEMP !=
+                     offsetof(struct trap_per_cpu, tsb_huge_temp)) ||
+                    (TRAP_PER_CPU_IRQ_WORKLIST_PA !=
+                     offsetof(struct trap_per_cpu, irq_worklist_pa)) ||
+                    (TRAP_PER_CPU_CPU_MONDO_QMASK !=
+                     offsetof(struct trap_per_cpu, cpu_mondo_qmask)) ||
+                    (TRAP_PER_CPU_DEV_MONDO_QMASK !=
+                     offsetof(struct trap_per_cpu, dev_mondo_qmask)) ||
+                    (TRAP_PER_CPU_RESUM_QMASK !=
+                     offsetof(struct trap_per_cpu, resum_qmask)) ||
+                    (TRAP_PER_CPU_NONRESUM_QMASK !=
+                     offsetof(struct trap_per_cpu, nonresum_qmask)) ||
+                    (TRAP_PER_CPU_PER_CPU_BASE !=
+                     offsetof(struct trap_per_cpu, __per_cpu_base)));
+
+       BUILD_BUG_ON((TSB_CONFIG_TSB !=
+                     offsetof(struct tsb_config, tsb)) ||
+                    (TSB_CONFIG_RSS_LIMIT !=
+                     offsetof(struct tsb_config, tsb_rss_limit)) ||
+                    (TSB_CONFIG_NENTRIES !=
+                     offsetof(struct tsb_config, tsb_nentries)) ||
+                    (TSB_CONFIG_REG_VAL !=
+                     offsetof(struct tsb_config, tsb_reg_val)) ||
+                    (TSB_CONFIG_MAP_VADDR !=
+                     offsetof(struct tsb_config, tsb_map_vaddr)) ||
+                    (TSB_CONFIG_MAP_PTE !=
+                     offsetof(struct tsb_config, tsb_map_pte)));
 
        /* Attach to the address space of init_task.  On SMP we
         * do this in smp.c:smp_callin for other cpus.
index cbb282dab5a7e5d82ac386730d6b3e1244ee08e4..26bb3919ff1fe216eda103883b9ee0aec2f8208e 100644 (file)
@@ -358,6 +358,7 @@ void __init paging_init(void)
        protection_map[15] = PAGE_SHARED;
        btfixup();
        prom_build_devicetree();
+       of_fill_in_cpu_data();
        device_scan();
 }
 
index f26a352c08a068b0b915ddc0d309c394cb2fc966..ca92e2f54e4d5bd5f3e2f663ce2056eecb853c7e 100644 (file)
@@ -1679,11 +1679,6 @@ pgd_t swapper_pg_dir[2048];
 static void sun4u_pgprot_init(void);
 static void sun4v_pgprot_init(void);
 
-/* Dummy function */
-void __init setup_per_cpu_areas(void)
-{
-}
-
 void __init paging_init(void)
 {
        unsigned long end_pfn, shift, phys_base;
@@ -1799,16 +1794,13 @@ void __init paging_init(void)
        if (tlb_type == hypervisor)
                sun4v_ktsb_register();
 
-       /* We must setup the per-cpu areas before we pull in the
-        * PROM and the MDESC.  The code there fills in cpu and
-        * other information into per-cpu data structures.
-        */
-       real_setup_per_cpu_areas();
-
        prom_build_devicetree();
+       of_populate_present_mask();
 
-       if (tlb_type == hypervisor)
+       if (tlb_type == hypervisor) {
                sun4v_mdesc_init();
+               mdesc_populate_present_mask(cpu_all_mask);
+       }
 
        /* Once the OF device tree and MDESC have been setup, we know
         * the list of possible cpus.  Therefore we can allocate the
index 06c9a7d98206f0256c23a281381bf2d6ab7ca441..ade4eb373bddc2e9d6c85472d26a90e62d457e2b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/fs.h>
 #include <linux/seq_file.h>
 #include <linux/kdebug.h>
+#include <linux/log2.h>
 
 #include <asm/bitext.h>
 #include <asm/page.h>
@@ -349,7 +350,7 @@ static void srmmu_free_nocache(unsigned long vaddr, int size)
                    vaddr, srmmu_nocache_end);
                BUG();
        }
-       if (size & (size-1)) {
+       if (!is_power_of_2(size)) {
                printk("Size 0x%x is not a power of 2\n", size);
                BUG();
        }
index 434ba121e3c59a30009117fd6f1c146f516270a6..3b44b47c7e1d4615dbf73dd6f2e92997b9fa29c3 100644 (file)
@@ -360,7 +360,7 @@ static struct platform_driver uml_net_driver = {
 
 static void net_device_release(struct device *dev)
 {
-       struct uml_net *device = dev->driver_data;
+       struct uml_net *device = dev_get_drvdata(dev);
        struct net_device *netdev = device->dev;
        struct uml_net_private *lp = netdev_priv(netdev);
 
@@ -440,7 +440,7 @@ static void eth_configure(int n, void *init, char *mac,
        device->pdev.id = n;
        device->pdev.name = DRIVER_NAME;
        device->pdev.dev.release = net_device_release;
-       device->pdev.dev.driver_data = device;
+       dev_set_drvdata(&device->pdev.dev, device);
        if (platform_device_register(&device->pdev))
                goto out_free_netdev;
        SET_NETDEV_DEV(dev,&device->pdev.dev);
index aa9e926e13d73dca17015a5bd5f8e5eb76842c63..8f05d4d9da128788d0b5b7d5f39ac5fe2741bd61 100644 (file)
@@ -778,7 +778,7 @@ static int ubd_open_dev(struct ubd *ubd_dev)
 
 static void ubd_device_release(struct device *dev)
 {
-       struct ubd *ubd_dev = dev->driver_data;
+       struct ubd *ubd_dev = dev_get_drvdata(dev);
 
        blk_cleanup_queue(ubd_dev->queue);
        *ubd_dev = ((struct ubd) DEFAULT_UBD);
@@ -807,7 +807,7 @@ static int ubd_disk_register(int major, u64 size, int unit,
                ubd_devs[unit].pdev.id   = unit;
                ubd_devs[unit].pdev.name = DRIVER_NAME;
                ubd_devs[unit].pdev.dev.release = ubd_device_release;
-               ubd_devs[unit].pdev.dev.driver_data = &ubd_devs[unit];
+               dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
                platform_device_register(&ubd_devs[unit].pdev);
                disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
        }
index 2ac1f0c2beb3ba54088d4e0c4e89622dbc03094d..b07af8861244cd4f108181c061a3fab787a724b2 100644 (file)
@@ -182,6 +182,11 @@ static struct notifier_block __refdata cpuid_class_cpu_notifier =
        .notifier_call = cpuid_class_cpu_callback,
 };
 
+static char *cpuid_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt));
+}
+
 static int __init cpuid_init(void)
 {
        int i, err = 0;
@@ -198,6 +203,7 @@ static int __init cpuid_init(void)
                err = PTR_ERR(cpuid_class);
                goto out_chrdev;
        }
+       cpuid_class->nodename = cpuid_nodename;
        for_each_online_cpu(i) {
                err = cpuid_device_create(i);
                if (err != 0)
index 9c4461501fcbb9618ac3ce12fef93f990b8f3955..9371448290ac3c4f3a3489b0d9edbe55a5dd689b 100644 (file)
@@ -236,6 +236,7 @@ static const struct file_operations microcode_fops = {
 static struct miscdevice microcode_dev = {
        .minor                  = MICROCODE_MINOR,
        .name                   = "microcode",
+       .devnode                = "cpu/microcode",
        .fops                   = &microcode_fops,
 };
 
index 3cf3413ec626936f334c309f9a20f2a32a36de96..98fd6cd4e3a479e8e1cea7a4ccfad7063f921850 100644 (file)
@@ -196,6 +196,11 @@ static struct notifier_block __refdata msr_class_cpu_notifier = {
        .notifier_call = msr_class_cpu_callback,
 };
 
+static char *msr_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "cpu/%u/msr", MINOR(dev->devt));
+}
+
 static int __init msr_init(void)
 {
        int i, err = 0;
@@ -212,6 +217,7 @@ static int __init msr_init(void)
                err = PTR_ERR(msr_class);
                goto out_chrdev;
        }
+       msr_class->nodename = msr_nodename;
        for_each_online_cpu(i) {
                err = msr_device_create(i);
                if (err != 0)
index f6452f692501a00f13684a73fd74248e878d79cd..b06cf5c2a829c49a17dc4a23ab4421d8933b3401 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/swap.h>
 #include <linux/writeback.h>
 #include <linux/task_io_accounting_ops.h>
-#include <linux/blktrace_api.h>
 #include <linux/fault-inject.h>
 
 #define CREATE_TRACE_POINTS
@@ -498,6 +497,11 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 
        q->backing_dev_info.unplug_io_fn = blk_backing_dev_unplug;
        q->backing_dev_info.unplug_io_data = q;
+       q->backing_dev_info.ra_pages =
+                       (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
+       q->backing_dev_info.state = 0;
+       q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
+
        err = bdi_init(&q->backing_dev_info);
        if (err) {
                kmem_cache_free(blk_requestq_cachep, q);
index d71cedc09c4e237f05f99753ffe0f1f4cb5557f5..7541ea4bf9fe8bf62c5f85cc1b17b60d08e9a19a 100644 (file)
@@ -95,6 +95,31 @@ void blk_queue_lld_busy(struct request_queue *q, lld_busy_fn *fn)
 }
 EXPORT_SYMBOL_GPL(blk_queue_lld_busy);
 
+/**
+ * blk_set_default_limits - reset limits to default values
+ * @limits:  the queue_limits structure to reset
+ *
+ * Description:
+ *   Returns a queue_limit struct to its default state.  Can be used by
+ *   stacking drivers like DM that stage table swaps and reuse an
+ *   existing device queue.
+ */
+void blk_set_default_limits(struct queue_limits *lim)
+{
+       lim->max_phys_segments = MAX_PHYS_SEGMENTS;
+       lim->max_hw_segments = MAX_HW_SEGMENTS;
+       lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
+       lim->max_segment_size = MAX_SEGMENT_SIZE;
+       lim->max_sectors = lim->max_hw_sectors = SAFE_MAX_SECTORS;
+       lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
+       lim->bounce_pfn = BLK_BOUNCE_ANY;
+       lim->alignment_offset = 0;
+       lim->io_opt = 0;
+       lim->misaligned = 0;
+       lim->no_cluster = 0;
+}
+EXPORT_SYMBOL(blk_set_default_limits);
+
 /**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
@@ -123,18 +148,8 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
         * set defaults
         */
        q->nr_requests = BLKDEV_MAX_RQ;
-       blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
-       blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
-       blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK);
-       blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
 
        q->make_request_fn = mfn;
-       q->backing_dev_info.ra_pages =
-                       (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
-       q->backing_dev_info.state = 0;
-       q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
-       blk_queue_max_sectors(q, SAFE_MAX_SECTORS);
-       blk_queue_logical_block_size(q, 512);
        blk_queue_dma_alignment(q, 511);
        blk_queue_congestion_threshold(q);
        q->nr_batching = BLK_BATCH_REQ;
@@ -147,6 +162,8 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
        q->unplug_timer.function = blk_unplug_timeout;
        q->unplug_timer.data = (unsigned long)q;
 
+       blk_set_default_limits(&q->limits);
+
        /*
         * by default assume old behaviour and bounce for any highmem page
         */
index 5358f9ae13c1797b7eda131c7033c73a0c525162..54106f052f707bde6c4b89530d53a585c06366ce 100644 (file)
@@ -1065,6 +1065,11 @@ EXPORT_SYMBOL_GPL(bsg_register_queue);
 
 static struct cdev bsg_cdev;
 
+static char *bsg_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "bsg/%s", dev_name(dev));
+}
+
 static int __init bsg_init(void)
 {
        int ret, i;
@@ -1085,6 +1090,7 @@ static int __init bsg_init(void)
                ret = PTR_ERR(bsg_class);
                goto destroy_kmemcache;
        }
+       bsg_class->nodename = bsg_nodename;
 
        ret = alloc_chrdev_region(&devid, 0, BSG_MAX_DEVS, "bsg");
        if (ret)
index ef2f72d4243407ccfec220c867028f28b013b751..833ec18eaa63e2a20b847797c99511e41314b474 100644 (file)
@@ -122,7 +122,6 @@ struct cfq_data {
        struct cfq_queue *async_idle_cfqq;
 
        sector_t last_position;
-       unsigned long last_end_request;
 
        /*
         * tunables, see top of file
@@ -1253,7 +1252,7 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd)
 
        BUG_ON(cfqd->busy_queues);
 
-       cfq_log(cfqd, "forced_dispatch=%d\n", dispatched);
+       cfq_log(cfqd, "forced_dispatch=%d", dispatched);
        return dispatched;
 }
 
@@ -2164,9 +2163,6 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
        if (cfq_cfqq_sync(cfqq))
                cfqd->sync_flight--;
 
-       if (!cfq_class_idle(cfqq))
-               cfqd->last_end_request = now;
-
        if (sync)
                RQ_CIC(rq)->last_end_request = now;
 
@@ -2479,7 +2475,6 @@ static void *cfq_init_queue(struct request_queue *q)
 
        INIT_WORK(&cfqd->unplug_work, cfq_kick_queue);
 
-       cfqd->last_end_request = jiffies;
        cfqd->cfq_quantum = cfq_quantum;
        cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0];
        cfqd->cfq_fifo_expire[1] = cfq_fifo_expire[1];
index fe7ccc0a618f35e21ed7fbbe19ae49665270d498..f4c64c2b303a33e2f46bd10b01d36c2cd931b4d6 100644 (file)
@@ -996,10 +996,20 @@ struct class block_class = {
        .name           = "block",
 };
 
+static char *block_nodename(struct device *dev)
+{
+       struct gendisk *disk = dev_to_disk(dev);
+
+       if (disk->nodename)
+               return disk->nodename(disk);
+       return NULL;
+}
+
 static struct device_type disk_type = {
        .name           = "disk",
        .groups         = disk_attr_groups,
        .release        = disk_release,
+       .nodename       = block_nodename,
 };
 
 #ifdef CONFIG_PROC_FS
index 07e20135f01b30873d1f4aca495d7278a81962cd..0bba148a2c61fc084d52a58df1b1498b20ef6034 100644 (file)
@@ -139,7 +139,7 @@ acpi_status acpi_ev_initialize_op_regions(void);
 acpi_status
 acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                               u32 function,
-                              acpi_physical_address address,
+                              u32 region_offset,
                               u32 bit_width, acpi_integer * value);
 
 acpi_status
index 16e5210ae936288c17a76b0c7f82e93873b658fa..3d87362d17ed163851c3f5790fb4ecc4976e5c30 100644 (file)
@@ -362,9 +362,6 @@ extern u8 acpi_gbl_method_executing;
 extern u8 acpi_gbl_abort_method;
 extern u8 acpi_gbl_db_terminate_threads;
 
-ACPI_EXTERN int optind;
-ACPI_EXTERN char *optarg;
-
 ACPI_EXTERN u8 acpi_gbl_db_opt_tables;
 ACPI_EXTERN u8 acpi_gbl_db_opt_stats;
 ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods;
index 2ec394a328e95fea0f15d2e94aef9c32fda507dd..ee986edfa0da32704133b949624aa6ff75f3bea2 100644 (file)
@@ -205,6 +205,7 @@ struct acpi_namespace_node {
 #define ANOBJ_METHOD_LOCAL              0x08   /* Node is a method local */
 #define ANOBJ_SUBTREE_HAS_INI           0x10   /* Used to optimize device initialization */
 #define ANOBJ_EVALUATED                 0x20   /* Set on first evaluation of node */
+#define ANOBJ_ALLOCATED_BUFFER          0x40   /* Method AML buffer is dynamic (install_method) */
 
 #define ANOBJ_IS_EXTERNAL               0x08   /* i_aSL only: This object created via External() */
 #define ANOBJ_METHOD_NO_RETVAL          0x10   /* i_aSL only: Method has no return value */
@@ -788,11 +789,14 @@ struct acpi_bit_register_info {
 /* For control registers, both ignored and reserved bits must be preserved */
 
 /*
- * The ACPI spec says to ignore PM1_CTL.SCI_EN (bit 0)
- * but we need to be able to write ACPI_BITREG_SCI_ENABLE directly
- * as a BIOS workaround on some machines.
+ * For PM1 control, the SCI enable bit (bit 0, SCI_EN) is defined by the
+ * ACPI specification to be a "preserved" bit - "OSPM always preserves this
+ * bit position", section 4.7.3.2.1. However, on some machines the OS must
+ * write a one to this bit after resume for the machine to work properly.
+ * To enable this, we no longer attempt to preserve this bit. No machines
+ * are known to fail if the bit is not preserved. (May 2009)
  */
-#define ACPI_PM1_CONTROL_IGNORED_BITS           0x0200 /* Bits 9 */
+#define ACPI_PM1_CONTROL_IGNORED_BITS           0x0200 /* Bit 9 */
 #define ACPI_PM1_CONTROL_RESERVED_BITS          0xC1F8 /* Bits 14-15, 3-8 */
 #define ACPI_PM1_CONTROL_PRESERVED_BITS \
               (ACPI_PM1_CONTROL_IGNORED_BITS | ACPI_PM1_CONTROL_RESERVED_BITS)
index 46cb5b46d2803fd43bf7691bf0ee065fcf039dfc..94cdc2b8cb9385d6814005933810afd6d81e8d72 100644 (file)
@@ -99,10 +99,19 @@ acpi_ns_walk_namespace(acpi_object_type type,
                       acpi_walk_callback user_function,
                       void *context, void **return_value);
 
-struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node
-                                                 *parent, struct acpi_namespace_node
+struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
+                                                 *parent,
+                                                 struct acpi_namespace_node
                                                  *child);
 
+struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
+                                                       struct
+                                                       acpi_namespace_node
+                                                       *parent,
+                                                       struct
+                                                       acpi_namespace_node
+                                                       *child);
+
 /*
  * nsparse - table parsing
  */
index ff851c5df698a465a3c5e3d730b0a00d7d14ea07..067f967eb389cf720b2ee7d9a25b840ca3477443 100644 (file)
@@ -483,7 +483,7 @@ typedef enum {
 
 #define AML_METHOD_ARG_COUNT        0x07
 #define AML_METHOD_SERIALIZED       0x08
-#define AML_METHOD_SYNCH_LEVEL      0xF0
+#define AML_METHOD_SYNC_LEVEL       0xF0
 
 /* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */
 
index dab3f48f0b42938066b145c58a7b1c231139944d..02e6caad4a7610718bb4d52df924a86ef5bf10e4 100644 (file)
@@ -734,7 +734,8 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
 
                        /* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */
 
-                       obj_desc->reference.value = opcode - AML_LOCAL_OP;
+                       obj_desc->reference.value =
+                           ((u32)opcode) - AML_LOCAL_OP;
                        obj_desc->reference.class = ACPI_REFCLASS_LOCAL;
 
 #ifndef ACPI_NO_METHOD_EXECUTION
@@ -754,7 +755,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
 
                        /* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */
 
-                       obj_desc->reference.value = opcode - AML_ARG_OP;
+                       obj_desc->reference.value = ((u32)opcode) - AML_ARG_OP;
                        obj_desc->reference.class = ACPI_REFCLASS_ARG;
 
 #ifndef ACPI_NO_METHOD_EXECUTION
index b4c87b5053e6d1c6daeff5d68013672466061378..584d766e6f124248c1b496731df225fd94fa0099 100644 (file)
@@ -1386,14 +1386,19 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
 
        case AML_BREAK_POINT_OP:
 
-               /* Call up to the OS service layer to handle this */
-
-               status =
-                   acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,
-                                  "Executed AML Breakpoint opcode");
+               /*
+                * Set the single-step flag. This will cause the debugger (if present)
+                * to break to the console within the AML debugger at the start of the
+                * next AML instruction.
+                */
+               ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE);
+               ACPI_DEBUGGER_EXEC(acpi_os_printf
+                                  ("**break** Executed AML BreakPoint opcode\n"));
 
-               /* If and when it returns, all done. */
+               /* Call to the OSL in case OS wants a piece of the action */
 
+               status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,
+                                       "Executed AML Breakpoint opcode");
                break;
 
        case AML_BREAK_OP:
index 40f92bf7dce5cc2e7bf33cd5fd83013d544d4328..e46c821cf57295b7064bd58a333d1692e373451e 100644 (file)
@@ -102,7 +102,7 @@ acpi_ds_result_pop(union acpi_operand_object **object,
        /* Return object of the top element and clean that top element result stack */
 
        walk_state->result_count--;
-       index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
+       index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
 
        *object = state->results.obj_desc[index];
        if (!*object) {
@@ -186,7 +186,7 @@ acpi_ds_result_push(union acpi_operand_object * object,
 
        /* Assign the address of object to the top free element of result stack */
 
-       index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
+       index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
        state->results.obj_desc[index] = object;
        walk_state->result_count++;
 
index 538d63264555b321d473ef95942f8602d9fe4a51..98c7f9c626531f00e2bb9933c02ff61c8c0d42df 100644 (file)
@@ -275,7 +275,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
  *
  * PARAMETERS:  region_obj          - Internal region object
  *              Function            - Read or Write operation
- *              Address             - Where in the space to read or write
+ *              region_offset       - Where in the region to read or write
  *              bit_width           - Field width in bits (8, 16, 32, or 64)
  *              Value               - Pointer to in or out value, must be
  *                                    full 64-bit acpi_integer
@@ -290,7 +290,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
 acpi_status
 acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                               u32 function,
-                              acpi_physical_address address,
+                              u32 region_offset,
                               u32 bit_width, acpi_integer * value)
 {
        acpi_status status;
@@ -396,7 +396,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
        ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
                          "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
                          &region_obj->region.handler->address_space, handler,
-                         ACPI_FORMAT_NATIVE_UINT(address),
+                         ACPI_FORMAT_NATIVE_UINT(region_obj->region.address +
+                                                 region_offset),
                          acpi_ut_get_region_name(region_obj->region.
                                                  space_id)));
 
@@ -412,8 +413,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
 
        /* Call the handler */
 
-       status = handler(function, address, bit_width, value,
-                        handler_desc->address_space.context,
+       status = handler(function,
+                        (region_obj->region.address + region_offset),
+                        bit_width, value, handler_desc->address_space.context,
                         region_obj2->extra.region_context);
 
        if (ACPI_FAILURE(status)) {
index d0a080747ec35cf6c2754ca3c534cb618401800c..4721f58fe42c0653d6a6c14aee384ffbab2e708a 100644 (file)
@@ -51,7 +51,7 @@
 ACPI_MODULE_NAME("evxfevnt")
 
 /* Local prototypes */
-acpi_status
+static acpi_status
 acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                       struct acpi_gpe_block_info *gpe_block, void *context);
 
@@ -785,7 +785,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_gpe_device)
  *              block device. NULL if the GPE is one of the FADT-defined GPEs.
  *
  ******************************************************************************/
-acpi_status
+static acpi_status
 acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                       struct acpi_gpe_block_info *gpe_block, void *context)
 {
index 3deb20a126b215d706b162ea761fa8eb3ead0344..277fd609611aec1a92eb5717c21724425ce4f61a 100644 (file)
@@ -47,6 +47,7 @@
 #include "acnamesp.h"
 #include "actables.h"
 #include "acdispat.h"
+#include "acevents.h"
 
 #define _COMPONENT          ACPI_EXECUTER
 ACPI_MODULE_NAME("exconfig")
@@ -57,6 +58,10 @@ acpi_ex_add_table(u32 table_index,
                  struct acpi_namespace_node *parent_node,
                  union acpi_operand_object **ddb_handle);
 
+static acpi_status
+acpi_ex_region_read(union acpi_operand_object *obj_desc,
+                   u32 length, u8 *buffer);
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_add_table
@@ -91,6 +96,7 @@ acpi_ex_add_table(u32 table_index,
 
        /* Init the table handle */
 
+       obj_desc->common.flags |= AOPOBJ_DATA_VALID;
        obj_desc->reference.class = ACPI_REFCLASS_TABLE;
        *ddb_handle = obj_desc;
 
@@ -229,6 +235,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
                                       walk_state);
                if (ACPI_FAILURE(status)) {
                        (void)acpi_ex_unload_table(ddb_handle);
+
+                       acpi_ut_remove_reference(ddb_handle);
                        return_ACPI_STATUS(status);
                }
        }
@@ -252,6 +260,47 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
        return_ACPI_STATUS(status);
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_region_read
+ *
+ * PARAMETERS:  obj_desc        - Region descriptor
+ *              Length          - Number of bytes to read
+ *              Buffer          - Pointer to where to put the data
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Read data from an operation region. The read starts from the
+ *              beginning of the region.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer)
+{
+       acpi_status status;
+       acpi_integer value;
+       u32 region_offset = 0;
+       u32 i;
+
+       /* Bytewise reads */
+
+       for (i = 0; i < length; i++) {
+               status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
+                                                       region_offset, 8,
+                                                       &value);
+               if (ACPI_FAILURE(status)) {
+                       return status;
+               }
+
+               *buffer = (u8)value;
+               buffer++;
+               region_offset++;
+       }
+
+       return AE_OK;
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_load_op
@@ -314,18 +363,23 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                        }
                }
 
-               /*
-                * Map the table header and get the actual table length. The region
-                * length is not guaranteed to be the same as the table length.
-                */
-               table = acpi_os_map_memory(obj_desc->region.address,
-                                          sizeof(struct acpi_table_header));
+               /* Get the table header first so we can get the table length */
+
+               table = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
                if (!table) {
                        return_ACPI_STATUS(AE_NO_MEMORY);
                }
 
+               status =
+                   acpi_ex_region_read(obj_desc,
+                                       sizeof(struct acpi_table_header),
+                                       ACPI_CAST_PTR(u8, table));
                length = table->length;
-               acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+               ACPI_FREE(table);
+
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
+               }
 
                /* Must have at least an ACPI table header */
 
@@ -334,10 +388,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                }
 
                /*
-                * The memory region is not guaranteed to remain stable and we must
-                * copy the table to a local buffer. For example, the memory region
-                * is corrupted after suspend on some machines. Dynamically loaded
-                * tables are usually small, so this overhead is minimal.
+                * The original implementation simply mapped the table, with no copy.
+                * However, the memory region is not guaranteed to remain stable and
+                * we must copy the table to a local buffer. For example, the memory
+                * region is corrupted after suspend on some machines. Dynamically
+                * loaded tables are usually small, so this overhead is minimal.
+                *
+                * The latest implementation (5/2009) does not use a mapping at all.
+                * We use the low-level operation region interface to read the table
+                * instead of the obvious optimization of using a direct mapping.
+                * This maintains a consistent use of operation regions across the
+                * entire subsystem. This is important if additional processing must
+                * be performed in the (possibly user-installed) operation region
+                * handler. For example, acpi_exec and ASLTS depend on this.
                 */
 
                /* Allocate a buffer for the table */
@@ -347,17 +410,16 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                        return_ACPI_STATUS(AE_NO_MEMORY);
                }
 
-               /* Map the entire table and copy it */
+               /* Read the entire table */
 
-               table = acpi_os_map_memory(obj_desc->region.address, length);
-               if (!table) {
+               status = acpi_ex_region_read(obj_desc, length,
+                                            ACPI_CAST_PTR(u8,
+                                                          table_desc.pointer));
+               if (ACPI_FAILURE(status)) {
                        ACPI_FREE(table_desc.pointer);
-                       return_ACPI_STATUS(AE_NO_MEMORY);
+                       return_ACPI_STATUS(status);
                }
 
-               ACPI_MEMCPY(table_desc.pointer, table, length);
-               acpi_os_unmap_memory(table, length);
-
                table_desc.address = obj_desc->region.address;
                break;
 
@@ -454,6 +516,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(status);
        }
 
+       /* Remove the reference by added by acpi_ex_store above */
+
+       acpi_ut_remove_reference(ddb_handle);
+
        /* Invoke table handler if present */
 
        if (acpi_gbl_table_handler) {
@@ -495,13 +561,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
 
        /*
         * Validate the handle
-        * Although the handle is partially validated in acpi_ex_reconfiguration(),
+        * Although the handle is partially validated in acpi_ex_reconfiguration()
         * when it calls acpi_ex_resolve_operands(), the handle is more completely
         * validated here.
+        *
+        * Handle must be a valid operand object of type reference. Also, the
+        * ddb_handle must still be marked valid (table has not been previously
+        * unloaded)
         */
        if ((!ddb_handle) ||
            (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) ||
-           (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE)) {
+           (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) ||
+           (!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) {
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
@@ -509,6 +580,12 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
 
        table_index = table_desc->reference.value;
 
+       /* Ensure the table is still loaded */
+
+       if (!acpi_tb_is_table_loaded(table_index)) {
+               return_ACPI_STATUS(AE_NOT_EXIST);
+       }
+
        /* Invoke table handler if present */
 
        if (acpi_gbl_table_handler) {
@@ -530,8 +607,10 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
        (void)acpi_tb_release_owner_id(table_index);
        acpi_tb_set_table_loaded_flag(table_index, FALSE);
 
-       /* Table unloaded, remove a reference to the ddb_handle object */
-
-       acpi_ut_remove_reference(ddb_handle);
+       /*
+        * Invalidate the handle. We do this because the handle may be stored
+        * in a named object and may not be actually deleted until much later.
+        */
+       ddb_handle->common.flags &= ~AOPOBJ_DATA_VALID;
        return_ACPI_STATUS(AE_OK);
 }
index a57ad2564ab0c7c66a1594601efcf161971dd4be..02b25d233d994523323e673f3f7eb8e99efb4da4 100644 (file)
@@ -502,7 +502,7 @@ acpi_ex_create_method(u8 * aml_start,
                 * ACPI 2.0: sync_level = sync_level in method declaration
                 */
                obj_desc->method.sync_level = (u8)
-                   ((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4);
+                   ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
        }
 
        /* Attach the new object to the method Node */
index 89d141fdae0b463eb650d6224219ba2b42fd6ba6..ec524614e7087c42e3337614b319e2a2f67278ca 100644 (file)
@@ -120,9 +120,11 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = {
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"}
 };
 
-static struct acpi_exdump_info acpi_ex_dump_method[8] = {
+static struct acpi_exdump_info acpi_ex_dump_method[9] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL},
-       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "ParamCount"},
+       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.method_flags), "Method Flags"},
+       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count),
+        "Parameter Count"},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"},
index 99cee61e655d7ddae24b2e73061a119244826e80..d4075b8210217ecc5c503b54b4831aabe7ad83c2 100644 (file)
@@ -222,7 +222,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
 {
        acpi_status status;
        union acpi_operand_object *rgn_desc;
-       acpi_physical_address address;
+       u32 region_offset;
 
        ACPI_FUNCTION_TRACE(ex_access_region);
 
@@ -243,7 +243,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
         * 3) The current offset into the field
         */
        rgn_desc = obj_desc->common_field.region_obj;
-       address = rgn_desc->region.address +
+       region_offset =
            obj_desc->common_field.base_byte_offset + field_datum_byte_offset;
 
        if ((function & ACPI_IO_MASK) == ACPI_READ) {
@@ -260,16 +260,18 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
                              obj_desc->common_field.access_byte_width,
                              obj_desc->common_field.base_byte_offset,
                              field_datum_byte_offset, ACPI_CAST_PTR(void,
-                                                                    address)));
+                                                                    (rgn_desc->
+                                                                     region.
+                                                                     address +
+                                                                     region_offset))));
 
        /* Invoke the appropriate address_space/op_region handler */
 
-       status = acpi_ev_address_space_dispatch(rgn_desc, function,
-                                               address,
-                                               ACPI_MUL_8(obj_desc->
-                                                          common_field.
-                                                          access_byte_width),
-                                               value);
+       status =
+           acpi_ev_address_space_dispatch(rgn_desc, function, region_offset,
+                                          ACPI_MUL_8(obj_desc->common_field.
+                                                     access_byte_width),
+                                          value);
 
        if (ACPI_FAILURE(status)) {
                if (status == AE_NOT_IMPLEMENTED) {
index d301c1f363ef0fceb3749ee679d8f1366ec7fb32..2f0114202b05dc8a86e77b31075d3e930e96718f 100644 (file)
@@ -83,6 +83,15 @@ void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc)
 
        if (obj_desc->mutex.prev) {
                (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next;
+
+               /*
+                * Migrate the previous sync level associated with this mutex to the
+                * previous mutex on the list so that it may be preserved. This handles
+                * the case where several mutexes have been acquired at the same level,
+                * but are not released in opposite order.
+                */
+               (obj_desc->mutex.prev)->mutex.original_sync_level =
+                   obj_desc->mutex.original_sync_level;
        } else {
                thread->acquired_mutex_list = obj_desc->mutex.next;
        }
@@ -349,6 +358,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
                      struct acpi_walk_state *walk_state)
 {
        acpi_status status = AE_OK;
+       u8 previous_sync_level;
 
        ACPI_FUNCTION_TRACE(ex_release_mutex);
 
@@ -373,11 +383,12 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
             walk_state->thread->thread_id)
            && (obj_desc != acpi_gbl_global_lock_mutex)) {
                ACPI_ERROR((AE_INFO,
-                           "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
-                           (unsigned long)walk_state->thread->thread_id,
+                           "Thread %p cannot release Mutex [%4.4s] acquired by thread %p",
+                           ACPI_CAST_PTR(void, walk_state->thread->thread_id),
                            acpi_ut_get_node_name(obj_desc->mutex.node),
-                           (unsigned long)obj_desc->mutex.owner_thread->
-                           thread_id));
+                           ACPI_CAST_PTR(void,
+                                         obj_desc->mutex.owner_thread->
+                                         thread_id)));
                return_ACPI_STATUS(AE_AML_NOT_OWNER);
        }
 
@@ -391,10 +402,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
        }
 
        /*
-        * The sync level of the mutex must be less than or equal to the current
-        * sync level
+        * The sync level of the mutex must be equal to the current sync level. In
+        * other words, the current level means that at least one mutex at that
+        * level is currently being held. Attempting to release a mutex of a
+        * different level can only mean that the mutex ordering rule is being
+        * violated. This behavior is clarified in ACPI 4.0 specification.
         */
-       if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
+       if (obj_desc->mutex.sync_level !=
+           walk_state->thread->current_sync_level) {
                ACPI_ERROR((AE_INFO,
                            "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d",
                            acpi_ut_get_node_name(obj_desc->mutex.node),
@@ -403,14 +418,24 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
        }
 
+       /*
+        * Get the previous sync_level from the head of the acquired mutex list.
+        * This handles the case where several mutexes at the same level have been
+        * acquired, but are not released in reverse order.
+        */
+       previous_sync_level =
+           walk_state->thread->acquired_mutex_list->mutex.original_sync_level;
+
        status = acpi_ex_release_mutex_object(obj_desc);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
 
        if (obj_desc->mutex.acquisition_depth == 0) {
 
-               /* Restore the original sync_level */
+               /* Restore the previous sync_level */
 
-               walk_state->thread->current_sync_level =
-                   obj_desc->mutex.original_sync_level;
+               walk_state->thread->current_sync_level = previous_sync_level;
        }
        return_ACPI_STATUS(status);
 }
index 90d606196c99595f871f249c33d931442e7610f0..6efd07a4f779c5975b864eb81989f60a9f84019f 100644 (file)
@@ -193,10 +193,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
 
                case ACPI_REFCLASS_TABLE:
 
+                       /* Case for ddb_handle */
+
                        ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
                                              "Table Index 0x%X\n",
                                              source_desc->reference.value));
-                       break;
+                       return;
 
                default:
                        break;
index 7b2fb602b5cbf59a441a98950078e34a6d7f862b..23d5505cb1f779cf551730065e36e84580852975 100644 (file)
@@ -81,9 +81,9 @@ acpi_status acpi_hw_clear_acpi_status(void)
 
        ACPI_FUNCTION_TRACE(hw_clear_acpi_status);
 
-       ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %0llX\n",
+       ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
                          ACPI_BITMASK_ALL_FIXED_STATUS,
-                         acpi_gbl_xpm1a_status.address));
+                         ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address)));
 
        lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
 
index aceb93111967f35a7f0a335c4bcb2798c4d56304..efc971ab7d6512dbc47607bd25d6d976f28ddff6 100644 (file)
@@ -334,9 +334,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
 
                /* Get the next node in this scope (NULL if none) */
 
-               child_node =
-                   acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
-                                         child_node);
+               child_node = acpi_ns_get_next_node(parent_node, child_node);
                if (child_node) {
 
                        /* Found a child node - detach any attached object */
@@ -345,8 +343,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
 
                        /* Check if this node has any children */
 
-                       if (acpi_ns_get_next_node
-                           (ACPI_TYPE_ANY, child_node, NULL)) {
+                       if (child_node->child) {
                                /*
                                 * There is at least one child of this node,
                                 * visit the node
@@ -432,9 +429,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
                 * Get the next child of this parent node. When child_node is NULL,
                 * the first child of the parent is returned
                 */
-               child_node =
-                   acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
-                                         child_node);
+               child_node = acpi_ns_get_next_node(parent_node, child_node);
 
                if (deletion_node) {
                        acpi_ns_delete_children(deletion_node);
@@ -452,8 +447,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
 
                        /* Check if this node has any children */
 
-                       if (acpi_ns_get_next_node
-                           (ACPI_TYPE_ANY, child_node, NULL)) {
+                       if (child_node->child) {
                                /*
                                 * There is at least one child of this node,
                                 * visit the node
index ae3dc10a7e817c4c9f11d7c5d6549e7cff2e0f61..af8e6bcee07e5544112299df765c540a7b4c0602 100644 (file)
@@ -149,7 +149,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
 
        name_buffer = ACPI_ALLOCATE_ZEROED(size);
        if (!name_buffer) {
-               ACPI_ERROR((AE_INFO, "Allocation failure"));
+               ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size));
                return_PTR(NULL);
        }
 
index 3eb20bfda9d81a079c606d2e91ac85aa5dd8a859..60f3af08d28c3955fdee04607e99ce95befda017 100644 (file)
@@ -213,6 +213,15 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node)
                return_VOID;
        }
 
+       if (node->flags & ANOBJ_ALLOCATED_BUFFER) {
+
+               /* Free the dynamic aml buffer */
+
+               if (obj_desc->common.type == ACPI_TYPE_METHOD) {
+                       ACPI_FREE(obj_desc->method.aml_start);
+               }
+       }
+
        /* Clear the entry in all cases */
 
        node->object = NULL;
index d9e8cbc6e679732d9a362d71f604a51d1683d223..7f8e066b12a3d20b79a986a7e771d65eef3a332c 100644 (file)
@@ -144,7 +144,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
 
        pathname = acpi_ns_get_external_pathname(node);
        if (!pathname) {
-               pathname = ACPI_CAST_PTR(char, predefined->info.name);
+               return AE_OK;   /* Could not get pathname, ignore */
        }
 
        /*
@@ -230,10 +230,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
        }
 
       exit:
-       if (pathname != predefined->info.name) {
-               ACPI_FREE(pathname);
-       }
-
+       ACPI_FREE(pathname);
        return (status);
 }
 
index f9b4f51bf8f2445fb7a48879b9d7298874a776ee..7e865639a928746abb4d94039dc771d8d40245fa 100644 (file)
 #include "accommon.h"
 #include "acnamesp.h"
 
+#ifdef ACPI_ASL_COMPILER
+#include "amlcode.h"
+#endif
+
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nssearch")
 
index 83e3aa6d4b9b65ddcec28881939908007ae39698..35539df5c75dc965800e555bd1432d8ef11c9767 100644 (file)
@@ -52,8 +52,7 @@ ACPI_MODULE_NAME("nswalk")
  *
  * FUNCTION:    acpi_ns_get_next_node
  *
- * PARAMETERS:  Type                - Type of node to be searched for
- *              parent_node         - Parent node whose children we are
+ * PARAMETERS:  parent_node         - Parent node whose children we are
  *                                    getting
  *              child_node          - Previous child that was found.
  *                                    The NEXT child will be returned
@@ -66,27 +65,68 @@ ACPI_MODULE_NAME("nswalk")
  *              within Scope is returned.
  *
  ******************************************************************************/
-struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node
-                                                 *parent_node, struct acpi_namespace_node
+struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
+                                                 *parent_node,
+                                                 struct acpi_namespace_node
                                                  *child_node)
 {
-       struct acpi_namespace_node *next_node = NULL;
-
        ACPI_FUNCTION_ENTRY();
 
        if (!child_node) {
 
                /* It's really the parent's _scope_ that we want */
 
-               next_node = parent_node->child;
+               return parent_node->child;
        }
 
-       else {
-               /* Start search at the NEXT node */
-
-               next_node = acpi_ns_get_next_valid_node(child_node);
+       /*
+        * Get the next node.
+        *
+        * If we are at the end of this peer list, return NULL
+        */
+       if (child_node->flags & ANOBJ_END_OF_PEER_LIST) {
+               return NULL;
        }
 
+       /* Otherwise just return the next peer */
+
+       return child_node->peer;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_get_next_node_typed
+ *
+ * PARAMETERS:  Type                - Type of node to be searched for
+ *              parent_node         - Parent node whose children we are
+ *                                    getting
+ *              child_node          - Previous child that was found.
+ *                                    The NEXT child will be returned
+ *
+ * RETURN:      struct acpi_namespace_node - Pointer to the NEXT child or NULL if
+ *                                    none is found.
+ *
+ * DESCRIPTION: Return the next peer node within the namespace.  If Handle
+ *              is valid, Scope is ignored.  Otherwise, the first node
+ *              within Scope is returned.
+ *
+ ******************************************************************************/
+
+struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
+                                                       struct
+                                                       acpi_namespace_node
+                                                       *parent_node,
+                                                       struct
+                                                       acpi_namespace_node
+                                                       *child_node)
+{
+       struct acpi_namespace_node *next_node = NULL;
+
+       ACPI_FUNCTION_ENTRY();
+
+       next_node = acpi_ns_get_next_node(parent_node, child_node);
+
+
        /* If any type is OK, we are done */
 
        if (type == ACPI_TYPE_ANY) {
@@ -186,9 +226,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
                /* Get the next node in this scope.  Null if not found */
 
                status = AE_OK;
-               child_node =
-                   acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
-                                         child_node);
+               child_node = acpi_ns_get_next_node(parent_node, child_node);
                if (child_node) {
 
                        /* Found next child, get the type if we are not searching for ANY */
@@ -269,8 +307,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
                         * function has specified that the maximum depth has been reached.
                         */
                        if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
-                               if (acpi_ns_get_next_node
-                                   (ACPI_TYPE_ANY, child_node, NULL)) {
+                               if (child_node->child) {
 
                                        /* There is at least one child of this node, visit it */
 
index 9589fea2499790bc4fc989baeb3700d49137390e..f23593d6add4857f146527e29b130fed13c47ff9 100644 (file)
@@ -45,6 +45,8 @@
 #include <acpi/acpi.h>
 #include "accommon.h"
 #include "acnamesp.h"
+#include "acparser.h"
+#include "amlcode.h"
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsxfname")
@@ -358,3 +360,151 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_object_info)
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_install_method
+ *
+ * PARAMETERS:  Buffer         - An ACPI table containing one control method
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install a control method into the namespace. If the method
+ *              name already exists in the namespace, it is overwritten. The
+ *              input buffer must contain a valid DSDT or SSDT containing a
+ *              single control method.
+ *
+ ******************************************************************************/
+acpi_status acpi_install_method(u8 *buffer)
+{
+       struct acpi_table_header *table =
+           ACPI_CAST_PTR(struct acpi_table_header, buffer);
+       u8 *aml_buffer;
+       u8 *aml_start;
+       char *path;
+       struct acpi_namespace_node *node;
+       union acpi_operand_object *method_obj;
+       struct acpi_parse_state parser_state;
+       u32 aml_length;
+       u16 opcode;
+       u8 method_flags;
+       acpi_status status;
+
+       /* Parameter validation */
+
+       if (!buffer) {
+               return AE_BAD_PARAMETER;
+       }
+
+       /* Table must be a DSDT or SSDT */
+
+       if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) &&
+           !ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) {
+               return AE_BAD_HEADER;
+       }
+
+       /* First AML opcode in the table must be a control method */
+
+       parser_state.aml = buffer + sizeof(struct acpi_table_header);
+       opcode = acpi_ps_peek_opcode(&parser_state);
+       if (opcode != AML_METHOD_OP) {
+               return AE_BAD_PARAMETER;
+       }
+
+       /* Extract method information from the raw AML */
+
+       parser_state.aml += acpi_ps_get_opcode_size(opcode);
+       parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state);
+       path = acpi_ps_get_next_namestring(&parser_state);
+       method_flags = *parser_state.aml++;
+       aml_start = parser_state.aml;
+       aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start);
+
+       /*
+        * Allocate resources up-front. We don't want to have to delete a new
+        * node from the namespace if we cannot allocate memory.
+        */
+       aml_buffer = ACPI_ALLOCATE(aml_length);
+       if (!aml_buffer) {
+               return AE_NO_MEMORY;
+       }
+
+       method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
+       if (!method_obj) {
+               ACPI_FREE(aml_buffer);
+               return AE_NO_MEMORY;
+       }
+
+       /* Lock namespace for acpi_ns_lookup, we may be creating a new node */
+
+       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       if (ACPI_FAILURE(status)) {
+               goto error_exit;
+       }
+
+       /* The lookup either returns an existing node or creates a new one */
+
+       status =
+           acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1,
+                          ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND,
+                          NULL, &node);
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+
+       if (ACPI_FAILURE(status)) {     /* ns_lookup */
+               if (status != AE_ALREADY_EXISTS) {
+                       goto error_exit;
+               }
+
+               /* Node existed previously, make sure it is a method node */
+
+               if (node->type != ACPI_TYPE_METHOD) {
+                       status = AE_TYPE;
+                       goto error_exit;
+               }
+       }
+
+       /* Copy the method AML to the local buffer */
+
+       ACPI_MEMCPY(aml_buffer, aml_start, aml_length);
+
+       /* Initialize the method object with the new method's information */
+
+       method_obj->method.aml_start = aml_buffer;
+       method_obj->method.aml_length = aml_length;
+
+       method_obj->method.param_count = (u8)
+           (method_flags & AML_METHOD_ARG_COUNT);
+
+       method_obj->method.method_flags = (u8)
+           (method_flags & ~AML_METHOD_ARG_COUNT);
+
+       if (method_flags & AML_METHOD_SERIALIZED) {
+               method_obj->method.sync_level = (u8)
+                   ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
+       }
+
+       /*
+        * Now that it is complete, we can attach the new method object to
+        * the method Node (detaches/deletes any existing object)
+        */
+       status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD);
+
+       /*
+        * Flag indicates AML buffer is dynamic, must be deleted later.
+        * Must be set only after attach above.
+        */
+       node->flags |= ANOBJ_ALLOCATED_BUFFER;
+
+       /* Remove local reference to the method object */
+
+       acpi_ut_remove_reference(method_obj);
+       return status;
+
+error_exit:
+
+       ACPI_FREE(aml_buffer);
+       ACPI_FREE(method_obj);
+       return status;
+}
+ACPI_EXPORT_SYMBOL(acpi_install_method)
index 1c7efc15225f6a63dcf4fc5e8ff763bbe8f7e327..4071bad4458ed7d229bc04e30cb02abcb8efe26b 100644 (file)
@@ -162,6 +162,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_type)
 acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle)
 {
        struct acpi_namespace_node *node;
+       struct acpi_namespace_node *parent_node;
        acpi_status status;
 
        if (!ret_handle) {
@@ -189,12 +190,12 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle)
 
        /* Get the parent entry */
 
-       *ret_handle =
-           acpi_ns_convert_entry_to_handle(acpi_ns_get_parent_node(node));
+       parent_node = acpi_ns_get_parent_node(node);
+       *ret_handle = acpi_ns_convert_entry_to_handle(parent_node);
 
        /* Return exception if parent is null */
 
-       if (!acpi_ns_get_parent_node(node)) {
+       if (!parent_node) {
                status = AE_NULL_ENTRY;
        }
 
@@ -268,7 +269,7 @@ acpi_get_next_object(acpi_object_type type,
 
        /* Internal function does the real work */
 
-       node = acpi_ns_get_next_node(type, parent_node, child_node);
+       node = acpi_ns_get_next_node_typed(type, parent_node, child_node);
        if (!node) {
                status = AE_NOT_FOUND;
                goto unlock_and_exit;
index 88b5a2c4814d0423f60a02e1c994d5cb6c9e9775..3c4dcc3d1069097f4255b92d5b2eaa68119b8424 100644 (file)
@@ -547,7 +547,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
 
                if (!package_element ||
                    (package_element->common.type != ACPI_TYPE_PACKAGE)) {
-                       return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+                       return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
                }
 
                /*
@@ -593,9 +593,6 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
                        } else {
                                temp_size_needed +=
                                    acpi_ns_get_pathname_length((*sub_object_list)->reference.node);
-                               if (!temp_size_needed) {
-                                       return_ACPI_STATUS(AE_BAD_PARAMETER);
-                               }
                        }
                } else {
                        /*
index 69a2aa5b5d831ae83ac0ba901732a121f918ad16..395212bcd19b470d756efa5328dfc9d21464c603 100644 (file)
@@ -338,13 +338,17 @@ acpi_resource_to_address64(struct acpi_resource *resource,
        switch (resource->type) {
        case ACPI_RESOURCE_TYPE_ADDRESS16:
 
-               address16 = (struct acpi_resource_address16 *)&resource->data;
+               address16 =
+                   ACPI_CAST_PTR(struct acpi_resource_address16,
+                                 &resource->data);
                ACPI_COPY_ADDRESS(out, address16);
                break;
 
        case ACPI_RESOURCE_TYPE_ADDRESS32:
 
-               address32 = (struct acpi_resource_address32 *)&resource->data;
+               address32 =
+                   ACPI_CAST_PTR(struct acpi_resource_address32,
+                                 &resource->data);
                ACPI_COPY_ADDRESS(out, address32);
                break;
 
index 71e655d14cb0759a71fff3da12188f6c8a0f0679..82b02dcb942e75f9cfe3871464da16dc839cfc6e 100644 (file)
@@ -284,9 +284,9 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
        if (length > sizeof(struct acpi_table_fadt)) {
                ACPI_WARNING((AE_INFO,
                              "FADT (revision %u) is longer than ACPI 2.0 version, "
-                             "truncating length 0x%X to 0x%zX",
-                             table->revision, (unsigned)length,
-                             sizeof(struct acpi_table_fadt)));
+                             "truncating length 0x%X to 0x%X",
+                             table->revision, length,
+                             (u32)sizeof(struct acpi_table_fadt)));
        }
 
        /* Clear the entire local FADT */
@@ -441,7 +441,7 @@ static void acpi_tb_convert_fadt(void)
                                                                   &acpi_gbl_FADT,
                                                                   fadt_info_table
                                                                   [i].length),
-                                                    address32);
+                                                    (u64) address32);
                }
        }
 }
@@ -469,7 +469,6 @@ static void acpi_tb_convert_fadt(void)
 static void acpi_tb_validate_fadt(void)
 {
        char *name;
-       u32 *address32;
        struct acpi_generic_address *address64;
        u8 length;
        u32 i;
@@ -505,15 +504,12 @@ static void acpi_tb_validate_fadt(void)
 
        for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
                /*
-                * Generate pointers to the 32-bit and 64-bit addresses, get the
-                * register length (width), and the register name
+                * Generate pointer to the 64-bit address, get the register
+                * length (width) and the register name
                 */
                address64 = ACPI_ADD_PTR(struct acpi_generic_address,
                                         &acpi_gbl_FADT,
                                         fadt_info_table[i].address64);
-               address32 =
-                   ACPI_ADD_PTR(u32, &acpi_gbl_FADT,
-                                fadt_info_table[i].address32);
                length =
                    *ACPI_ADD_PTR(u8, &acpi_gbl_FADT,
                                  fadt_info_table[i].length);
index f865d5a096de28e2ab57bb2c9c5d295f7e354243..63e82329a9e858ca81e1169daf1bf0f4f40e0e14 100644 (file)
@@ -472,7 +472,7 @@ acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index)
         * lock may block, and also since the execution of a namespace walk
         * must be allowed to use the interpreter.
         */
-       acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
+       (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
        status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock);
 
        acpi_ns_delete_namespace_by_owner(owner_id);
index 919624f123d5ab4e6cb65b8ec23702c0d6d538ab..0f0c64bf8ac98d1cae2da0bdb073405d5f08d9e5 100644 (file)
@@ -676,6 +676,7 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
 {
        u16 reference_count;
        union acpi_operand_object *next_object;
+       acpi_status status;
 
        /* Save fields from destination that we don't want to overwrite */
 
@@ -768,6 +769,28 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
                }
                break;
 
+               /*
+                * For Mutex and Event objects, we cannot simply copy the underlying
+                * OS object. We must create a new one.
+                */
+       case ACPI_TYPE_MUTEX:
+
+               status = acpi_os_create_mutex(&dest_desc->mutex.os_mutex);
+               if (ACPI_FAILURE(status)) {
+                       return status;
+               }
+               break;
+
+       case ACPI_TYPE_EVENT:
+
+               status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0,
+                                                 &dest_desc->event.
+                                                 os_semaphore);
+               if (ACPI_FAILURE(status)) {
+                       return status;
+               }
+               break;
+
        default:
                /* Nothing to do for other simple objects */
                break;
index 38821f53042c34c215d6776ba6599434b3273f5f..527d729f681506d160c0e93611f60439c0dcb740 100644 (file)
@@ -179,9 +179,9 @@ acpi_debug_print(u32 requested_debug_level,
        if (thread_id != acpi_gbl_prev_thread_id) {
                if (ACPI_LV_THREADS & acpi_dbg_level) {
                        acpi_os_printf
-                           ("\n**** Context Switch from TID %lX to TID %lX ****\n\n",
-                            (unsigned long)acpi_gbl_prev_thread_id,
-                            (unsigned long)thread_id);
+                           ("\n**** Context Switch from TID %p to TID %p ****\n\n",
+                            ACPI_CAST_PTR(void, acpi_gbl_prev_thread_id),
+                            ACPI_CAST_PTR(void, thread_id));
                }
 
                acpi_gbl_prev_thread_id = thread_id;
@@ -194,7 +194,7 @@ acpi_debug_print(u32 requested_debug_level,
        acpi_os_printf("%8s-%04ld ", module_name, line_number);
 
        if (ACPI_LV_THREADS & acpi_dbg_level) {
-               acpi_os_printf("[%04lX] ", (unsigned long)thread_id);
+               acpi_os_printf("[%p] ", ACPI_CAST_PTR(void, thread_id));
        }
 
        acpi_os_printf("[%02ld] %-22.22s: ",
index a5ee23bc4f5563bcece4fe2a628016cf7a8c4208..bc1710315088a7304cfaa86bc9237f7ca0afd75f 100644 (file)
@@ -75,6 +75,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
        union acpi_operand_object *handler_desc;
        union acpi_operand_object *second_desc;
        union acpi_operand_object *next_desc;
+       union acpi_operand_object **last_obj_ptr;
 
        ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object);
 
@@ -223,6 +224,26 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
                         */
                        handler_desc = object->region.handler;
                        if (handler_desc) {
+                               next_desc =
+                                   handler_desc->address_space.region_list;
+                               last_obj_ptr =
+                                   &handler_desc->address_space.region_list;
+
+                               /* Remove the region object from the handler's list */
+
+                               while (next_desc) {
+                                       if (next_desc == object) {
+                                               *last_obj_ptr =
+                                                   next_desc->region.next;
+                                               break;
+                                       }
+
+                                       /* Walk the linked list of handler */
+
+                                       last_obj_ptr = &next_desc->region.next;
+                                       next_desc = next_desc->region.next;
+                               }
+
                                if (handler_desc->address_space.handler_flags &
                                    ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
 
index 1c9e250caefb0c0eb57809c543514b227bf89557..fbe782348b0bcf0111971398ac0dc752b2f6e92d 100644 (file)
@@ -1033,11 +1033,12 @@ acpi_error(const char *module_name, u32 line_number, const char *format, ...)
 {
        va_list args;
 
-       acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
+       acpi_os_printf("ACPI Error: ");
 
        va_start(args, format);
        acpi_os_vprintf(format, args);
-       acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+       acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
+                      line_number);
        va_end(args);
 }
 
@@ -1047,12 +1048,12 @@ acpi_exception(const char *module_name,
 {
        va_list args;
 
-       acpi_os_printf("ACPI Exception (%s-%04d): %s, ", module_name,
-                      line_number, acpi_format_exception(status));
+       acpi_os_printf("ACPI Exception: %s, ", acpi_format_exception(status));
 
        va_start(args, format);
        acpi_os_vprintf(format, args);
-       acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+       acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
+                      line_number);
        va_end(args);
 }
 
@@ -1061,11 +1062,12 @@ acpi_warning(const char *module_name, u32 line_number, const char *format, ...)
 {
        va_list args;
 
-       acpi_os_printf("ACPI Warning (%s-%04d): ", module_name, line_number);
+       acpi_os_printf("ACPI Warning: ");
 
        va_start(args, format);
        acpi_os_vprintf(format, args);
-       acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+       acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
+                      line_number);
        va_end(args);
 }
 
@@ -1074,10 +1076,6 @@ acpi_info(const char *module_name, u32 line_number, const char *format, ...)
 {
        va_list args;
 
-       /*
-        * Removed module_name, line_number, and acpica version, not needed
-        * for info output
-        */
        acpi_os_printf("ACPI: ");
 
        va_start(args, format);
index 26c93a748e64b10795e61eaf61991a980ceabc2f..80bb6515411791898cacbee2c3c71c92bcc85180 100644 (file)
@@ -230,17 +230,18 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
                        if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
                                if (i == mutex_id) {
                                        ACPI_ERROR((AE_INFO,
-                                                   "Mutex [%s] already acquired by this thread [%X]",
+                                                   "Mutex [%s] already acquired by this thread [%p]",
                                                    acpi_ut_get_mutex_name
                                                    (mutex_id),
-                                                   this_thread_id));
+                                                   ACPI_CAST_PTR(void,
+                                                                 this_thread_id)));
 
                                        return (AE_ALREADY_ACQUIRED);
                                }
 
                                ACPI_ERROR((AE_INFO,
-                                           "Invalid acquire order: Thread %X owns [%s], wants [%s]",
-                                           this_thread_id,
+                                           "Invalid acquire order: Thread %p owns [%s], wants [%s]",
+                                           ACPI_CAST_PTR(void, this_thread_id),
                                            acpi_ut_get_mutex_name(i),
                                            acpi_ut_get_mutex_name(mutex_id)));
 
@@ -251,24 +252,24 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
 #endif
 
        ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-                         "Thread %lX attempting to acquire Mutex [%s]\n",
-                         (unsigned long)this_thread_id,
+                         "Thread %p attempting to acquire Mutex [%s]\n",
+                         ACPI_CAST_PTR(void, this_thread_id),
                          acpi_ut_get_mutex_name(mutex_id)));
 
        status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
                                       ACPI_WAIT_FOREVER);
        if (ACPI_SUCCESS(status)) {
                ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-                                 "Thread %lX acquired Mutex [%s]\n",
-                                 (unsigned long)this_thread_id,
+                                 "Thread %p acquired Mutex [%s]\n",
+                                 ACPI_CAST_PTR(void, this_thread_id),
                                  acpi_ut_get_mutex_name(mutex_id)));
 
                acpi_gbl_mutex_info[mutex_id].use_count++;
                acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id;
        } else {
                ACPI_EXCEPTION((AE_INFO, status,
-                               "Thread %lX could not acquire Mutex [%X]",
-                               (unsigned long)this_thread_id, mutex_id));
+                               "Thread %p could not acquire Mutex [%X]",
+                               ACPI_CAST_PTR(void, this_thread_id), mutex_id));
        }
 
        return (status);
@@ -293,9 +294,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
        ACPI_FUNCTION_NAME(ut_release_mutex);
 
        this_thread_id = acpi_os_get_thread_id();
-       ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-                         "Thread %lX releasing Mutex [%s]\n",
-                         (unsigned long)this_thread_id,
+       ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %p releasing Mutex [%s]\n",
+                         ACPI_CAST_PTR(void, this_thread_id),
                          acpi_ut_get_mutex_name(mutex_id)));
 
        if (mutex_id > ACPI_MAX_MUTEX) {
index 1977d4beb89e0012290a567c850f6a59dd3da1b0..7ecb1938e590f34526beaaeda2a3f6683f4024ce 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/kallsyms.h>
 #include <linux/semaphore.h>
 #include <linux/mutex.h>
+#include <linux/async.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -161,10 +162,18 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
        struct device *dev = to_dev(kobj);
        int retval = 0;
 
-       /* add the major/minor if present */
+       /* add device node properties if present */
        if (MAJOR(dev->devt)) {
+               const char *tmp;
+               const char *name;
+
                add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
                add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
+               name = device_get_nodename(dev, &tmp);
+               if (name) {
+                       add_uevent_var(env, "DEVNAME=%s", name);
+                       kfree(tmp);
+               }
        }
 
        if (dev->type && dev->type->name)
@@ -874,7 +883,7 @@ int device_add(struct device *dev)
         * the name, and force the use of dev_name()
         */
        if (dev->init_name) {
-               dev_set_name(dev, dev->init_name);
+               dev_set_name(dev, "%s", dev->init_name);
                dev->init_name = NULL;
        }
 
@@ -1127,6 +1136,47 @@ static struct device *next_device(struct klist_iter *i)
        return dev;
 }
 
+/**
+ * device_get_nodename - path of device node file
+ * @dev: device
+ * @tmp: possibly allocated string
+ *
+ * Return the relative path of a possible device node.
+ * Non-default names may need to allocate a memory to compose
+ * a name. This memory is returned in tmp and needs to be
+ * freed by the caller.
+ */
+const char *device_get_nodename(struct device *dev, const char **tmp)
+{
+       char *s;
+
+       *tmp = NULL;
+
+       /* the device type may provide a specific name */
+       if (dev->type && dev->type->nodename)
+               *tmp = dev->type->nodename(dev);
+       if (*tmp)
+               return *tmp;
+
+       /* the class may provide a specific name */
+       if (dev->class && dev->class->nodename)
+               *tmp = dev->class->nodename(dev);
+       if (*tmp)
+               return *tmp;
+
+       /* return name without allocation, tmp == NULL */
+       if (strchr(dev_name(dev), '!') == NULL)
+               return dev_name(dev);
+
+       /* replace '!' in the name with '/' */
+       *tmp = kstrdup(dev_name(dev), GFP_KERNEL);
+       if (!*tmp)
+               return NULL;
+       while ((s = strchr(*tmp, '!')))
+               s[0] = '/';
+       return *tmp;
+}
+
 /**
  * device_for_each_child - device child iterator.
  * @parent: parent struct device.
@@ -1271,7 +1321,7 @@ struct device *__root_device_register(const char *name, struct module *owner)
        if (!root)
                return ERR_PTR(err);
 
-       err = dev_set_name(&root->dev, name);
+       err = dev_set_name(&root->dev, "%s", name);
        if (err) {
                kfree(root);
                return ERR_PTR(err);
@@ -1665,4 +1715,5 @@ void device_shutdown(void)
        kobject_put(sysfs_dev_char_kobj);
        kobject_put(sysfs_dev_block_kobj);
        kobject_put(dev_kobj);
+       async_synchronize_full();
 }
index 742cbe6b042bbf711054e2cd7f02cdcc66354752..f0106875f01da48f9fb70afb6b2a68ac7259e37a 100644 (file)
@@ -226,7 +226,7 @@ static int __device_attach(struct device_driver *drv, void *data)
  * pair is found, break out and return.
  *
  * Returns 1 if the device was bound to a driver;
- * 0 if no matching device was found;
+ * 0 if no matching driver was found;
  * -ENODEV if the device is not registered.
  *
  * When called for a USB interface, @dev->parent->sem must be held.
@@ -320,6 +320,10 @@ static void __device_release_driver(struct device *dev)
                devres_release_all(dev);
                dev->driver = NULL;
                klist_remove(&dev->p->knode_driver);
+               if (dev->bus)
+                       blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
+                                                    BUS_NOTIFY_UNBOUND_DRIVER,
+                                                    dev);
        }
 }
 
index 8a267c4276291bb775e2590a6935825ae35e9305..ddeb819c8f878a3cf07c18ed9d6d2c3ffe082e46 100644 (file)
@@ -40,7 +40,7 @@ static int loading_timeout = 60;      /* In seconds */
 static DEFINE_MUTEX(fw_lock);
 
 struct firmware_priv {
-       char fw_id[FIRMWARE_NAME_MAX];
+       char *fw_id;
        struct completion completion;
        struct bin_attribute attr_data;
        struct firmware *fw;
@@ -355,8 +355,9 @@ static void fw_dev_release(struct device *dev)
        for (i = 0; i < fw_priv->nr_pages; i++)
                __free_page(fw_priv->pages[i]);
        kfree(fw_priv->pages);
+       kfree(fw_priv->fw_id);
        kfree(fw_priv);
-       kfree(dev);
+       put_device(dev);
 
        module_put(THIS_MODULE);
 }
@@ -386,13 +387,19 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
 
        init_completion(&fw_priv->completion);
        fw_priv->attr_data = firmware_attr_data_tmpl;
-       strlcpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX);
+       fw_priv->fw_id = kstrdup(fw_name, GFP_KERNEL);
+       if (!fw_priv->fw_id) {
+               dev_err(device, "%s: Firmware name allocation failed\n",
+                       __func__);
+               retval = -ENOMEM;
+               goto error_kfree;
+       }
 
        fw_priv->timeout.function = firmware_class_timeout;
        fw_priv->timeout.data = (u_long) fw_priv;
        init_timer(&fw_priv->timeout);
 
-       dev_set_name(f_dev, dev_name(device));
+       dev_set_name(f_dev, "%s", dev_name(device));
        f_dev->parent = device;
        f_dev->class = &firmware_class;
        dev_set_drvdata(f_dev, fw_priv);
@@ -400,14 +407,17 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
        retval = device_register(f_dev);
        if (retval) {
                dev_err(device, "%s: device_register failed\n", __func__);
-               goto error_kfree;
+               put_device(f_dev);
+               goto error_kfree_fw_id;
        }
        *dev_p = f_dev;
        return 0;
 
+error_kfree_fw_id:
+       kfree(fw_priv->fw_id);
 error_kfree:
-       kfree(fw_priv);
        kfree(f_dev);
+       kfree(fw_priv);
        return retval;
 }
 
@@ -615,8 +625,9 @@ request_firmware_work_func(void *arg)
  * @cont: function will be called asynchronously when the firmware
  *     request is over.
  *
- *     Asynchronous variant of request_firmware() for contexts where
- *     it is not possible to sleep.
+ *     Asynchronous variant of request_firmware() for user contexts where
+ *     it is not possible to sleep for long time. It can't be called
+ *     in atomic contexts.
  **/
 int
 request_firmware_nowait(
index ead3f64c41d0506774788860f0f2232f22c9ce0a..81cb01bfc356294865a4e04721d77d5a9c64ffff 100644 (file)
@@ -69,7 +69,8 @@ EXPORT_SYMBOL_GPL(platform_get_irq);
  * @name: resource name
  */
 struct resource *platform_get_resource_byname(struct platform_device *dev,
-                                             unsigned int type, char *name)
+                                             unsigned int type,
+                                             const char *name)
 {
        int i;
 
@@ -88,7 +89,7 @@ EXPORT_SYMBOL_GPL(platform_get_resource_byname);
  * @dev: platform device
  * @name: IRQ name
  */
-int platform_get_irq_byname(struct platform_device *dev, char *name)
+int platform_get_irq_byname(struct platform_device *dev, const char *name)
 {
        struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ,
                                                          name);
@@ -244,7 +245,7 @@ int platform_device_add(struct platform_device *pdev)
        if (pdev->id != -1)
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
        else
-               dev_set_name(&pdev->dev, pdev->name);
+               dev_set_name(&pdev->dev, "%s", pdev->name);
 
        for (i = 0; i < pdev->num_resources; i++) {
                struct resource *p, *r = &pdev->resource[i];
index 9742a78c9fe42a043bfa0c57e89ead65e4f6fc2f..79a9ae5238acc1b9fa06a2fed1ed70d2440a9416 100644 (file)
@@ -131,6 +131,8 @@ static struct kset *system_kset;
 
 int sysdev_class_register(struct sysdev_class *cls)
 {
+       int retval;
+
        pr_debug("Registering sysdev class '%s'\n", cls->name);
 
        INIT_LIST_HEAD(&cls->drivers);
@@ -138,7 +140,11 @@ int sysdev_class_register(struct sysdev_class *cls)
        cls->kset.kobj.parent = &system_kset->kobj;
        cls->kset.kobj.ktype = &ktype_sysdev_class;
        cls->kset.kobj.kset = system_kset;
-       kobject_set_name(&cls->kset.kobj, cls->name);
+
+       retval = kobject_set_name(&cls->kset.kobj, "%s", cls->name);
+       if (retval)
+               return retval;
+
        return kset_register(&cls->kset);
 }
 
index 200efc4d2c1e756cd9a7182709bbfb2328a57140..19888354188f7f4c4afb0f1c37050cc1d06805fc 100644 (file)
@@ -266,6 +266,11 @@ static const struct file_operations aoe_fops = {
        .owner = THIS_MODULE,
 };
 
+static char *aoe_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev));
+}
+
 int __init
 aoechr_init(void)
 {
@@ -283,6 +288,8 @@ aoechr_init(void)
                unregister_chrdev(AOE_MAJOR, "aoechr");
                return PTR_ERR(aoe_class);
        }
+       aoe_class->nodename = aoe_nodename;
+
        for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
                device_create(aoe_class, NULL,
                              MKDEV(AOE_MAJOR, chardevs[i].minor), NULL,
index b22cec97ea194e148427f998a5c310bc3eedf262..c7a527c08a0980d542c1fffbd30687bbc95289d0 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
 #include <linux/compat.h>
-#include <linux/blktrace_api.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
index 60de5a01e71e6ecd67b15eee29fef7d567265872..f703f54782469e2ae9491cbd6d6dd89708fb8a55 100644 (file)
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
+#include <linux/mg_disk.h>
 
 #define MG_RES_SEC (CONFIG_MG_DISK_RES << 1)
 
 /* name for block device */
 #define MG_DISK_NAME "mgd"
-/* name for platform device */
-#define MG_DEV_NAME "mg_disk"
 
 #define MG_DISK_MAJ 0
 #define MG_DISK_MAX_PART 16
 #define MG_TMAX_SWRST_TO_RDY   500
 #define MG_TMAX_RSTOUT         3000
 
-/* device attribution */
-/* use mflash as boot device */
-#define MG_BOOT_DEV            (1 << 0)
-/* use mflash as storage device */
-#define MG_STORAGE_DEV         (1 << 1)
-/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */
-#define MG_STORAGE_DEV_SKIP_RST        (1 << 2)
-
 #define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST)
 
-/* names of GPIO resource */
-#define MG_RST_PIN     "mg_rst"
-/* except MG_BOOT_DEV, reset-out pin should be assigned */
-#define MG_RSTOUT_PIN  "mg_rstout"
-
-/* private driver data */
-struct mg_drv_data {
-       /* disk resource */
-       u32 use_polling;
-
-       /* device attribution */
-       u32 dev_attr;
-
-       /* internally used */
-       struct mg_host *host;
-};
-
 /* main structure for mflash driver */
 struct mg_host {
        struct device *dev;
index d57f11759480c1c2874922e773cee62ac6571472..83650e00632d80b6837678355fbac3c50c6d9a94 100644 (file)
@@ -430,7 +430,7 @@ static void pkt_sysfs_cleanup(void)
 /********************************************************************
   entries in debugfs
 
-  /debugfs/pktcdvd[0-7]/
+  /sys/kernel/debug/pktcdvd[0-7]/
                        info
 
  *******************************************************************/
@@ -2855,6 +2855,11 @@ static struct block_device_operations pktcdvd_ops = {
        .media_changed =        pkt_media_changed,
 };
 
+static char *pktcdvd_nodename(struct gendisk *gd)
+{
+       return kasprintf(GFP_KERNEL, "pktcdvd/%s", gd->disk_name);
+}
+
 /*
  * Set up mapping from pktcdvd device to CD-ROM device.
  */
@@ -2907,6 +2912,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
        disk->fops = &pktcdvd_ops;
        disk->flags = GENHD_FL_REMOVABLE;
        strcpy(disk->disk_name, pd->name);
+       disk->nodename = pktcdvd_nodename;
        disk->private_data = pd;
        disk->queue = blk_alloc_queue(GFP_KERNEL);
        if (!disk->queue)
@@ -3062,6 +3068,7 @@ static const struct file_operations pkt_ctl_fops = {
 static struct miscdevice pkt_misc = {
        .minor          = MISC_DYNAMIC_MINOR,
        .name           = DRIVER_NAME,
+       .name           = "pktcdvd/control",
        .fops           = &pkt_ctl_fops
 };
 
index aaeeb544228a322efc790482f206f48afdf829a8..34cbb7f3efa89e5504920d547b081c86fe9ca4e9 100644 (file)
@@ -120,7 +120,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
 static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
                                     struct request *req)
 {
-       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
        int write = rq_data_dir(req), res;
        const char *op = write ? "write" : "read";
        u64 start_sector, sectors;
@@ -168,7 +168,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
 static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
                                        struct request *req)
 {
-       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
        u64 res;
 
        dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__);
@@ -213,7 +213,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev,
 static void ps3disk_request(struct request_queue *q)
 {
        struct ps3_storage_device *dev = q->queuedata;
-       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
 
        if (priv->req) {
                dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
@@ -245,7 +245,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
                return IRQ_HANDLED;
        }
 
-       priv = dev->sbd.core.driver_data;
+       priv = ps3_system_bus_get_drvdata(&dev->sbd);
        req = priv->req;
        if (!req) {
                dev_dbg(&dev->sbd.core,
@@ -364,7 +364,7 @@ static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs,
 
 static int ps3disk_identify(struct ps3_storage_device *dev)
 {
-       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
        struct lv1_ata_cmnd_block ata_cmnd;
        u16 *id = dev->bounce_buf;
        u64 res;
@@ -445,7 +445,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
                goto fail;
        }
 
-       dev->sbd.core.driver_data = priv;
+       ps3_system_bus_set_drvdata(_dev, priv);
        spin_lock_init(&priv->lock);
 
        dev->bounce_size = BOUNCE_SIZE;
@@ -523,7 +523,7 @@ fail_free_bounce:
        kfree(dev->bounce_buf);
 fail_free_priv:
        kfree(priv);
-       dev->sbd.core.driver_data = NULL;
+       ps3_system_bus_set_drvdata(_dev, NULL);
 fail:
        mutex_lock(&ps3disk_mask_mutex);
        __clear_bit(devidx, &ps3disk_mask);
@@ -534,7 +534,7 @@ fail:
 static int ps3disk_remove(struct ps3_system_bus_device *_dev)
 {
        struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
-       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
 
        mutex_lock(&ps3disk_mask_mutex);
        __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS,
@@ -548,7 +548,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev)
        ps3stor_teardown(dev);
        kfree(dev->bounce_buf);
        kfree(priv);
-       dev->sbd.core.driver_data = NULL;
+       ps3_system_bus_set_drvdata(_dev, NULL);
        return 0;
 }
 
index 8eddef373a9197d9db8834d5ba15d1f743b85ee2..095f97e6066562671eaad46eed57478aa3bafaf7 100644 (file)
 #include <linux/seq_file.h>
 
 #include <asm/firmware.h>
+#include <asm/iommu.h>
 #include <asm/lv1call.h>
 #include <asm/ps3.h>
+#include <asm/ps3gpu.h>
 
 
 #define DEVICE_NAME            "ps3vram"
@@ -45,8 +47,6 @@
 #define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN   0x0000030c
 #define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY      0x00000104
 
-#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
-
 #define CACHE_PAGE_PRESENT 1
 #define CACHE_PAGE_DIRTY   2
 
@@ -72,8 +72,7 @@ struct ps3vram_priv {
        u64 memory_handle;
        u64 context_handle;
        u32 *ctrl;
-       u32 *reports;
-       u8 __iomem *ddr_base;
+       void *reports;
        u8 *xdr_buf;
 
        u32 *fifo_base;
@@ -81,8 +80,8 @@ struct ps3vram_priv {
 
        struct ps3vram_cache cache;
 
-       /* Used to serialize cache/DMA operations */
-       struct mutex lock;
+       spinlock_t lock;        /* protecting list of bios */
+       struct bio_list list;
 };
 
 
@@ -103,15 +102,15 @@ static char *size = "256M";
 module_param(size, charp, 0);
 MODULE_PARM_DESC(size, "memory size");
 
-static u32 *ps3vram_get_notifier(u32 *reports, int notifier)
+static u32 *ps3vram_get_notifier(void *reports, int notifier)
 {
-       return (void *)reports + DMA_NOTIFIER_OFFSET_BASE +
+       return reports + DMA_NOTIFIER_OFFSET_BASE +
               DMA_NOTIFIER_SIZE * notifier;
 }
 
 static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
        int i;
 
@@ -122,7 +121,7 @@ static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev)
 static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
                                 unsigned int timeout_ms)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
        unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
 
@@ -137,7 +136,7 @@ static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
 
 static void ps3vram_init_ring(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
        priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET;
@@ -146,7 +145,7 @@ static void ps3vram_init_ring(struct ps3_system_bus_device *dev)
 static int ps3vram_wait_ring(struct ps3_system_bus_device *dev,
                             unsigned int timeout_ms)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
 
        do {
@@ -175,7 +174,7 @@ static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, u32 tag,
 
 static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        int status;
 
        ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET));
@@ -183,20 +182,17 @@ static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev)
        priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
 
        /* asking the HV for a blit will kick the FIFO */
-       status = lv1_gpu_context_attribute(priv->context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
-                                          0, 0, 0);
+       status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0);
        if (status)
-               dev_err(&dev->core,
-                       "%s: lv1_gpu_context_attribute failed %d\n", __func__,
-                       status);
+               dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n",
+                       __func__, status);
 
        priv->fifo_ptr = priv->fifo_base;
 }
 
 static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        int status;
 
        mutex_lock(&ps3_gpu_mutex);
@@ -205,13 +201,10 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
                               (priv->fifo_ptr - priv->fifo_base) * sizeof(u32);
 
        /* asking the HV for a blit will kick the FIFO */
-       status = lv1_gpu_context_attribute(priv->context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
-                                          0, 0, 0);
+       status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0);
        if (status)
-               dev_err(&dev->core,
-                       "%s: lv1_gpu_context_attribute failed %d\n", __func__,
-                       status);
+               dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n",
+                       __func__, status);
 
        if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) >
            FIFO_SIZE - 1024) {
@@ -225,7 +218,7 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
 
 static void ps3vram_bind(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1);
        ps3vram_out_ring(priv, 0x31337303);
@@ -248,7 +241,7 @@ static int ps3vram_upload(struct ps3_system_bus_device *dev,
                          unsigned int src_offset, unsigned int dst_offset,
                          int len, int count)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        ps3vram_begin_ring(priv, UPLOAD_SUBCH,
                           NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
@@ -280,7 +273,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev,
                            unsigned int src_offset, unsigned int dst_offset,
                            int len, int count)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
                           NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
@@ -310,7 +303,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev,
 
 static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        struct ps3vram_cache *cache = &priv->cache;
 
        if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY))
@@ -332,7 +325,7 @@ static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry)
 static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry,
                               unsigned int address)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        struct ps3vram_cache *cache = &priv->cache;
 
        dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address);
@@ -352,7 +345,7 @@ static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry,
 
 static void ps3vram_cache_flush(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        struct ps3vram_cache *cache = &priv->cache;
        int i;
 
@@ -366,7 +359,7 @@ static void ps3vram_cache_flush(struct ps3_system_bus_device *dev)
 static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev,
                                        loff_t address)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        struct ps3vram_cache *cache = &priv->cache;
        unsigned int base;
        unsigned int offset;
@@ -400,7 +393,7 @@ static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev,
 
 static int ps3vram_cache_init(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        priv->cache.page_count = CACHE_PAGE_COUNT;
        priv->cache.page_size = CACHE_PAGE_SIZE;
@@ -419,7 +412,7 @@ static int ps3vram_cache_init(struct ps3_system_bus_device *dev)
 
 static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        ps3vram_cache_flush(dev);
        kfree(priv->cache.tags);
@@ -428,7 +421,7 @@ static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev)
 static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
                        size_t len, size_t *retlen, u_char *buf)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        unsigned int cached, count;
 
        dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__,
@@ -449,8 +442,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
                offset = (unsigned int) (from & (priv->cache.page_size - 1));
                avail  = priv->cache.page_size - offset;
 
-               mutex_lock(&priv->lock);
-
                entry = ps3vram_cache_match(dev, from);
                cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
 
@@ -462,8 +453,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
                        avail = count;
                memcpy(buf, priv->xdr_buf + cached, avail);
 
-               mutex_unlock(&priv->lock);
-
                buf += avail;
                count -= avail;
                from += avail;
@@ -476,7 +465,7 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
 static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
                         size_t len, size_t *retlen, const u_char *buf)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        unsigned int cached, count;
 
        if (to >= priv->size)
@@ -494,8 +483,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
                offset = (unsigned int) (to & (priv->cache.page_size - 1));
                avail  = priv->cache.page_size - offset;
 
-               mutex_lock(&priv->lock);
-
                entry = ps3vram_cache_match(dev, to);
                cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
 
@@ -509,8 +496,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
 
                priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY;
 
-               mutex_unlock(&priv->lock);
-
                buf += avail;
                count -= avail;
                to += avail;
@@ -543,28 +528,26 @@ static const struct file_operations ps3vram_proc_fops = {
 
 static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        struct proc_dir_entry *pde;
 
-       pde = proc_create(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops);
-       if (!pde) {
+       pde = proc_create_data(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops,
+                              priv);
+       if (!pde)
                dev_warn(&dev->core, "failed to create /proc entry\n");
-               return;
-       }
-       pde->data = priv;
 }
 
-static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
+static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev,
+                                 struct bio *bio)
 {
-       struct ps3_system_bus_device *dev = q->queuedata;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        int write = bio_data_dir(bio) == WRITE;
        const char *op = write ? "write" : "read";
        loff_t offset = bio->bi_sector << 9;
        int error = 0;
        struct bio_vec *bvec;
        unsigned int i;
-
-       dev_dbg(&dev->core, "%s\n", __func__);
+       struct bio *next;
 
        bio_for_each_segment(bvec, bio, i) {
                /* PS3 is ppc64, so we don't handle highmem */
@@ -585,6 +568,7 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
 
                if (retlen != len) {
                        dev_err(&dev->core, "Short %s\n", op);
+                       error = -EIO;
                        goto out;
                }
 
@@ -594,7 +578,35 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
        dev_dbg(&dev->core, "%s completed\n", op);
 
 out:
+       spin_lock_irq(&priv->lock);
+       bio_list_pop(&priv->list);
+       next = bio_list_peek(&priv->list);
+       spin_unlock_irq(&priv->lock);
+
        bio_endio(bio, error);
+       return next;
+}
+
+static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
+{
+       struct ps3_system_bus_device *dev = q->queuedata;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
+       int busy;
+
+       dev_dbg(&dev->core, "%s\n", __func__);
+
+       spin_lock_irq(&priv->lock);
+       busy = !bio_list_empty(&priv->list);
+       bio_list_add(&priv->list, bio);
+       spin_unlock_irq(&priv->lock);
+
+       if (busy)
+               return 0;
+
+       do {
+               bio = ps3vram_do_bio(dev, bio);
+       } while (bio);
+
        return 0;
 }
 
@@ -604,8 +616,8 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
        int error, status;
        struct request_queue *queue;
        struct gendisk *gendisk;
-       u64 ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, ddr_size,
-           reports_size;
+       u64 ddr_size, ddr_lpar, ctrl_lpar, info_lpar, reports_lpar,
+           reports_size, xdr_lpar;
        char *rest;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -614,10 +626,9 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
                goto fail;
        }
 
-       mutex_init(&priv->lock);
-       dev->core.driver_data = priv;
-
-       priv = dev->core.driver_data;
+       spin_lock_init(&priv->lock);
+       bio_list_init(&priv->list);
+       ps3_system_bus_set_drvdata(dev, priv);
 
        /* Allocate XDR buffer (1MiB aligned) */
        priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL,
@@ -636,7 +647,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
        if (ps3_open_hv_device(dev)) {
                dev_err(&dev->core, "ps3_open_hv_device failed\n");
                error = -EAGAIN;
-               goto out_close_gpu;
+               goto out_free_xdr_buf;
        }
 
        /* Request memory */
@@ -660,7 +671,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
                dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n",
                        status);
                error = -ENOMEM;
-               goto out_free_xdr_buf;
+               goto out_close_gpu;
        }
 
        /* Request context */
@@ -676,9 +687,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
        }
 
        /* Map XDR buffer to RSX */
+       xdr_lpar = ps3_mm_phys_to_lpar(__pa(priv->xdr_buf));
        status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
-                                      ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
-                                      XDR_BUF_SIZE, 0);
+                                      xdr_lpar, XDR_BUF_SIZE,
+                                      CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
+                                      CBE_IOPTE_M);
        if (status) {
                dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n",
                        status);
@@ -686,19 +699,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
                goto out_free_context;
        }
 
-       priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE);
-
-       if (!priv->ddr_base) {
-               dev_err(&dev->core, "ioremap DDR failed\n");
-               error = -ENOMEM;
-               goto out_free_context;
-       }
-
        priv->ctrl = ioremap(ctrl_lpar, 64 * 1024);
        if (!priv->ctrl) {
                dev_err(&dev->core, "ioremap CTRL failed\n");
                error = -ENOMEM;
-               goto out_unmap_vram;
+               goto out_unmap_context;
        }
 
        priv->reports = ioremap(reports_lpar, reports_size);
@@ -775,8 +780,9 @@ out_unmap_reports:
        iounmap(priv->reports);
 out_unmap_ctrl:
        iounmap(priv->ctrl);
-out_unmap_vram:
-       iounmap(priv->ddr_base);
+out_unmap_context:
+       lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, xdr_lpar,
+                             XDR_BUF_SIZE, CBE_IOPTE_M);
 out_free_context:
        lv1_gpu_context_free(priv->context_handle);
 out_free_memory:
@@ -787,14 +793,14 @@ out_free_xdr_buf:
        free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
 fail_free_priv:
        kfree(priv);
-       dev->core.driver_data = NULL;
+       ps3_system_bus_set_drvdata(dev, NULL);
 fail:
        return error;
 }
 
 static int ps3vram_remove(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        del_gendisk(priv->gendisk);
        put_disk(priv->gendisk);
@@ -803,13 +809,15 @@ static int ps3vram_remove(struct ps3_system_bus_device *dev)
        ps3vram_cache_cleanup(dev);
        iounmap(priv->reports);
        iounmap(priv->ctrl);
-       iounmap(priv->ddr_base);
+       lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
+                             ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
+                             XDR_BUF_SIZE, CBE_IOPTE_M);
        lv1_gpu_context_free(priv->context_handle);
        lv1_gpu_memory_free(priv->memory_handle);
        ps3_close_hv_device(dev);
        free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
        kfree(priv);
-       dev->core.driver_data = NULL;
+       ps3_system_bus_set_drvdata(dev, NULL);
        return 0;
 }
 
index c1996829d5ecb92231042afd0cdc90ee7b4ad186..e53284767f7c9e59b89c6fe1611487526dee081c 100644 (file)
@@ -753,12 +753,12 @@ static int blkfront_probe(struct xenbus_device *dev,
 
        /* Front end dir is a number, which is used as the id. */
        info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0);
-       dev->dev.driver_data = info;
+       dev_set_drvdata(&dev->dev, info);
 
        err = talk_to_backend(dev, info);
        if (err) {
                kfree(info);
-               dev->dev.driver_data = NULL;
+               dev_set_drvdata(&dev->dev, NULL);
                return err;
        }
 
@@ -843,7 +843,7 @@ static int blkif_recover(struct blkfront_info *info)
  */
 static int blkfront_resume(struct xenbus_device *dev)
 {
-       struct blkfront_info *info = dev->dev.driver_data;
+       struct blkfront_info *info = dev_get_drvdata(&dev->dev);
        int err;
 
        dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
@@ -922,7 +922,7 @@ static void blkfront_connect(struct blkfront_info *info)
  */
 static void blkfront_closing(struct xenbus_device *dev)
 {
-       struct blkfront_info *info = dev->dev.driver_data;
+       struct blkfront_info *info = dev_get_drvdata(&dev->dev);
        unsigned long flags;
 
        dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename);
@@ -957,7 +957,7 @@ static void blkfront_closing(struct xenbus_device *dev)
 static void backend_changed(struct xenbus_device *dev,
                            enum xenbus_state backend_state)
 {
-       struct blkfront_info *info = dev->dev.driver_data;
+       struct blkfront_info *info = dev_get_drvdata(&dev->dev);
        struct block_device *bd;
 
        dev_dbg(&dev->dev, "blkfront:backend_changed.\n");
@@ -997,7 +997,7 @@ static void backend_changed(struct xenbus_device *dev,
 
 static int blkfront_remove(struct xenbus_device *dev)
 {
-       struct blkfront_info *info = dev->dev.driver_data;
+       struct blkfront_info *info = dev_get_drvdata(&dev->dev);
 
        dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename);
 
@@ -1010,7 +1010,7 @@ static int blkfront_remove(struct xenbus_device *dev)
 
 static int blkfront_is_ready(struct xenbus_device *dev)
 {
-       struct blkfront_info *info = dev->dev.driver_data;
+       struct blkfront_info *info = dev_get_drvdata(&dev->dev);
 
        return info->is_ready;
 }
index 54481a8877699d40d22d3afceded64d70365cbe0..86105efb4eb6cb948314a69b3b754ffdc290771a 100644 (file)
@@ -4,7 +4,7 @@
  * This HVC device driver provides terminal access using
  * z/VM IUCV communication paths.
  *
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008, 2009
  *
  * Author(s):  Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  */
@@ -15,6 +15,7 @@
 #include <asm/ebcdic.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/init.h>
 #include <linux/mempool.h>
 #include <linux/moduleparam.h>
@@ -74,6 +75,7 @@ struct hvc_iucv_private {
        wait_queue_head_t       sndbuf_waitq;   /* wait for send completion */
        struct list_head        tty_outqueue;   /* outgoing IUCV messages */
        struct list_head        tty_inqueue;    /* incoming IUCV messages */
+       struct device           *dev;           /* device structure */
 };
 
 struct iucv_tty_buffer {
@@ -542,7 +544,68 @@ static void flush_sndbuf_sync(struct hvc_iucv_private *priv)
 
        if (sync_wait)
                wait_event_timeout(priv->sndbuf_waitq,
-                                  tty_outqueue_empty(priv), HZ);
+                                  tty_outqueue_empty(priv), HZ/10);
+}
+
+/**
+ * hvc_iucv_hangup() - Sever IUCV path and schedule hvc tty hang up
+ * @priv:      Pointer to hvc_iucv_private structure
+ *
+ * This routine severs an existing IUCV communication path and hangs
+ * up the underlying HVC terminal device.
+ * The hang-up occurs only if an IUCV communication path is established;
+ * otherwise there is no need to hang up the terminal device.
+ *
+ * The IUCV HVC hang-up is separated into two steps:
+ * 1. After the IUCV path has been severed, the iucv_state is set to
+ *    IUCV_SEVERED.
+ * 2. Later, when the HVC thread calls hvc_iucv_get_chars(), the
+ *    IUCV_SEVERED state causes the tty hang-up in the HVC layer.
+ *
+ * If the tty has not yet been opened, clean up the hvc_iucv_private
+ * structure to allow re-connects.
+ * If the tty has been opened, let get_chars() return -EPIPE to signal
+ * the HVC layer to hang up the tty and, if so, wake up the HVC thread
+ * to call get_chars()...
+ *
+ * Special notes on hanging up a HVC terminal instantiated as console:
+ * Hang-up:    1. do_tty_hangup() replaces file ops (= hung_up_tty_fops)
+ *             2. do_tty_hangup() calls tty->ops->close() for console_filp
+ *                     => no hangup notifier is called by HVC (default)
+ *             2. hvc_close() returns because of tty_hung_up_p(filp)
+ *                     => no delete notifier is called!
+ * Finally, the back-end is not being notified, thus, the tty session is
+ * kept active (TTY_OPEN) to be ready for re-connects.
+ *
+ * Locking:    spin_lock(&priv->lock) w/o disabling bh
+ */
+static void hvc_iucv_hangup(struct hvc_iucv_private *priv)
+{
+       struct iucv_path *path;
+
+       path = NULL;
+       spin_lock(&priv->lock);
+       if (priv->iucv_state == IUCV_CONNECTED) {
+               path = priv->path;
+               priv->path = NULL;
+               priv->iucv_state = IUCV_SEVERED;
+               if (priv->tty_state == TTY_CLOSED)
+                       hvc_iucv_cleanup(priv);
+               else
+                       /* console is special (see above) */
+                       if (priv->is_console) {
+                               hvc_iucv_cleanup(priv);
+                               priv->tty_state = TTY_OPENED;
+                       } else
+                               hvc_kick();
+       }
+       spin_unlock(&priv->lock);
+
+       /* finally sever path (outside of priv->lock due to lock ordering) */
+       if (path) {
+               iucv_path_sever(path, NULL);
+               iucv_path_free(path);
+       }
 }
 
 /**
@@ -735,11 +798,8 @@ out_path_handled:
  * @ipuser:    User specified data for this path
  *             (AF_IUCV: port/service name and originator port)
  *
- * The function also severs the path (as required by the IUCV protocol) and
- * sets the iucv state to IUCV_SEVERED for the associated struct
- * hvc_iucv_private instance. Later, the IUCV_SEVERED state triggers a tty
- * hangup (hvc_iucv_get_chars() / hvc_iucv_write()).
- * If tty portion of the HVC is closed, clean up the outqueue.
+ * This function calls the hvc_iucv_hangup() function for the
+ * respective IUCV HVC terminal.
  *
  * Locking:    struct hvc_iucv_private->lock
  */
@@ -747,33 +807,7 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
 {
        struct hvc_iucv_private *priv = path->private;
 
-       spin_lock(&priv->lock);
-       priv->iucv_state = IUCV_SEVERED;
-
-       /* If the tty has not yet been opened, clean up the hvc_iucv_private
-        * structure to allow re-connects.
-        * This is also done for our console device because console hangups
-        * are handled specially and no notifier is called by HVC.
-        * The tty session is active (TTY_OPEN) and ready for re-connects...
-        *
-        * If it has been opened, let get_chars() return -EPIPE to signal the
-        * HVC layer to hang up the tty.
-        * If so, we need to wake up the HVC thread to call get_chars()...
-        */
-       priv->path = NULL;
-       if (priv->tty_state == TTY_CLOSED)
-               hvc_iucv_cleanup(priv);
-       else
-               if (priv->is_console) {
-                       hvc_iucv_cleanup(priv);
-                       priv->tty_state = TTY_OPENED;
-               } else
-                       hvc_kick();
-       spin_unlock(&priv->lock);
-
-       /* finally sever path (outside of priv->lock due to lock ordering) */
-       iucv_path_sever(path, ipuser);
-       iucv_path_free(path);
+       hvc_iucv_hangup(priv);
 }
 
 /**
@@ -853,6 +887,37 @@ static void hvc_iucv_msg_complete(struct iucv_path *path,
        destroy_tty_buffer_list(&list_remove);
 }
 
+/**
+ * hvc_iucv_pm_freeze() - Freeze PM callback
+ * @dev:       IUVC HVC terminal device
+ *
+ * Sever an established IUCV communication path and
+ * trigger a hang-up of the underlying HVC terminal.
+ */
+static int hvc_iucv_pm_freeze(struct device *dev)
+{
+       struct hvc_iucv_private *priv = dev_get_drvdata(dev);
+
+       local_bh_disable();
+       hvc_iucv_hangup(priv);
+       local_bh_enable();
+
+       return 0;
+}
+
+/**
+ * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback
+ * @dev:       IUVC HVC terminal device
+ *
+ * Wake up the HVC thread to trigger hang-up and respective
+ * HVC back-end notifier invocations.
+ */
+static int hvc_iucv_pm_restore_thaw(struct device *dev)
+{
+       hvc_kick();
+       return 0;
+}
+
 
 /* HVC operations */
 static struct hv_ops hvc_iucv_ops = {
@@ -863,6 +928,20 @@ static struct hv_ops hvc_iucv_ops = {
        .notifier_hangup = hvc_iucv_notifier_hangup,
 };
 
+/* Suspend / resume device operations */
+static struct dev_pm_ops hvc_iucv_pm_ops = {
+       .freeze   = hvc_iucv_pm_freeze,
+       .thaw     = hvc_iucv_pm_restore_thaw,
+       .restore  = hvc_iucv_pm_restore_thaw,
+};
+
+/* IUCV HVC device driver */
+static struct device_driver hvc_iucv_driver = {
+       .name = KMSG_COMPONENT,
+       .bus  = &iucv_bus,
+       .pm   = &hvc_iucv_pm_ops,
+};
+
 /**
  * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
  * @id:                        hvc_iucv_table index
@@ -897,14 +976,12 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
        /* set console flag */
        priv->is_console = is_console;
 
-       /* finally allocate hvc */
+       /* allocate hvc device */
        priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /*             PAGE_SIZE */
                              HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256);
        if (IS_ERR(priv->hvc)) {
                rc = PTR_ERR(priv->hvc);
-               free_page((unsigned long) priv->sndbuf);
-               kfree(priv);
-               return rc;
+               goto out_error_hvc;
        }
 
        /* notify HVC thread instead of using polling */
@@ -915,8 +992,45 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
        memcpy(priv->srv_name, name, 8);
        ASCEBC(priv->srv_name, 8);
 
+       /* create and setup device */
+       priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL);
+       if (!priv->dev) {
+               rc = -ENOMEM;
+               goto out_error_dev;
+       }
+       dev_set_name(priv->dev, "hvc_iucv%d", id);
+       dev_set_drvdata(priv->dev, priv);
+       priv->dev->bus = &iucv_bus;
+       priv->dev->parent = iucv_root;
+       priv->dev->driver = &hvc_iucv_driver;
+       priv->dev->release = (void (*)(struct device *)) kfree;
+       rc = device_register(priv->dev);
+       if (rc) {
+               kfree(priv->dev);
+               goto out_error_dev;
+       }
+
        hvc_iucv_table[id] = priv;
        return 0;
+
+out_error_dev:
+       hvc_remove(priv->hvc);
+out_error_hvc:
+       free_page((unsigned long) priv->sndbuf);
+       kfree(priv);
+
+       return rc;
+}
+
+/**
+ * hvc_iucv_destroy() - Destroy and free hvc_iucv_private instances
+ */
+static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv)
+{
+       hvc_remove(priv->hvc);
+       device_unregister(priv->dev);
+       free_page((unsigned long) priv->sndbuf);
+       kfree(priv);
 }
 
 /**
@@ -1109,6 +1223,11 @@ static int __init hvc_iucv_init(void)
                goto out_error;
        }
 
+       /* register IUCV HVC device driver */
+       rc = driver_register(&hvc_iucv_driver);
+       if (rc)
+               goto out_error;
+
        /* parse hvc_iucv_allow string and create z/VM user ID filter list */
        if (hvc_iucv_filter_string) {
                rc = hvc_iucv_setup_filter(hvc_iucv_filter_string);
@@ -1183,15 +1302,14 @@ out_error_iucv:
        iucv_unregister(&hvc_iucv_handler, 0);
 out_error_hvc:
        for (i = 0; i < hvc_iucv_devices; i++)
-               if (hvc_iucv_table[i]) {
-                       if (hvc_iucv_table[i]->hvc)
-                               hvc_remove(hvc_iucv_table[i]->hvc);
-                       kfree(hvc_iucv_table[i]);
-               }
+               if (hvc_iucv_table[i])
+                       hvc_iucv_destroy(hvc_iucv_table[i]);
 out_error_memory:
        mempool_destroy(hvc_iucv_mempool);
        kmem_cache_destroy(hvc_iucv_buffer_cache);
 out_error:
+       if (hvc_iucv_filter)
+               kfree(hvc_iucv_filter);
        hvc_iucv_devices = 0; /* ensure that we do not provide any device */
        return rc;
 }
index c76bccf5354dc77f1b97bdb3ea22266d8154faa5..7d64e4230e661ebaac5aeff1383c6967cf963f7b 100644 (file)
@@ -347,7 +347,7 @@ static void __exit hvcs_module_exit(void);
 
 static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod)
 {
-       return viod->dev.driver_data;
+       return dev_get_drvdata(&viod->dev);
 }
 /* The sysfs interface for the driver and devices */
 
@@ -785,7 +785,7 @@ static int __devinit hvcs_probe(
        kref_init(&hvcsd->kref);
 
        hvcsd->vdev = dev;
-       dev->dev.driver_data = hvcsd;
+       dev_set_drvdata(&dev->dev, hvcsd);
 
        hvcsd->index = index;
 
@@ -831,7 +831,7 @@ static int __devinit hvcs_probe(
 
 static int __devexit hvcs_remove(struct vio_dev *dev)
 {
-       struct hvcs_struct *hvcsd = dev->dev.driver_data;
+       struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
        unsigned long flags;
        struct tty_struct *tty;
 
index e5d583c84e4f864ae31cb95534bd5befe6291ed6..fc93e2fc7c71220d02e31acbaf67d40eda7b3133 100644 (file)
@@ -153,6 +153,7 @@ static const struct file_operations rng_chrdev_ops = {
 static struct miscdevice rng_miscdev = {
        .minor          = RNG_MISCDEV_MINOR,
        .name           = RNG_MODULE_NAME,
+       .devnode        = "hwrng",
        .fops           = &rng_chrdev_ops,
 };
 
index 259644646b82e88ea2f120b1f73eb3563c627aa4..d2e698096ace182698152e2366d7c2dc2cf91342 100644 (file)
@@ -2375,14 +2375,14 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
                info->io.addr_data, info->io.regsize, info->io.regspacing,
                info->irq);
 
-       dev->dev.driver_data = (void *) info;
+       dev_set_drvdata(&dev->dev, info);
 
        return try_smi_init(info);
 }
 
 static int __devexit ipmi_of_remove(struct of_device *dev)
 {
-       cleanup_one_si(dev->dev.driver_data);
+       cleanup_one_si(dev_get_drvdata(&dev->dev));
        return 0;
 }
 
index a5e0db9d7662d4a060ff167260753b193a64ee9f..62c99fa59e2b5bf09ee792652648eab4760f37bc 100644 (file)
@@ -168,7 +168,6 @@ static const struct file_operations misc_fops = {
        .open           = misc_open,
 };
 
-
 /**
  *     misc_register   -       register a miscellaneous device
  *     @misc: device structure
@@ -217,8 +216,8 @@ int misc_register(struct miscdevice * misc)
                misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
        dev = MKDEV(MISC_MAJOR, misc->minor);
 
-       misc->this_device = device_create(misc_class, misc->parent, dev, NULL,
-                                         "%s", misc->name);
+       misc->this_device = device_create(misc_class, misc->parent, dev,
+                                         misc, "%s", misc->name);
        if (IS_ERR(misc->this_device)) {
                err = PTR_ERR(misc->this_device);
                goto out;
@@ -264,6 +263,15 @@ int misc_deregister(struct miscdevice *misc)
 EXPORT_SYMBOL(misc_register);
 EXPORT_SYMBOL(misc_deregister);
 
+static char *misc_nodename(struct device *dev)
+{
+       struct miscdevice *c = dev_get_drvdata(dev);
+
+       if (c->devnode)
+               return kstrdup(c->devnode, GFP_KERNEL);
+       return NULL;
+}
+
 static int __init misc_init(void)
 {
        int err;
@@ -279,6 +287,7 @@ static int __init misc_init(void)
        err = -EIO;
        if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
                goto fail_printk;
+       misc_class->nodename = misc_nodename;
        return 0;
 
 fail_printk:
index afbe45676d71c8f064e5102b0e8460dbde0119a3..f424d394a286415e82c8aafdc634073f916f6521 100644 (file)
 
 struct ps3flash_private {
        struct mutex mutex;     /* Bounce buffer mutex */
+       u64 chunk_sectors;
+       int tag;                /* Start sector of buffer, -1 if invalid */
+       bool dirty;
 };
 
 static struct ps3_storage_device *ps3flash_dev;
 
-static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
-                                          u64 lpar, u64 start_sector,
-                                          u64 sectors, int write)
+static int ps3flash_read_write_sectors(struct ps3_storage_device *dev,
+                                      u64 start_sector, int write)
 {
-       u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
+       struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+       u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar,
+                                            start_sector, priv->chunk_sectors,
                                             write);
        if (res) {
                dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
                        __LINE__, write ? "write" : "read", res);
                return -EIO;
        }
-       return sectors;
+       return 0;
 }
 
-static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
-                                    u64 start_sector, u64 sectors,
-                                    unsigned int sector_offset)
+static int ps3flash_writeback(struct ps3_storage_device *dev)
 {
-       u64 max_sectors, lpar;
+       struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+       int res;
 
-       max_sectors = dev->bounce_size / dev->blk_size;
-       if (sectors > max_sectors) {
-               dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n",
-                       __func__, __LINE__, max_sectors);
-               sectors = max_sectors;
-       }
+       if (!priv->dirty || priv->tag < 0)
+               return 0;
 
-       lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
-       return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
-                                          0);
+       res = ps3flash_read_write_sectors(dev, priv->tag, 1);
+       if (res)
+               return res;
+
+       priv->dirty = false;
+       return 0;
 }
 
-static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
-                                   u64 start_sector)
+static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
 {
-       u64 sectors = dev->bounce_size / dev->blk_size;
-       return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
-                                         sectors, 1);
+       struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+       int res;
+
+       if (start_sector == priv->tag)
+               return 0;
+
+       res = ps3flash_writeback(dev);
+       if (res)
+               return res;
+
+       priv->tag = -1;
+
+       res = ps3flash_read_write_sectors(dev, start_sector, 0);
+       if (res)
+               return res;
+
+       priv->tag = start_sector;
+       return 0;
 }
 
 static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
@@ -104,18 +120,19 @@ out:
        return res;
 }
 
-static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
-                            loff_t *pos)
+static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
+                            size_t count, loff_t *pos)
 {
        struct ps3_storage_device *dev = ps3flash_dev;
-       struct ps3flash_private *priv = dev->sbd.core.driver_data;
-       u64 size, start_sector, end_sector, offset;
-       ssize_t sectors_read;
+       struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+       u64 size, sector, offset;
+       int res;
        size_t remaining, n;
+       const void *src;
 
        dev_dbg(&dev->sbd.core,
-               "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
-               __func__, __LINE__, count, *pos, buf);
+               "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
+               __func__, __LINE__, count, *pos, userbuf, kernelbuf);
 
        size = dev->regions[dev->region_idx].size*dev->blk_size;
        if (*pos >= size || !count)
@@ -128,61 +145,63 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
                count = size - *pos;
        }
 
-       start_sector = *pos / dev->blk_size;
-       offset = *pos % dev->blk_size;
-       end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
+       sector = *pos / dev->bounce_size * priv->chunk_sectors;
+       offset = *pos % dev->bounce_size;
 
        remaining = count;
        do {
+               n = min_t(u64, remaining, dev->bounce_size - offset);
+               src = dev->bounce_buf + offset;
+
                mutex_lock(&priv->mutex);
 
-               sectors_read = ps3flash_read_sectors(dev, start_sector,
-                                                    end_sector-start_sector,
-                                                    0);
-               if (sectors_read < 0) {
-                       mutex_unlock(&priv->mutex);
+               res = ps3flash_fetch(dev, sector);
+               if (res)
                        goto fail;
-               }
 
-               n = min_t(u64, remaining, sectors_read*dev->blk_size-offset);
                dev_dbg(&dev->sbd.core,
-                       "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
-                       __func__, __LINE__, n, dev->bounce_buf+offset, buf);
-               if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
-                       mutex_unlock(&priv->mutex);
-                       sectors_read = -EFAULT;
-                       goto fail;
+                       "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
+                       __func__, __LINE__, n, src, userbuf, kernelbuf);
+               if (userbuf) {
+                       if (copy_to_user(userbuf, src, n)) {
+                               res = -EFAULT;
+                               goto fail;
+                       }
+                       userbuf += n;
+               }
+               if (kernelbuf) {
+                       memcpy(kernelbuf, src, n);
+                       kernelbuf += n;
                }
 
                mutex_unlock(&priv->mutex);
 
                *pos += n;
-               buf += n;
                remaining -= n;
-               start_sector += sectors_read;
+               sector += priv->chunk_sectors;
                offset = 0;
        } while (remaining > 0);
 
        return count;
 
 fail:
-       return sectors_read;
+       mutex_unlock(&priv->mutex);
+       return res;
 }
 
-static ssize_t ps3flash_write(struct file *file, const char __user *buf,
-                             size_t count, loff_t *pos)
+static ssize_t ps3flash_write(const char __user *userbuf,
+                             const void *kernelbuf, size_t count, loff_t *pos)
 {
        struct ps3_storage_device *dev = ps3flash_dev;
-       struct ps3flash_private *priv = dev->sbd.core.driver_data;
-       u64 size, chunk_sectors, start_write_sector, end_write_sector,
-           end_read_sector, start_read_sector, head, tail, offset;
-       ssize_t res;
+       struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+       u64 size, sector, offset;
+       int res = 0;
        size_t remaining, n;
-       unsigned int sec_off;
+       void *dst;
 
        dev_dbg(&dev->sbd.core,
-               "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
-               __func__, __LINE__, count, *pos, buf);
+               "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n",
+               __func__, __LINE__, count, *pos, userbuf, kernelbuf);
 
        size = dev->regions[dev->region_idx].size*dev->blk_size;
        if (*pos >= size || !count)
@@ -195,89 +214,46 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
                count = size - *pos;
        }
 
-       chunk_sectors = dev->bounce_size / dev->blk_size;
-
-       start_write_sector = *pos / dev->bounce_size * chunk_sectors;
+       sector = *pos / dev->bounce_size * priv->chunk_sectors;
        offset = *pos % dev->bounce_size;
-       end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
-                          chunk_sectors;
-
-       end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
-       start_read_sector = (*pos + count) / dev->blk_size;
-
-       /*
-        * As we have to write in 256 KiB chunks, while we can read in blk_size
-        * (usually 512 bytes) chunks, we perform the following steps:
-        *   1. Read from start_write_sector to end_read_sector ("head")
-        *   2. Read from start_read_sector to end_write_sector ("tail")
-        *   3. Copy data to buffer
-        *   4. Write from start_write_sector to end_write_sector
-        * All of this is complicated by using only one 256 KiB bounce buffer.
-        */
-
-       head = end_read_sector - start_write_sector;
-       tail = end_write_sector - start_read_sector;
 
        remaining = count;
        do {
+               n = min_t(u64, remaining, dev->bounce_size - offset);
+               dst = dev->bounce_buf + offset;
+
                mutex_lock(&priv->mutex);
 
-               if (end_read_sector >= start_read_sector) {
-                       /* Merge head and tail */
-                       dev_dbg(&dev->sbd.core,
-                               "Merged head and tail: %llu sectors at %llu\n",
-                               chunk_sectors, start_write_sector);
-                       res = ps3flash_read_sectors(dev, start_write_sector,
-                                                   chunk_sectors, 0);
-                       if (res < 0)
+               if (n != dev->bounce_size)
+                       res = ps3flash_fetch(dev, sector);
+               else if (sector != priv->tag)
+                       res = ps3flash_writeback(dev);
+               if (res)
+                       goto fail;
+
+               dev_dbg(&dev->sbd.core,
+                       "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
+                       __func__, __LINE__, n, userbuf, kernelbuf, dst);
+               if (userbuf) {
+                       if (copy_from_user(dst, userbuf, n)) {
+                               res = -EFAULT;
                                goto fail;
-               } else {
-                       if (head) {
-                               /* Read head */
-                               dev_dbg(&dev->sbd.core,
-                                       "head: %llu sectors at %llu\n", head,
-                                       start_write_sector);
-                               res = ps3flash_read_sectors(dev,
-                                                           start_write_sector,
-                                                           head, 0);
-                               if (res < 0)
-                                       goto fail;
-                       }
-                       if (start_read_sector <
-                           start_write_sector+chunk_sectors) {
-                               /* Read tail */
-                               dev_dbg(&dev->sbd.core,
-                                       "tail: %llu sectors at %llu\n", tail,
-                                       start_read_sector);
-                               sec_off = start_read_sector-start_write_sector;
-                               res = ps3flash_read_sectors(dev,
-                                                           start_read_sector,
-                                                           tail, sec_off);
-                               if (res < 0)
-                                       goto fail;
                        }
+                       userbuf += n;
                }
-
-               n = min_t(u64, remaining, dev->bounce_size-offset);
-               dev_dbg(&dev->sbd.core,
-                       "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
-                       __func__, __LINE__, n, buf, dev->bounce_buf+offset);
-               if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
-                       res = -EFAULT;
-                       goto fail;
+               if (kernelbuf) {
+                       memcpy(dst, kernelbuf, n);
+                       kernelbuf += n;
                }
 
-               res = ps3flash_write_chunk(dev, start_write_sector);
-               if (res < 0)
-                       goto fail;
+               priv->tag = sector;
+               priv->dirty = true;
 
                mutex_unlock(&priv->mutex);
 
                *pos += n;
-               buf += n;
                remaining -= n;
-               start_write_sector += chunk_sectors;
-               head = 0;
+               sector += priv->chunk_sectors;
                offset = 0;
        } while (remaining > 0);
 
@@ -288,6 +264,51 @@ fail:
        return res;
 }
 
+static ssize_t ps3flash_user_read(struct file *file, char __user *buf,
+                                 size_t count, loff_t *pos)
+{
+       return ps3flash_read(buf, NULL, count, pos);
+}
+
+static ssize_t ps3flash_user_write(struct file *file, const char __user *buf,
+                                  size_t count, loff_t *pos)
+{
+       return ps3flash_write(buf, NULL, count, pos);
+}
+
+static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos)
+{
+       return ps3flash_read(NULL, buf, count, &pos);
+}
+
+static ssize_t ps3flash_kernel_write(const void *buf, size_t count,
+                                    loff_t pos)
+{
+       ssize_t res;
+       int wb;
+
+       res = ps3flash_write(NULL, buf, count, &pos);
+       if (res < 0)
+               return res;
+
+       /* Make kernel writes synchronous */
+       wb = ps3flash_writeback(ps3flash_dev);
+       if (wb)
+               return wb;
+
+       return res;
+}
+
+static int ps3flash_flush(struct file *file, fl_owner_t id)
+{
+       return ps3flash_writeback(ps3flash_dev);
+}
+
+static int ps3flash_fsync(struct file *file, struct dentry *dentry,
+                         int datasync)
+{
+       return ps3flash_writeback(ps3flash_dev);
+}
 
 static irqreturn_t ps3flash_interrupt(int irq, void *data)
 {
@@ -312,12 +333,18 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-
 static const struct file_operations ps3flash_fops = {
        .owner  = THIS_MODULE,
        .llseek = ps3flash_llseek,
-       .read   = ps3flash_read,
-       .write  = ps3flash_write,
+       .read   = ps3flash_user_read,
+       .write  = ps3flash_user_write,
+       .flush  = ps3flash_flush,
+       .fsync  = ps3flash_fsync,
+};
+
+static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = {
+       .read   = ps3flash_kernel_read,
+       .write  = ps3flash_kernel_write,
 };
 
 static struct miscdevice ps3flash_misc = {
@@ -366,11 +393,13 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
                goto fail;
        }
 
-       dev->sbd.core.driver_data = priv;
+       ps3_system_bus_set_drvdata(&dev->sbd, priv);
        mutex_init(&priv->mutex);
+       priv->tag = -1;
 
        dev->bounce_size = ps3flash_bounce_buffer.size;
        dev->bounce_buf = ps3flash_bounce_buffer.address;
+       priv->chunk_sectors = dev->bounce_size / dev->blk_size;
 
        error = ps3stor_setup(dev, ps3flash_interrupt);
        if (error)
@@ -386,13 +415,15 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
 
        dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
                 __func__, __LINE__, ps3flash_misc.minor);
+
+       ps3_os_area_flash_register(&ps3flash_kernel_ops);
        return 0;
 
 fail_teardown:
        ps3stor_teardown(dev);
 fail_free_priv:
        kfree(priv);
-       dev->sbd.core.driver_data = NULL;
+       ps3_system_bus_set_drvdata(&dev->sbd, NULL);
 fail:
        ps3flash_dev = NULL;
        return error;
@@ -402,10 +433,11 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev)
 {
        struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
 
+       ps3_os_area_flash_register(NULL);
        misc_deregister(&ps3flash_misc);
        ps3stor_teardown(dev);
-       kfree(dev->sbd.core.driver_data);
-       dev->sbd.core.driver_data = NULL;
+       kfree(ps3_system_bus_get_drvdata(&dev->sbd));
+       ps3_system_bus_set_drvdata(&dev->sbd, NULL);
        ps3flash_dev = NULL;
        return 0;
 }
index 5acd29e6e0430ee6bc16f3b4757a4fc76eb5cc06..daebe1ba43d42ad0f3a4053cea80e6c411e8968a 100644 (file)
@@ -95,23 +95,34 @@ static void pty_unthrottle(struct tty_struct *tty)
  * a count.
  *
  * FIXME: Our pty_write method is called with our ldisc lock held but
- * not our partners. We can't just take the other one blindly without
- * risking deadlocks.
+ * not our partners. We can't just wait on the other one blindly without
+ * risking deadlocks. At some point when everything has settled down we need
+ * to look into making pty_write at least able to sleep over an ldisc change.
+ *
+ * The return on no ldisc is a bit counter intuitive but the logic works
+ * like this. During an ldisc change the other end will flush its buffers. We
+ * thus return the full length which is identical to the case where we had
+ * proper locking and happened to queue the bytes just before the flush during
+ * the ldisc change.
  */
 static int pty_write(struct tty_struct *tty, const unsigned char *buf,
                                                                int count)
 {
        struct tty_struct *to = tty->link;
-       int     c;
+       struct tty_ldisc *ld;
+       int c = count;
 
        if (!to || tty->stopped)
                return 0;
-
-       c = to->receive_room;
-       if (c > count)
-               c = count;
-       to->ldisc->ops->receive_buf(to, buf, NULL, c);
-
+       ld = tty_ldisc_ref(to);
+
+       if (ld) {
+               c = to->receive_room;
+               if (c > count)
+                       c = count;
+               ld->ops->receive_buf(to, buf, NULL, c);
+               tty_ldisc_deref(ld);
+       }
        return c;
 }
 
@@ -145,14 +156,23 @@ static int pty_write_room(struct tty_struct *tty)
 static int pty_chars_in_buffer(struct tty_struct *tty)
 {
        struct tty_struct *to = tty->link;
-       int count;
+       struct tty_ldisc *ld;
+       int count = 0;
 
        /* We should get the line discipline lock for "tty->link" */
-       if (!to || !to->ldisc->ops->chars_in_buffer)
+       if (!to)
+               return 0;
+       /* We cannot take a sleeping reference here without deadlocking with
+          an ldisc change - but it doesn't really matter */
+       ld = tty_ldisc_ref(to);
+       if (ld == NULL)
                return 0;
 
        /* The ldisc must report 0 if no characters available to be read */
-       count = to->ldisc->ops->chars_in_buffer(to);
+       if (ld->ops->chars_in_buffer)
+               count = ld->ops->chars_in_buffer(to);
+
+       tty_ldisc_deref(ld);
 
        if (tty->driver->subtype == PTY_TYPE_SLAVE)
                return count;
@@ -182,12 +202,19 @@ static void pty_flush_buffer(struct tty_struct *tty)
 {
        struct tty_struct *to = tty->link;
        unsigned long flags;
+       struct tty_ldisc *ld;
 
        if (!to)
                return;
+       ld = tty_ldisc_ref(to);
+
+       /* The other end is changing discipline */
+       if (!ld)
+               return;
 
-       if (to->ldisc->ops->flush_buffer)
+       if (ld->ops->flush_buffer)
                to->ldisc->ops->flush_buffer(to);
+       tty_ldisc_deref(ld);
 
        if (to->packet) {
                spin_lock_irqsave(&tty->ctrl_lock, flags);
index db32f0e4c7dd48aaef0f1022627a4bebaded6f39..05f9d18b9361227e7cff39946e2d3de41faf8609 100644 (file)
@@ -261,6 +261,11 @@ static const struct file_operations raw_ctl_fops = {
 
 static struct cdev raw_cdev;
 
+static char *raw_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "raw/%s", dev_name(dev));
+}
+
 static int __init raw_init(void)
 {
        dev_t dev = MKDEV(RAW_MAJOR, 0);
@@ -284,6 +289,7 @@ static int __init raw_init(void)
                ret = PTR_ERR(raw_class);
                goto error_region;
        }
+       raw_class->nodename = raw_nodename;
        device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
 
        return 0;
index 939e198d7670adfdad2068b4036a8d9348779444..a3afa0c387cdeb79c9dc9a406eb70935ceaf50d4 100644 (file)
@@ -1263,7 +1263,9 @@ static int tty_reopen(struct tty_struct *tty)
        tty->count++;
        tty->driver = driver; /* N.B. why do this every time?? */
 
+       mutex_lock(&tty->ldisc_mutex);
        WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+       mutex_unlock(&tty->ldisc_mutex);
 
        return 0;
 }
index 8116bb1c8f801c505816b0eec531bed441ff0842..b24f6c6a1ea317c1ccf399eaf2842f281175d70d 100644 (file)
@@ -947,7 +947,6 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
        void __user *p = (void __user *)arg;
        int ret = 0;
        struct ktermios kterm;
-       struct termiox ktermx;
 
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
            tty->driver->subtype == PTY_TYPE_MASTER)
@@ -1049,7 +1048,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                return ret;
 #endif
 #ifdef TCGETX
-       case TCGETX:
+       case TCGETX: {
+               struct termiox ktermx;
                if (real_tty->termiox == NULL)
                        return -EINVAL;
                mutex_lock(&real_tty->termios_mutex);
@@ -1058,6 +1058,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
                        ret = -EFAULT;
                return ret;
+       }
        case TCSETX:
                return set_termiox(real_tty, p, 0);
        case TCSETXW:
index 39c8f86dedd49c9e60ebe1e4e218225416bf0375..a19e935847b0a14e9740184e32d6e099efc26955 100644 (file)
@@ -148,8 +148,10 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc)
                }
        }
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-       if (err)
+       if (err) {
+               kfree(ld);
                return ERR_PTR(err);
+       }
        return ld;
 }
 
@@ -205,6 +207,7 @@ static void tty_ldisc_put(struct tty_ldisc *ld)
        ldo->refcount--;
        module_put(ldo->owner);
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       WARN_ON(ld->refcount);
        kfree(ld);
 }
 
@@ -262,7 +265,7 @@ const struct file_operations tty_ldiscs_proc_fops = {
  *     @ld: line discipline
  *
  *     Install an instance of a line discipline into a tty structure. The
- *     ldisc must have a reference count above zero to ensure it remains/
+ *     ldisc must have a reference count above zero to ensure it remains.
  *     The tty instance refcount starts at zero.
  *
  *     Locking:
@@ -791,6 +794,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
                /* Avoid racing set_ldisc */
                mutex_lock(&tty->ldisc_mutex);
                /* Switch back to N_TTY */
+               tty_ldisc_halt(tty);
+               tty_ldisc_wait_idle(tty);
                tty_ldisc_reinit(tty);
                /* At this point we have a closed ldisc and we want to
                   reopen it. We could defer this to the next open but
index 74edb1d0110f7675f2635d26f5dc4ade609a96ac..0dd0f633b18ddabbcfb55f095b7631eeee177fea 100644 (file)
@@ -31,11 +31,11 @@ static int __init pci_eisa_init(struct pci_dev *pdev,
        }
 
        pci_eisa_root.dev              = &pdev->dev;
-       pci_eisa_root.dev->driver_data = &pci_eisa_root;
        pci_eisa_root.res              = pdev->bus->resource[0];
        pci_eisa_root.bus_base_addr    = pdev->bus->resource[0]->start;
        pci_eisa_root.slots            = EISA_MAX_SLOTS;
        pci_eisa_root.dma_mask         = pdev->dma_mask;
+       dev_set_drvdata(pci_eisa_root.dev, &pci_eisa_root);
 
        if (eisa_root_register (&pci_eisa_root)) {
                printk (KERN_ERR "pci_eisa : Could not register EISA root\n");
index 3074879f231f26d9df3b5219e69a49bfcf8704d5..535e4f9c83f4fed09ca3c00e085b53c60e0cee62 100644 (file)
@@ -57,7 +57,7 @@ static int __init virtual_eisa_root_init (void)
 
        eisa_bus_root.force_probe = force_probe;
        
-       eisa_root_dev.dev.driver_data = &eisa_bus_root;
+       dev_set_drvdata(&eisa_root_dev.dev, &eisa_bus_root);
 
        if (eisa_root_register (&eisa_bus_root)) {
                /* A real bridge may have been registered before
index 2bcf51557c72ae8300ae844106ed0d052f9eb068..a70e66e78c7b8bedfadfc85dc3e434a219aede42 100644 (file)
@@ -1125,7 +1125,7 @@ static int sbp2_probe(struct device *dev)
                return -ENOMEM;
 
        tgt = (struct sbp2_target *)shost->hostdata;
-       unit->device.driver_data = tgt;
+       dev_set_drvdata(&unit->device, tgt);
        tgt->unit = unit;
        kref_init(&tgt->kref);
        INIT_LIST_HEAD(&tgt->lu_list);
@@ -1180,7 +1180,7 @@ static int sbp2_probe(struct device *dev)
 static int sbp2_remove(struct device *dev)
 {
        struct fw_unit *unit = fw_unit(dev);
-       struct sbp2_target *tgt = unit->device.driver_data;
+       struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
 
        sbp2_target_put(tgt);
        return 0;
@@ -1240,7 +1240,7 @@ static void sbp2_reconnect(struct work_struct *work)
 
 static void sbp2_update(struct fw_unit *unit)
 {
-       struct sbp2_target *tgt = unit->device.driver_data;
+       struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
        struct sbp2_logical_unit *lu;
 
        fw_device_enable_phys_dma(fw_device(unit->device.parent));
index c77c6c6d9d2c907eadf71c81f9a0aa3d5db4a37e..6ce0e2667a85f046987b9a7cd4f3a919b5630f5f 100644 (file)
@@ -105,7 +105,7 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count,
                ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
                                          root, tmp, &drm_debugfs_fops);
                if (!ent) {
-                       DRM_ERROR("Cannot create /debugfs/dri/%s/%s\n",
+                       DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/%s\n",
                                  name, files[i].name);
                        drm_free(tmp, sizeof(struct drm_info_node),
                                 _DRM_DRIVER);
@@ -133,9 +133,9 @@ EXPORT_SYMBOL(drm_debugfs_create_files);
  * \param minor device minor number
  * \param root DRI debugfs dir entry.
  *
- * Create the DRI debugfs root entry "/debugfs/dri", the device debugfs root entry
- * "/debugfs/dri/%minor%/", and each entry in debugfs_list as
- * "/debugfs/dri/%minor%/%name%".
+ * Create the DRI debugfs root entry "/sys/kernel/debug/dri", the device debugfs root entry
+ * "/sys/kernel/debug/dri/%minor%/", and each entry in debugfs_list as
+ * "/sys/kernel/debug/dri/%minor%/%name%".
  */
 int drm_debugfs_init(struct drm_minor *minor, int minor_id,
                     struct dentry *root)
@@ -148,7 +148,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
        sprintf(name, "%d", minor_id);
        minor->debugfs_root = debugfs_create_dir(name, root);
        if (!minor->debugfs_root) {
-               DRM_ERROR("Cannot create /debugfs/dri/%s\n", name);
+               DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s\n", name);
                return -1;
        }
 
@@ -165,7 +165,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
                ret = dev->driver->debugfs_init(minor);
                if (ret) {
                        DRM_ERROR("DRM: Driver failed to initialize "
-                                 "/debugfs/dri.\n");
+                                 "/sys/kernel/debug/dri.\n");
                        return ret;
                }
        }
index 019b7c5782367390783dfa8fada2046872a6e0c8..1bf7efd8d334acf7908d5f5dd02bb4fd6db1abe5 100644 (file)
@@ -339,7 +339,7 @@ static int __init drm_core_init(void)
 
        drm_debugfs_root = debugfs_create_dir("dri", NULL);
        if (!drm_debugfs_root) {
-               DRM_ERROR("Cannot create /debugfs/dri\n");
+               DRM_ERROR("Cannot create /sys/kernel/debug/dri\n");
                ret = -1;
                goto err_p3;
        }
index 89050684fe0d2c7b33a2fdf0a31287c5955e5778..387a8de1bc7e51f60af11c903d5852a93bc98e15 100644 (file)
@@ -343,7 +343,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t
 #if defined(CONFIG_DEBUG_FS)
        ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root);
        if (ret) {
-               DRM_ERROR("DRM: Failed to initialize /debugfs/dri.\n");
+               DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
                goto err_g2;
        }
 #endif
index 9987ab8808356d13b01c2540c085181e4f7db791..85ec31b3ff00a09f1d18b0a9b66cd31b68d8ba21 100644 (file)
@@ -70,6 +70,11 @@ static ssize_t version_show(struct class *dev, char *buf)
                       CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
 }
 
+static char *drm_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
+}
+
 static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
 
 /**
@@ -101,6 +106,8 @@ struct class *drm_sysfs_create(struct module *owner, char *name)
        if (err)
                goto err_out_class;
 
+       class->nodename = drm_nodename;
+
        return class;
 
 err_out_class:
index e9b436d2d94434c17fb1030d50528341edd71659..9e9421525fb9125fa962c2266550f67545855b39 100644 (file)
@@ -850,8 +850,14 @@ static const struct file_operations hiddev_fops = {
 #endif
 };
 
+static char *hiddev_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
 static struct usb_class_driver hiddev_class = {
        .name =         "hiddev%d",
+       .nodename =     hiddev_nodename,
        .fops =         &hiddev_fops,
        .minor_base =   HIDDEV_MINOR_BASE,
 };
@@ -955,7 +961,6 @@ static int hiddev_usbd_probe(struct usb_interface *intf,
        return -ENODEV;
 }
 
-
 static /* const */ struct usb_driver hiddev_driver = {
        .name =         "hiddev",
        .probe =        hiddev_usbd_probe,
index d73f5f473e38e09cd92ca4f339b8f3c893de440a..f8090e137fef6ae3b9570433256eeed43f419539 100644 (file)
@@ -306,11 +306,11 @@ config SENSORS_F71805F
          will be called f71805f.
 
 config SENSORS_F71882FG
-       tristate "Fintek F71862FG, F71882FG and F8000"
+       tristate "Fintek F71858FG, F71862FG, F71882FG and F8000"
        depends on EXPERIMENTAL
        help
          If you say yes here you get support for hardware monitoring
-         features of the Fintek F71882FG/F71883FG, F71862FG/71863FG
+         features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG
          and F8000 Super-I/O chips.
 
          This driver can also be built as a module.  If so, the module
@@ -418,7 +418,7 @@ config SENSORS_IBMAEM
          power sensors and capping hardware in various IBM System X
          servers that support Active Energy Manager.  This includes
          the x3350, x3550, x3650, x3655, x3755, x3850 M2, x3950 M2,
-         and certain HS2x/LS2x/QS2x blades.
+         and certain HC10/HS2x/LS2x/QS2x blades.
 
          This driver can also be built as a module.  If so, the module
          will be called ibmaem.
@@ -787,6 +787,16 @@ config SENSORS_THMC50
          This driver can also be built as a module.  If so, the module
          will be called thmc50.
 
+config SENSORS_TMP401
+       tristate "Texas Instruments TMP401 and compatibles"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for Texas Instruments TMP401 and
+         TMP411 temperature sensor chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tmp401.
+
 config SENSORS_VIA686A
        tristate "VIA686A"
        depends on PCI
index 0ae26984ba45b8727deb435f4289ccc71542b3a6..b793dce6bed5b7521ecc929375c51654ea7ca48d 100644 (file)
@@ -82,6 +82,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
 obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
 obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
 obj-$(CONFIG_SENSORS_THMC50)   += thmc50.o
+obj-$(CONFIG_SENSORS_TMP401)   += tmp401.o
 obj-$(CONFIG_SENSORS_VIA686A)  += via686a.o
 obj-$(CONFIG_SENSORS_VT1211)   += vt1211.o
 obj-$(CONFIG_SENSORS_VT8231)   += vt8231.o
index 5f81ddf7150871e67c7fe3ff1647df7e01c6c2c5..4146105f1a5779a5de55006444b9de99e90e8319 100644 (file)
@@ -1,6 +1,6 @@
 /***************************************************************************
  *   Copyright (C) 2006 by Hans Edgington <hans@edgington.nl>              *
- *   Copyright (C) 2007,2008 by Hans de Goede <hdegoede@redhat.com>        *
+ *   Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.com>           *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
@@ -32,6 +32,7 @@
 
 #define DRVNAME "f71882fg"
 
+#define SIO_F71858FG_LD_HWM    0x02    /* Hardware monitor logical device */
 #define SIO_F71882FG_LD_HWM    0x04    /* Hardware monitor logical device */
 #define SIO_UNLOCK_KEY         0x87    /* Key to enable Super-I/O */
 #define SIO_LOCK_KEY           0xAA    /* Key to diasble Super-I/O */
@@ -44,6 +45,7 @@
 #define SIO_REG_ADDR           0x60    /* Logical device address (2 bytes) */
 
 #define SIO_FINTEK_ID          0x1934  /* Manufacturers ID */
+#define SIO_F71858_ID          0x0507  /* Chipset ID */
 #define SIO_F71862_ID          0x0601  /* Chipset ID */
 #define SIO_F71882_ID          0x0541  /* Chipset ID */
 #define SIO_F8000_ID           0x0581  /* Chipset ID */
@@ -70,6 +72,7 @@
 #define F71882FG_REG_TEMP_HIGH(nr)     (0x81 + 2 * (nr))
 #define F71882FG_REG_TEMP_STATUS       0x62
 #define F71882FG_REG_TEMP_BEEP         0x63
+#define F71882FG_REG_TEMP_CONFIG       0x69
 #define F71882FG_REG_TEMP_HYST(nr)     (0x6C + (nr))
 #define F71882FG_REG_TEMP_TYPE         0x6B
 #define F71882FG_REG_TEMP_DIODE_OPEN   0x6F
@@ -92,9 +95,10 @@ static unsigned short force_id;
 module_param(force_id, ushort, 0);
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
-enum chips { f71862fg, f71882fg, f8000 };
+enum chips { f71858fg, f71862fg, f71882fg, f8000 };
 
 static const char *f71882fg_names[] = {
+       "f71858fg",
        "f71862fg",
        "f71882fg",
        "f8000",
@@ -119,6 +123,7 @@ struct f71882fg_data {
        struct device *hwmon_dev;
 
        struct mutex update_lock;
+       int temp_start;                 /* temp numbering start (0 or 1) */
        char valid;                     /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
        unsigned long last_limits;      /* In jiffies */
@@ -136,7 +141,7 @@ struct f71882fg_data {
        /* Note: all models have only 3 temperature channels, but on some
           they are addressed as 0-2 and on others as 1-3, so for coding
           convenience we reserve space for 4 channels */
-       u     temp[4];
+       u16     temp[4];
        u8      temp_ovt[4];
        u8      temp_high[4];
        u8      temp_hyst[2]; /* 2 hysts stored per reg */
@@ -144,6 +149,7 @@ struct f71882fg_data {
        u8      temp_status;
        u8      temp_beep;
        u8      temp_diode_open;
+       u8      temp_config;
        u8      pwm[4];
        u8      pwm_enable;
        u8      pwm_auto_point_hyst[2];
@@ -247,11 +253,55 @@ static struct platform_driver f71882fg_driver = {
                .name   = DRVNAME,
        },
        .probe          = f71882fg_probe,
-       .remove         = __devexit_p(f71882fg_remove),
+       .remove         = f71882fg_remove,
 };
 
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
+/* Temp and in attr for the f71858fg */
+static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
+       SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
+       SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
+       SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
+       SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+       SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
+               store_temp_max, 0, 0),
+       SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+               store_temp_max_hyst, 0, 0),
+       SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
+       SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+               store_temp_crit, 0, 0),
+       SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+               0, 0),
+       SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
+       SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
+       SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
+       SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
+               store_temp_max, 0, 1),
+       SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+               store_temp_max_hyst, 0, 1),
+       SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
+       SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+               store_temp_crit, 0, 1),
+       SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+               0, 1),
+       SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
+       SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
+       SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
+       SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
+       SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
+               store_temp_max, 0, 2),
+       SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+               store_temp_max_hyst, 0, 2),
+       SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
+       SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+               store_temp_crit, 0, 2),
+       SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+               0, 2),
+       SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
+       SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
+};
+
 /* Temp and in attr common to both the f71862fg and f71882fg */
 static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = {
        SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
@@ -344,6 +394,7 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
        SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
                store_temp_max, 0, 0),
        SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
+       SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
        SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
        SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
                store_temp_crit, 0, 1),
@@ -351,12 +402,14 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
                store_temp_max, 0, 1),
        SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
        SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
+       SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
        SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
        SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
                store_temp_crit, 0, 2),
        SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
                store_temp_max, 0, 2),
        SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
+       SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
 };
 
 /* Fan / PWM attr common to all models */
@@ -395,6 +448,9 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[] = {
                      show_pwm_auto_point_channel,
                      store_pwm_auto_point_channel, 0, 1),
 
+       SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
+       SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+                     store_pwm_enable, 0, 2),
        SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
                      show_pwm_interpolate, store_pwm_interpolate, 0, 2),
        SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
@@ -450,9 +506,6 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = {
        SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
                      show_pwm_auto_point_temp_hyst, NULL, 3, 1),
 
-       SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
-       SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
-                     store_pwm_enable, 0, 2),
        SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
                      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
                      1, 2),
@@ -473,22 +526,8 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = {
                      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
 };
 
-/* Fan / PWM attr for the f71882fg */
-static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
-       SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-               store_fan_beep, 0, 0),
-       SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-               store_fan_beep, 0, 1),
-       SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-               store_fan_beep, 0, 2),
-       SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
-       SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
-                     show_fan_full_speed,
-                     store_fan_full_speed, 0, 3),
-       SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-               store_fan_beep, 0, 3),
-       SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
-
+/* Fan / PWM attr common to both the f71882fg and f71858fg */
+static struct sensor_device_attribute_2 f71882fg_f71858fg_fan_attr[] = {
        SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
                      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
                      0, 0),
@@ -565,9 +604,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
        SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
                      show_pwm_auto_point_temp_hyst, NULL, 3, 1),
 
-       SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
-       SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
-                     store_pwm_enable, 0, 2),
        SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
                      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
                      0, 2),
@@ -605,6 +641,24 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
                      show_pwm_auto_point_temp_hyst, NULL, 2, 2),
        SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
                      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
+};
+
+/* Fan / PWM attr found on the f71882fg but not on the f71858fg */
+static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
+       SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 0, 0),
+       SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 0, 1),
+       SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 0, 2),
+
+       SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
+       SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
+                     show_fan_full_speed,
+                     store_fan_full_speed, 0, 3),
+       SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 0, 3),
+       SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
 
        SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
        SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
@@ -659,8 +713,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
 static struct sensor_device_attribute_2 f8000_fan_attr[] = {
        SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
 
-       SENSOR_ATTR_2(pwm3, S_IRUGO, show_pwm, NULL, 0, 2),
-
        SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
                      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
                      0, 2),
@@ -857,13 +909,20 @@ static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
        outb(val & 255, data->addr + DATA_REG_OFFSET);
 }
 
+static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
+{
+       if (data->type == f71858fg)
+               return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
+       else
+               return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
+}
+
 static struct f71882fg_data *f71882fg_update_device(struct device *dev)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
        int nr, reg = 0, reg2;
        int nr_fans = (data->type == f71882fg) ? 4 : 3;
-       int nr_ins = (data->type == f8000) ? 3 : 9;
-       int temp_start = (data->type == f8000) ? 0 : 1;
+       int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
 
        mutex_lock(&data->update_lock);
 
@@ -878,7 +937,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                }
 
                /* Get High & boundary temps*/
-               for (nr = temp_start; nr < 3 + temp_start; nr++) {
+               for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
                        data->temp_ovt[nr] = f71882fg_read8(data,
                                                F71882FG_REG_TEMP_OVT(nr));
                        data->temp_high[nr] = f71882fg_read8(data,
@@ -886,14 +945,17 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                }
 
                if (data->type != f8000) {
-                       data->fan_beep = f71882fg_read8(data,
-                                               F71882FG_REG_FAN_BEEP);
-                       data->temp_beep = f71882fg_read8(data,
-                                               F71882FG_REG_TEMP_BEEP);
                        data->temp_hyst[0] = f71882fg_read8(data,
                                                F71882FG_REG_TEMP_HYST(0));
                        data->temp_hyst[1] = f71882fg_read8(data,
                                                F71882FG_REG_TEMP_HYST(1));
+               }
+
+               if (data->type == f71862fg || data->type == f71882fg) {
+                       data->fan_beep = f71882fg_read8(data,
+                                               F71882FG_REG_FAN_BEEP);
+                       data->temp_beep = f71882fg_read8(data,
+                                               F71882FG_REG_TEMP_BEEP);
                        /* Have to hardcode type, because temp1 is special */
                        reg  = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
                        data->temp_type[2] = (reg & 0x04) ? 2 : 4;
@@ -904,10 +966,10 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                        data->temp_type[1] = 6 /* PECI */;
                else if ((reg2 & 0x03) == 0x02)
                        data->temp_type[1] = 5 /* AMDSI */;
-               else if (data->type != f8000)
+               else if (data->type == f71862fg || data->type == f71882fg)
                        data->temp_type[1] = (reg & 0x02) ? 2 : 4;
                else
-                       data->temp_type[1] = 2; /* F8000 only supports BJT */
+                       data->temp_type[1] = 2; /* Only supports BJT */
 
                data->pwm_enable = f71882fg_read8(data,
                                                  F71882FG_REG_PWM_ENABLE);
@@ -963,9 +1025,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                                                F71882FG_REG_TEMP_STATUS);
                data->temp_diode_open = f71882fg_read8(data,
                                                F71882FG_REG_TEMP_DIODE_OPEN);
-               for (nr = temp_start; nr < 3 + temp_start; nr++)
-                       data->temp[nr] = f71882fg_read8(data,
-                                               F71882FG_REG_TEMP(nr));
+               for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
+                       data->temp[nr] = f71882fg_read_temp(data, nr);
 
                data->fan_status = f71882fg_read8(data,
                                                F71882FG_REG_FAN_STATUS);
@@ -1168,8 +1229,24 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
 {
        struct f71882fg_data *data = f71882fg_update_device(dev);
        int nr = to_sensor_dev_attr_2(devattr)->index;
+       int sign, temp;
+
+       if (data->type == f71858fg) {
+               /* TEMP_TABLE_SEL 1 or 3 ? */
+               if (data->temp_config & 1) {
+                       sign = data->temp[nr] & 0x0001;
+                       temp = (data->temp[nr] >> 5) & 0x7ff;
+               } else {
+                       sign = data->temp[nr] & 0x8000;
+                       temp = (data->temp[nr] >> 5) & 0x3ff;
+               }
+               temp *= 125;
+               if (sign)
+                       temp -= 128000;
+       } else
+               temp = data->temp[nr] * 1000;
 
-       return sprintf(buf, "%d\n", data->temp[nr] * 1000);
+       return sprintf(buf, "%d\n", temp);
 }
 
 static ssize_t show_temp_max(struct device *dev, struct device_attribute
@@ -1440,6 +1517,10 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
        int nr = to_sensor_dev_attr_2(devattr)->index;
        long val = simple_strtol(buf, NULL, 10);
 
+       /* Special case for F8000 pwm channel 3 which only does auto mode */
+       if (data->type == f8000 && nr == 2 && val != 2)
+               return -EINVAL;
+
        mutex_lock(&data->update_lock);
        data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
        /* Special case for F8000 auto PWM mode / Thermostat mode */
@@ -1458,6 +1539,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
        } else {
                switch (val) {
                case 1:
+                       /* The f71858fg does not support manual RPM mode */
+                       if (data->type == f71858fg &&
+                           ((data->pwm_enable >> (2 * nr)) & 1)) {
+                               count = -EINVAL;
+                               goto leave;
+                       }
                        data->pwm_enable |= 2 << (2 * nr);
                        break;          /* Manual */
                case 2:
@@ -1616,9 +1703,9 @@ static ssize_t show_pwm_auto_point_channel(struct device *dev,
        int result;
        struct f71882fg_data *data = f71882fg_update_device(dev);
        int nr = to_sensor_dev_attr_2(devattr)->index;
-       int temp_start = (data->type == f8000) ? 0 : 1;
 
-       result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start);
+       result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
+                      data->temp_start);
 
        return sprintf(buf, "%d\n", result);
 }
@@ -1629,7 +1716,6 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev,
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
        int nr = to_sensor_dev_attr_2(devattr)->index;
-       int temp_start = (data->type == f8000) ? 0 : 1;
        long val = simple_strtol(buf, NULL, 10);
 
        switch (val) {
@@ -1645,7 +1731,7 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev,
        default:
                return -EINVAL;
        }
-       val += temp_start;
+       val += data->temp_start;
        mutex_lock(&data->update_lock);
        data->pwm_auto_point_mapping[nr] =
                f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
@@ -1721,6 +1807,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 
        data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
        data->type = sio_data->type;
+       data->temp_start =
+           (data->type == f71858fg || data->type == f8000) ? 0 : 1;
        mutex_init(&data->update_lock);
        platform_set_drvdata(pdev, data);
 
@@ -1736,19 +1824,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                goto exit_free;
        }
 
-       data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
-       /* If it is a 71862 and the fan / pwm part is enabled sanity check
-          the pwm settings */
-       if (data->type == f71862fg && (start_reg & 0x02)) {
-               if ((data->pwm_enable & 0x15) != 0x15) {
-                       dev_err(&pdev->dev,
-                               "Invalid (reserved) pwm settings: 0x%02x\n",
-                               (unsigned int)data->pwm_enable);
-                       err = -ENODEV;
-                       goto exit_free;
-               }
-       }
-
        /* Register sysfs interface files */
        err = device_create_file(&pdev->dev, &dev_attr_name);
        if (err)
@@ -1756,6 +1831,20 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 
        if (start_reg & 0x01) {
                switch (data->type) {
+               case f71858fg:
+                       data->temp_config =
+                               f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
+                       if (data->temp_config & 0x10)
+                               /* The f71858fg temperature alarms behave as
+                                  the f8000 alarms in this mode */
+                               err = f71882fg_create_sysfs_files(pdev,
+                                       f8000_in_temp_attr,
+                                       ARRAY_SIZE(f8000_in_temp_attr));
+                       else
+                               err = f71882fg_create_sysfs_files(pdev,
+                                       f71858fg_in_temp_attr,
+                                       ARRAY_SIZE(f71858fg_in_temp_attr));
+                       break;
                case f71882fg:
                        err = f71882fg_create_sysfs_files(pdev,
                                        f71882fg_in_temp_attr,
@@ -1779,6 +1868,35 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
        }
 
        if (start_reg & 0x02) {
+               data->pwm_enable =
+                       f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
+
+               /* Sanity check the pwm settings */
+               switch (data->type) {
+               case f71858fg:
+                       err = 0;
+                       for (i = 0; i < nr_fans; i++)
+                               if (((data->pwm_enable >> (i * 2)) & 3) == 3)
+                                       err = 1;
+                       break;
+               case f71862fg:
+                       err = (data->pwm_enable & 0x15) != 0x15;
+                       break;
+               case f71882fg:
+                       err = 0;
+                       break;
+               case f8000:
+                       err = data->pwm_enable & 0x20;
+                       break;
+               }
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "Invalid (reserved) pwm settings: 0x%02x\n",
+                               (unsigned int)data->pwm_enable);
+                       err = -ENODEV;
+                       goto exit_unregister_sysfs;
+               }
+
                err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr,
                                        ARRAY_SIZE(fxxxx_fan_attr));
                if (err)
@@ -1794,6 +1912,13 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                        err = f71882fg_create_sysfs_files(pdev,
                                        f71882fg_fan_attr,
                                        ARRAY_SIZE(f71882fg_fan_attr));
+                       if (err)
+                               goto exit_unregister_sysfs;
+                       /* fall through! */
+               case f71858fg:
+                       err = f71882fg_create_sysfs_files(pdev,
+                                       f71882fg_f71858fg_fan_attr,
+                                       ARRAY_SIZE(f71882fg_f71858fg_fan_attr));
                        break;
                case f8000:
                        err = f71882fg_create_sysfs_files(pdev,
@@ -1878,6 +2003,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
 
        devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
        switch (devid) {
+       case SIO_F71858_ID:
+               sio_data->type = f71858fg;
+               break;
        case SIO_F71862_ID:
                sio_data->type = f71862fg;
                break;
@@ -1892,7 +2020,11 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
                goto exit;
        }
 
-       superio_select(sioaddr, SIO_F71882FG_LD_HWM);
+       if (sio_data->type == f71858fg)
+               superio_select(sioaddr, SIO_F71858FG_LD_HWM);
+       else
+               superio_select(sioaddr, SIO_F71882FG_LD_HWM);
+
        if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
                printk(KERN_WARNING DRVNAME ": Device not activated\n");
                goto exit;
index e15c3e7b07e9a1e2314e29090750fd51abadfde7..29ea6753f3bbe54592168dcaa1db07b1a2dbab3d 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/hwmon.h>
 #include <linux/gfp.h>
 #include <linux/spinlock.h>
+#include <linux/pci.h>
 
 #define HWMON_ID_PREFIX "hwmon"
 #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
@@ -86,8 +87,36 @@ void hwmon_device_unregister(struct device *dev)
                        "hwmon_device_unregister() failed: bad class ID!\n");
 }
 
+static void __init hwmon_pci_quirks(void)
+{
+#if defined CONFIG_X86 && defined CONFIG_PCI
+       struct pci_dev *sb;
+       u16 base;
+       u8 enable;
+
+       /* Open access to 0x295-0x296 on MSI MS-7031 */
+       sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL);
+       if (sb &&
+           (sb->subsystem_vendor == 0x1462 &&  /* MSI */
+            sb->subsystem_device == 0x0031)) { /* MS-7031 */
+
+               pci_read_config_byte(sb, 0x48, &enable);
+               pci_read_config_word(sb, 0x64, &base);
+
+               if (base == 0 && !(enable & BIT(2))) {
+                       dev_info(&sb->dev,
+                                "Opening wide generic port at 0x295\n");
+                       pci_write_config_word(sb, 0x64, 0x295);
+                       pci_write_config_byte(sb, 0x48, enable | BIT(2));
+               }
+       }
+#endif
+}
+
 static int __init hwmon_init(void)
 {
+       hwmon_pci_quirks();
+
        hwmon_class = class_create(THIS_MODULE, "hwmon");
        if (IS_ERR(hwmon_class)) {
                printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n");
index fe74609a7feb5f706ab907c5d69be9881c5bc731..405d3fb5d76f9e90aa9115b56eb4676c4e1b03bb 100644 (file)
@@ -1127,3 +1127,4 @@ MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650-*");
 MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3655-*");
 MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3755-*");
 MODULE_ALIAS("dmi:bvnIBM:*:pnIBM3850M2/x3950M2-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMBladeHC10-*");
index f27af6a9da4148939859ba5a2749a23d17fb73ba..86142a858238b8ddc0ccf65282ef56e34bd0b8ff 100644 (file)
@@ -12,7 +12,7 @@
  * also work with the MAX6651. It does not distinguish max6650 and max6651
  * chips.
  *
- * Tha datasheet was last seen at:
+ * The datasheet was last seen at:
  *
  *        http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
  *
@@ -98,6 +98,16 @@ I2C_CLIENT_INSMOD_1(max6650);
 #define MAX6650_CFG_MODE_OPEN_LOOP     0x30
 #define MAX6650_COUNT_MASK             0x03
 
+/*
+ * Alarm status register bits
+ */
+
+#define MAX6650_ALRM_MAX       0x01
+#define MAX6650_ALRM_MIN       0x02
+#define MAX6650_ALRM_TACH      0x04
+#define MAX6650_ALRM_GPIO1     0x08
+#define MAX6650_ALRM_GPIO2     0x10
+
 /* Minimum and maximum values of the FAN-RPM */
 #define FAN_RPM_MIN 240
 #define FAN_RPM_MAX 30000
@@ -151,6 +161,7 @@ struct max6650_data
        u8 tach[4];
        u8 count;
        u8 dac;
+       u8 alarm;
 };
 
 static ssize_t get_fan(struct device *dev, struct device_attribute *devattr,
@@ -418,6 +429,33 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
        return count;
 }
 
+/*
+ * Get alarm stati:
+ * Possible values:
+ * 0 = no alarm
+ * 1 = alarm
+ */
+
+static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr,
+                        char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct max6650_data *data = max6650_update_device(dev);
+       struct i2c_client *client = to_i2c_client(dev);
+       int alarm = 0;
+
+       if (data->alarm & attr->index) {
+               mutex_lock(&data->update_lock);
+               alarm = 1;
+               data->alarm &= ~attr->index;
+               data->alarm |= i2c_smbus_read_byte_data(client,
+                                                       MAX6650_REG_ALARM);
+               mutex_unlock(&data->update_lock);
+       }
+
+       return sprintf(buf, "%d\n", alarm);
+}
+
 static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0);
 static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1);
 static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2);
@@ -426,7 +464,41 @@ static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target);
 static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div);
 static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable);
 static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);
+static SENSOR_DEVICE_ATTR(fan1_max_alarm, S_IRUGO, get_alarm, NULL,
+                         MAX6650_ALRM_MAX);
+static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, get_alarm, NULL,
+                         MAX6650_ALRM_MIN);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_alarm, NULL,
+                         MAX6650_ALRM_TACH);
+static SENSOR_DEVICE_ATTR(gpio1_alarm, S_IRUGO, get_alarm, NULL,
+                         MAX6650_ALRM_GPIO1);
+static SENSOR_DEVICE_ATTR(gpio2_alarm, S_IRUGO, get_alarm, NULL,
+                         MAX6650_ALRM_GPIO2);
+
+static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
+                                   int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct i2c_client *client = to_i2c_client(dev);
+       u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
+       struct device_attribute *devattr;
 
+       /*
+        * Hide the alarms that have not been enabled by the firmware
+        */
+
+       devattr = container_of(a, struct device_attribute, attr);
+       if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr
+        || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr
+        || devattr == &sensor_dev_attr_fan1_fault.dev_attr
+        || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr
+        || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {
+               if (!(alarm_en & to_sensor_dev_attr(devattr)->index))
+                       return 0;
+       }
+
+       return a->mode;
+}
 
 static struct attribute *max6650_attrs[] = {
        &sensor_dev_attr_fan1_input.dev_attr.attr,
@@ -437,11 +509,17 @@ static struct attribute *max6650_attrs[] = {
        &dev_attr_fan1_div.attr,
        &dev_attr_pwm1_enable.attr,
        &dev_attr_pwm1.attr,
+       &sensor_dev_attr_fan1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan1_fault.dev_attr.attr,
+       &sensor_dev_attr_gpio1_alarm.dev_attr.attr,
+       &sensor_dev_attr_gpio2_alarm.dev_attr.attr,
        NULL
 };
 
 static struct attribute_group max6650_attr_grp = {
        .attrs = max6650_attrs,
+       .is_visible = max6650_attrs_visible,
 };
 
 /*
@@ -659,6 +737,12 @@ static struct max6650_data *max6650_update_device(struct device *dev)
                                                        MAX6650_REG_COUNT);
                data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
 
+               /* Alarms are cleared on read in case the condition that
+                * caused the alarm is removed. Keep the value latched here
+                * for providing the register through different alarm files. */
+               data->alarm |= i2c_smbus_read_byte_data(client,
+                                                       MAX6650_REG_ALARM);
+
                data->last_updated = jiffies;
                data->valid = 1;
        }
index 6cbdc2fea7349cce363df97ed0000b0096ba38e4..56cd6004da36e1ec08f94e05b890f61239323c08 100644 (file)
@@ -627,35 +627,35 @@ static struct platform_driver sht_drivers[] = {
                        .owner = THIS_MODULE,
                },
                .probe = sht15_probe,
-               .remove = sht15_remove,
+               .remove = __devexit_p(sht15_remove),
        }, {
                .driver = {
                        .name = "sht11",
                        .owner = THIS_MODULE,
                },
                .probe = sht15_probe,
-               .remove = sht15_remove,
+               .remove = __devexit_p(sht15_remove),
        }, {
                .driver = {
                        .name = "sht15",
                        .owner = THIS_MODULE,
                },
                .probe = sht15_probe,
-               .remove = sht15_remove,
+               .remove = __devexit_p(sht15_remove),
        }, {
                .driver = {
                        .name = "sht71",
                        .owner = THIS_MODULE,
                },
                .probe = sht15_probe,
-               .remove = sht15_remove,
+               .remove = __devexit_p(sht15_remove),
        }, {
                .driver = {
                        .name = "sht75",
                        .owner = THIS_MODULE,
                },
                .probe = sht15_probe,
-               .remove = sht15_remove,
+               .remove = __devexit_p(sht15_remove),
        },
 };
 
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
new file mode 100644 (file)
index 0000000..7b34f2c
--- /dev/null
@@ -0,0 +1,690 @@
+/* tmp401.c
+ *
+ * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com>
+ * Preliminary tmp411 support by:
+ * Gabriel Konat, Sander Leget, Wouter Willems
+ * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC.
+ *
+ * Note this IC is in some aspect similar to the LM90, but it has quite a
+ * few differences too, for example the local temp has a higher resolution
+ * and thus has 16 bits registers for its value and limit instead of 8 bits.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_2(tmp401, tmp411);
+
+/*
+ * The TMP401 registers, note some registers have different addresses for
+ * reading and writing
+ */
+#define TMP401_STATUS                          0x02
+#define TMP401_CONFIG_READ                     0x03
+#define TMP401_CONFIG_WRITE                    0x09
+#define TMP401_CONVERSION_RATE_READ            0x04
+#define TMP401_CONVERSION_RATE_WRITE           0x0A
+#define TMP401_TEMP_CRIT_HYST                  0x21
+#define TMP401_CONSECUTIVE_ALERT               0x22
+#define TMP401_MANUFACTURER_ID_REG             0xFE
+#define TMP401_DEVICE_ID_REG                   0xFF
+#define TMP411_N_FACTOR_REG                    0x18
+
+static const u8 TMP401_TEMP_MSB[2]                     = { 0x00, 0x01 };
+static const u8 TMP401_TEMP_LSB[2]                     = { 0x15, 0x10 };
+static const u8 TMP401_TEMP_LOW_LIMIT_MSB_READ[2]      = { 0x06, 0x08 };
+static const u8 TMP401_TEMP_LOW_LIMIT_MSB_WRITE[2]     = { 0x0C, 0x0E };
+static const u8 TMP401_TEMP_LOW_LIMIT_LSB[2]           = { 0x17, 0x14 };
+static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_READ[2]     = { 0x05, 0x07 };
+static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[2]    = { 0x0B, 0x0D };
+static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2]          = { 0x16, 0x13 };
+/* These are called the THERM limit / hysteresis / mask in the datasheet */
+static const u8 TMP401_TEMP_CRIT_LIMIT[2]              = { 0x20, 0x19 };
+
+static const u8 TMP411_TEMP_LOWEST_MSB[2]              = { 0x30, 0x34 };
+static const u8 TMP411_TEMP_LOWEST_LSB[2]              = { 0x31, 0x35 };
+static const u8 TMP411_TEMP_HIGHEST_MSB[2]             = { 0x32, 0x36 };
+static const u8 TMP411_TEMP_HIGHEST_LSB[2]             = { 0x33, 0x37 };
+
+/* Flags */
+#define TMP401_CONFIG_RANGE            0x04
+#define TMP401_CONFIG_SHUTDOWN         0x40
+#define TMP401_STATUS_LOCAL_CRIT               0x01
+#define TMP401_STATUS_REMOTE_CRIT              0x02
+#define TMP401_STATUS_REMOTE_OPEN              0x04
+#define TMP401_STATUS_REMOTE_LOW               0x08
+#define TMP401_STATUS_REMOTE_HIGH              0x10
+#define TMP401_STATUS_LOCAL_LOW                0x20
+#define TMP401_STATUS_LOCAL_HIGH               0x40
+
+/* Manufacturer / Device ID's */
+#define TMP401_MANUFACTURER_ID                 0x55
+#define TMP401_DEVICE_ID                       0x11
+#define TMP411_DEVICE_ID                       0x12
+
+/*
+ * Functions declarations
+ */
+
+static int tmp401_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id);
+static int tmp401_detect(struct i2c_client *client, int kind,
+                        struct i2c_board_info *info);
+static int tmp401_remove(struct i2c_client *client);
+static struct tmp401_data *tmp401_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id tmp401_id[] = {
+       { "tmp401", tmp401 },
+       { "tmp411", tmp411 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tmp401_id);
+
+static struct i2c_driver tmp401_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "tmp401",
+       },
+       .probe          = tmp401_probe,
+       .remove         = tmp401_remove,
+       .id_table       = tmp401_id,
+       .detect         = tmp401_detect,
+       .address_data   = &addr_data,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct tmp401_data {
+       struct device *hwmon_dev;
+       struct mutex update_lock;
+       char valid; /* zero until following fields are valid */
+       unsigned long last_updated; /* in jiffies */
+       int kind;
+
+       /* register values */
+       u8 status;
+       u8 config;
+       u16 temp[2];
+       u16 temp_low[2];
+       u16 temp_high[2];
+       u8 temp_crit[2];
+       u8 temp_crit_hyst;
+       u16 temp_lowest[2];
+       u16 temp_highest[2];
+};
+
+/*
+ * Sysfs attr show / store functions
+ */
+
+static int tmp401_register_to_temp(u16 reg, u8 config)
+{
+       int temp = reg;
+
+       if (config & TMP401_CONFIG_RANGE)
+               temp -= 64 * 256;
+
+       return (temp * 625 + 80) / 160;
+}
+
+static u16 tmp401_temp_to_register(long temp, u8 config)
+{
+       if (config & TMP401_CONFIG_RANGE) {
+               temp = SENSORS_LIMIT(temp, -64000, 191000);
+               temp += 64000;
+       } else
+               temp = SENSORS_LIMIT(temp, 0, 127000);
+
+       return (temp * 160 + 312) / 625;
+}
+
+static int tmp401_crit_register_to_temp(u8 reg, u8 config)
+{
+       int temp = reg;
+
+       if (config & TMP401_CONFIG_RANGE)
+               temp -= 64;
+
+       return temp * 1000;
+}
+
+static u8 tmp401_crit_temp_to_register(long temp, u8 config)
+{
+       if (config & TMP401_CONFIG_RANGE) {
+               temp = SENSORS_LIMIT(temp, -64000, 191000);
+               temp += 64000;
+       } else
+               temp = SENSORS_LIMIT(temp, 0, 127000);
+
+       return (temp + 500) / 1000;
+}
+
+static ssize_t show_temp_value(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+               tmp401_register_to_temp(data->temp[index], data->config));
+}
+
+static ssize_t show_temp_min(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+               tmp401_register_to_temp(data->temp_low[index], data->config));
+}
+
+static ssize_t show_temp_max(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+               tmp401_register_to_temp(data->temp_high[index], data->config));
+}
+
+static ssize_t show_temp_crit(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+                       tmp401_crit_register_to_temp(data->temp_crit[index],
+                                                       data->config));
+}
+
+static ssize_t show_temp_crit_hyst(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int temp, index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       mutex_lock(&data->update_lock);
+       temp = tmp401_crit_register_to_temp(data->temp_crit[index],
+                                               data->config);
+       temp -= data->temp_crit_hyst * 1000;
+       mutex_unlock(&data->update_lock);
+
+       return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t show_temp_lowest(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+               tmp401_register_to_temp(data->temp_lowest[index],
+                                       data->config));
+}
+
+static ssize_t show_temp_highest(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+               tmp401_register_to_temp(data->temp_highest[index],
+                                       data->config));
+}
+
+static ssize_t show_status(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int mask = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       if (data->status & mask)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t store_temp_min(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+       long val;
+       u16 reg;
+
+       if (strict_strtol(buf, 10, &val))
+               return -EINVAL;
+
+       reg = tmp401_temp_to_register(val, data->config);
+
+       mutex_lock(&data->update_lock);
+
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_LOW_LIMIT_MSB_WRITE[index], reg >> 8);
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_LOW_LIMIT_LSB[index], reg & 0xFF);
+
+       data->temp_low[index] = reg;
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+       long val;
+       u16 reg;
+
+       if (strict_strtol(buf, 10, &val))
+               return -EINVAL;
+
+       reg = tmp401_temp_to_register(val, data->config);
+
+       mutex_lock(&data->update_lock);
+
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[index], reg >> 8);
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_HIGH_LIMIT_LSB[index], reg & 0xFF);
+
+       data->temp_high[index] = reg;
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t store_temp_crit(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+       long val;
+       u8 reg;
+
+       if (strict_strtol(buf, 10, &val))
+               return -EINVAL;
+
+       reg = tmp401_crit_temp_to_register(val, data->config);
+
+       mutex_lock(&data->update_lock);
+
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_CRIT_LIMIT[index], reg);
+
+       data->temp_crit[index] = reg;
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       int temp, index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+       long val;
+       u8 reg;
+
+       if (strict_strtol(buf, 10, &val))
+               return -EINVAL;
+
+       if (data->config & TMP401_CONFIG_RANGE)
+               val = SENSORS_LIMIT(val, -64000, 191000);
+       else
+               val = SENSORS_LIMIT(val, 0, 127000);
+
+       mutex_lock(&data->update_lock);
+       temp = tmp401_crit_register_to_temp(data->temp_crit[index],
+                                               data->config);
+       val = SENSORS_LIMIT(val, temp - 255000, temp);
+       reg = ((temp - val) + 500) / 1000;
+
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_CRIT_HYST, reg);
+
+       data->temp_crit_hyst = reg;
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+/*
+ * Resets the historical measurements of minimum and maximum temperatures.
+ * This is done by writing any value to any of the minimum/maximum registers
+ * (0x30-0x37).
+ */
+static ssize_t reset_temp_history(struct device *dev,
+       struct device_attribute *devattr, const char *buf, size_t count)
+{
+       long val;
+
+       if (strict_strtol(buf, 10, &val))
+               return -EINVAL;
+
+       if (val != 1) {
+               dev_err(dev, "temp_reset_history value %ld not"
+                       " supported. Use 1 to reset the history!\n", val);
+               return -EINVAL;
+       }
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP411_TEMP_LOWEST_MSB[0], val);
+
+       return count;
+}
+
+static struct sensor_device_attribute tmp401_attr[] = {
+       SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
+       SENSOR_ATTR(temp1_min, 0644, show_temp_min, store_temp_min, 0),
+       SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0),
+       SENSOR_ATTR(temp1_crit, 0644, show_temp_crit, store_temp_crit, 0),
+       SENSOR_ATTR(temp1_crit_hyst, 0644, show_temp_crit_hyst,
+                   store_temp_crit_hyst, 0),
+       SENSOR_ATTR(temp1_min_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_LOCAL_LOW),
+       SENSOR_ATTR(temp1_max_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_LOCAL_HIGH),
+       SENSOR_ATTR(temp1_crit_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_LOCAL_CRIT),
+       SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
+       SENSOR_ATTR(temp2_min, 0644, show_temp_min, store_temp_min, 1),
+       SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1),
+       SENSOR_ATTR(temp2_crit, 0644, show_temp_crit, store_temp_crit, 1),
+       SENSOR_ATTR(temp2_crit_hyst, 0444, show_temp_crit_hyst, NULL, 1),
+       SENSOR_ATTR(temp2_fault, 0444, show_status, NULL,
+                   TMP401_STATUS_REMOTE_OPEN),
+       SENSOR_ATTR(temp2_min_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_REMOTE_LOW),
+       SENSOR_ATTR(temp2_max_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_REMOTE_HIGH),
+       SENSOR_ATTR(temp2_crit_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_REMOTE_CRIT),
+};
+
+/*
+ * Additional features of the TMP411 chip.
+ * The TMP411 stores the minimum and maximum
+ * temperature measured since power-on, chip-reset, or
+ * minimum and maximum register reset for both the local
+ * and remote channels.
+ */
+static struct sensor_device_attribute tmp411_attr[] = {
+       SENSOR_ATTR(temp1_highest, 0444, show_temp_highest, NULL, 0),
+       SENSOR_ATTR(temp1_lowest, 0444, show_temp_lowest, NULL, 0),
+       SENSOR_ATTR(temp2_highest, 0444, show_temp_highest, NULL, 1),
+       SENSOR_ATTR(temp2_lowest, 0444, show_temp_lowest, NULL, 1),
+       SENSOR_ATTR(temp_reset_history, 0200, NULL, reset_temp_history, 0),
+};
+
+/*
+ * Begin non sysfs callback code (aka Real code)
+ */
+
+static void tmp401_init_client(struct i2c_client *client)
+{
+       int config, config_orig;
+
+       /* Set the conversion rate to 2 Hz */
+       i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5);
+
+       /* Start conversions (disable shutdown if necessary) */
+       config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
+       if (config < 0) {
+               dev_warn(&client->dev, "Initialization failed!\n");
+               return;
+       }
+
+       config_orig = config;
+       config &= ~TMP401_CONFIG_SHUTDOWN;
+
+       if (config != config_orig)
+               i2c_smbus_write_byte_data(client, TMP401_CONFIG_WRITE, config);
+}
+
+static int tmp401_detect(struct i2c_client *client, int kind,
+                        struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       /* Detect and identify the chip */
+       if (kind <= 0) {
+               u8 reg;
+
+               reg = i2c_smbus_read_byte_data(client,
+                                              TMP401_MANUFACTURER_ID_REG);
+               if (reg != TMP401_MANUFACTURER_ID)
+                       return -ENODEV;
+
+               reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG);
+
+               switch (reg) {
+               case TMP401_DEVICE_ID:
+                       kind = tmp401;
+                       break;
+               case TMP411_DEVICE_ID:
+                       kind = tmp411;
+                       break;
+               default:
+                       return -ENODEV;
+               }
+
+               reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
+               if (reg & 0x1b)
+                       return -ENODEV;
+
+               reg = i2c_smbus_read_byte_data(client,
+                                              TMP401_CONVERSION_RATE_READ);
+               /* Datasheet says: 0x1-0x6 */
+               if (reg > 15)
+                       return -ENODEV;
+       }
+       strlcpy(info->type, tmp401_id[kind - 1].name, I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int tmp401_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       int i, err = 0;
+       struct tmp401_data *data;
+       const char *names[] = { "TMP401", "TMP411" };
+
+       data = kzalloc(sizeof(struct tmp401_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+       data->kind = id->driver_data;
+
+       /* Initialize the TMP401 chip */
+       tmp401_init_client(client);
+
+       /* Register sysfs hooks */
+       for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) {
+               err = device_create_file(&client->dev,
+                                        &tmp401_attr[i].dev_attr);
+               if (err)
+                       goto exit_remove;
+       }
+
+       /* Register aditional tmp411 sysfs hooks */
+       if (data->kind == tmp411) {
+               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) {
+                       err = device_create_file(&client->dev,
+                                                &tmp411_attr[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+               }
+       }
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               data->hwmon_dev = NULL;
+               goto exit_remove;
+       }
+
+       dev_info(&client->dev, "Detected TI %s chip\n",
+                names[data->kind - 1]);
+
+       return 0;
+
+exit_remove:
+       tmp401_remove(client); /* will also free data for us */
+       return err;
+}
+
+static int tmp401_remove(struct i2c_client *client)
+{
+       struct tmp401_data *data = i2c_get_clientdata(client);
+       int i;
+
+       if (data->hwmon_dev)
+               hwmon_device_unregister(data->hwmon_dev);
+
+       for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++)
+               device_remove_file(&client->dev, &tmp401_attr[i].dev_attr);
+
+       if (data->kind == tmp411) {
+               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
+                       device_remove_file(&client->dev,
+                                          &tmp411_attr[i].dev_attr);
+       }
+
+       kfree(data);
+       return 0;
+}
+
+static struct tmp401_data *tmp401_update_device_reg16(
+       struct i2c_client *client, struct tmp401_data *data)
+{
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               /*
+                * High byte must be read first immediately followed
+                * by the low byte
+                */
+               data->temp[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_MSB[i]) << 8;
+               data->temp[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LSB[i]);
+               data->temp_low[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
+               data->temp_low[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LOW_LIMIT_LSB[i]);
+               data->temp_high[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
+               data->temp_high[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_HIGH_LIMIT_LSB[i]);
+               data->temp_crit[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_CRIT_LIMIT[i]);
+
+               if (data->kind == tmp411) {
+                       data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
+                               TMP411_TEMP_LOWEST_MSB[i]) << 8;
+                       data->temp_lowest[i] |= i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_LOWEST_LSB[i]);
+
+                       data->temp_highest[i] = i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
+                       data->temp_highest[i] |= i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_HIGHEST_LSB[i]);
+               }
+       }
+       return data;
+}
+
+static struct tmp401_data *tmp401_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp401_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
+               data->config = i2c_smbus_read_byte_data(client,
+                                               TMP401_CONFIG_READ);
+               tmp401_update_device_reg16(client, data);
+
+               data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
+                                               TMP401_TEMP_CRIT_HYST);
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+static int __init tmp401_init(void)
+{
+       return i2c_add_driver(&tmp401_driver);
+}
+
+static void __exit tmp401_exit(void)
+{
+       i2c_del_driver(&tmp401_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(tmp401_init);
+module_exit(tmp401_exit);
index e64b42058b219772d0c28ecf0a8780f8ef7ea1ab..0e9746913d2b718bafdd43dc38be46c8a931ab38 100644 (file)
@@ -36,6 +36,7 @@
     w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
                                                0x8860 0xa1
     w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
+    w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
     w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
 */
 
 #include <asm/io.h>
 #include "lm75.h"
 
-enum kinds { w83627ehf, w83627dhg, w83667hg };
+enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg };
 
 /* used to set data->name = w83627ehf_device_names[data->sio_kind] */
 static const char * w83627ehf_device_names[] = {
        "w83627ehf",
        "w83627dhg",
+       "w83627dhg",
        "w83667hg",
 };
 
@@ -86,6 +88,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
 #define SIO_W83627EHF_ID       0x8850
 #define SIO_W83627EHG_ID       0x8860
 #define SIO_W83627DHG_ID       0xa020
+#define SIO_W83627DHG_P_ID     0xb070
 #define SIO_W83667HG_ID        0xa510
 #define SIO_ID_MASK            0xFFF0
 
@@ -1517,6 +1520,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
        static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
        static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
        static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
+       static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
        static const char __initdata sio_name_W83667HG[] = "W83667HG";
 
        u16 val;
@@ -1542,6 +1546,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
                sio_data->kind = w83627dhg;
                sio_name = sio_name_W83627DHG;
                break;
+       case SIO_W83627DHG_P_ID:
+               sio_data->kind = w83627dhg_p;
+               sio_name = sio_name_W83627DHG_P;
+               break;
        case SIO_W83667HG_ID:
                sio_data->kind = w83667hg;
                sio_name = sio_name_W83667HG;
index c8460fa9cfac751b8c236d9ad171f823376951d7..0d04d3ebfc2dd963c73740a5b2140434caefa99d 100644 (file)
@@ -211,7 +211,7 @@ config I2C_VIA
          will be called i2c-via.
 
 config I2C_VIAPRO
-       tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820"
+       tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx"
        depends on PCI
        help
          If you say yes to this option, support will be included for the VIA
@@ -225,8 +225,8 @@ config I2C_VIAPRO
            VT8237R/A/S
            VT8251
            CX700
-           VX800
-           VX820
+           VX800/VX820
+           VX855/VX875
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-viapro.
index 02e6f724b05f262196ad8c57dea9d27155eaa0db..54d810a4d00f86aa3ff687294e235b47a0a4a7cf 100644 (file)
@@ -37,6 +37,7 @@
    VT8251             0x3287             yes
    CX700              0x8324             yes
    VX800/VX820        0x8353             yes
+   VX855/VX875        0x8409             yes
 
    Note: we assume there can only be one device, with one SMBus interface.
 */
@@ -404,6 +405,7 @@ found:
        switch (pdev->device) {
        case PCI_DEVICE_ID_VIA_CX700:
        case PCI_DEVICE_ID_VIA_VX800:
+       case PCI_DEVICE_ID_VIA_VX855:
        case PCI_DEVICE_ID_VIA_8251:
        case PCI_DEVICE_ID_VIA_8237:
        case PCI_DEVICE_ID_VIA_8237A:
@@ -469,6 +471,8 @@ static struct pci_device_id vt596_ids[] = {
          .driver_data = SMBBA3 },
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
          .driver_data = SMBBA3 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855),
+         .driver_data = SMBBA3 },
        { 0, }
 };
 
index 1a474acc0dddf10bf30648c9fbc519de2af0c28c..7663d57833a06e76d099a11366eb21eecaebc953 100644 (file)
@@ -163,7 +163,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = {
 
 static struct i2c_adapter voodoo3_i2c_adapter = {
        .owner          = THIS_MODULE,
-       .class          = I2C_CLASS_TV_ANALOG, 
        .name           = "I2C Voodoo3/Banshee adapter",
        .algo_data      = &voo_i2c_bit_data,
 };
index 8f8c81eb0aee750006a7949ed530d10a4257503c..02d746c9c47451ebb0f14f4a28e20735c1185c4f 100644 (file)
@@ -64,21 +64,6 @@ config SENSORS_PCA9539
          This driver is deprecated and will be dropped soon. Use
          drivers/gpio/pca953x.c instead.
 
-config SENSORS_MAX6875
-       tristate "Maxim MAX6875 Power supply supervisor"
-       depends on EXPERIMENTAL
-       help
-         If you say yes here you get support for the Maxim MAX6875
-         EEPROM-programmable, quad power-supply sequencer/supervisor.
-
-         This provides an interface to program the EEPROM and reset the chip.
-
-         This driver also supports the Maxim MAX6874 hex power-supply
-         sequencer/supervisor if found at a compatible address.
-
-         This driver can also be built as a module.  If so, the module
-         will be called max6875.
-
 config SENSORS_TSL2550
        tristate "Taos TSL2550 ambient light sensor"
        depends on EXPERIMENTAL
index 55a37603718332dcceab0ef5c90f38a6cb054a8e..f4680d16ee341fee40cb6d1c3f615ee8a259eb54 100644 (file)
@@ -11,7 +11,6 @@
 #
 
 obj-$(CONFIG_DS1682)           += ds1682.o
-obj-$(CONFIG_SENSORS_MAX6875)  += max6875.o
 obj-$(CONFIG_SENSORS_PCA9539)  += pca9539.o
 obj-$(CONFIG_SENSORS_PCF8574)  += pcf8574.o
 obj-$(CONFIG_PCF8575)          += pcf8575.o
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
deleted file mode 100644 (file)
index 033d9d8..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
-    max6875.c - driver for MAX6874/MAX6875
-
-    Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
-
-    Based on i2c/chips/eeprom.c
-
-    The MAX6875 has a bank of registers and two banks of EEPROM.
-    Address ranges are defined as follows:
-     * 0x0000 - 0x0046 = configuration registers
-     * 0x8000 - 0x8046 = configuration EEPROM
-     * 0x8100 - 0x82FF = user EEPROM
-
-    This driver makes the user EEPROM available for read.
-
-    The registers & config EEPROM should be accessed via i2c-dev.
-
-    The MAX6875 ignores the lowest address bit, so each chip responds to
-    two addresses - 0x50/0x51 and 0x52/0x53.
-
-    Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read
-    address, so this driver is destructive if loaded for the wrong EEPROM chip.
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; version 2 of the License.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-
-/* Do not scan - the MAX6875 access method will write to some EEPROM chips */
-static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/* Insmod parameters */
-I2C_CLIENT_INSMOD_1(max6875);
-
-/* The MAX6875 can only read/write 16 bytes at a time */
-#define SLICE_SIZE                     16
-#define SLICE_BITS                     4
-
-/* USER EEPROM is at addresses 0x8100 - 0x82FF */
-#define USER_EEPROM_BASE               0x8100
-#define USER_EEPROM_SIZE               0x0200
-#define USER_EEPROM_SLICES             32
-
-/* MAX6875 commands */
-#define MAX6875_CMD_BLK_READ           0x84
-
-/* Each client has this additional data */
-struct max6875_data {
-       struct i2c_client       *fake_client;
-       struct mutex            update_lock;
-
-       u32                     valid;
-       u8                      data[USER_EEPROM_SIZE];
-       unsigned long           last_updated[USER_EEPROM_SLICES];
-};
-
-static void max6875_update_slice(struct i2c_client *client, int slice)
-{
-       struct max6875_data *data = i2c_get_clientdata(client);
-       int i, j, addr;
-       u8 *buf;
-
-       if (slice >= USER_EEPROM_SLICES)
-               return;
-
-       mutex_lock(&data->update_lock);
-
-       buf = &data->data[slice << SLICE_BITS];
-
-       if (!(data->valid & (1 << slice)) ||
-           time_after(jiffies, data->last_updated[slice])) {
-
-               dev_dbg(&client->dev, "Starting update of slice %u\n", slice);
-
-               data->valid &= ~(1 << slice);
-
-               addr = USER_EEPROM_BASE + (slice << SLICE_BITS);
-
-               /* select the eeprom address */
-               if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) {
-                       dev_err(&client->dev, "address set failed\n");
-                       goto exit_up;
-               }
-
-               if (i2c_check_functionality(client->adapter,
-                                           I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
-                       if (i2c_smbus_read_i2c_block_data(client,
-                                                         MAX6875_CMD_BLK_READ,
-                                                         SLICE_SIZE,
-                                                         buf) != SLICE_SIZE) {
-                               goto exit_up;
-                       }
-               } else {
-                       for (i = 0; i < SLICE_SIZE; i++) {
-                               j = i2c_smbus_read_byte(client);
-                               if (j < 0) {
-                                       goto exit_up;
-                               }
-                               buf[i] = j;
-                       }
-               }
-               data->last_updated[slice] = jiffies;
-               data->valid |= (1 << slice);
-       }
-exit_up:
-       mutex_unlock(&data->update_lock);
-}
-
-static ssize_t max6875_read(struct kobject *kobj,
-                           struct bin_attribute *bin_attr,
-                           char *buf, loff_t off, size_t count)
-{
-       struct i2c_client *client = kobj_to_i2c_client(kobj);
-       struct max6875_data *data = i2c_get_clientdata(client);
-       int slice, max_slice;
-
-       if (off > USER_EEPROM_SIZE)
-               return 0;
-
-       if (off + count > USER_EEPROM_SIZE)
-               count = USER_EEPROM_SIZE - off;
-
-       /* refresh slices which contain requested bytes */
-       max_slice = (off + count - 1) >> SLICE_BITS;
-       for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++)
-               max6875_update_slice(client, slice);
-
-       memcpy(buf, &data->data[off], count);
-
-       return count;
-}
-
-static struct bin_attribute user_eeprom_attr = {
-       .attr = {
-               .name = "eeprom",
-               .mode = S_IRUGO,
-       },
-       .size = USER_EEPROM_SIZE,
-       .read = max6875_read,
-};
-
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int max6875_detect(struct i2c_client *client, int kind,
-                         struct i2c_board_info *info)
-{
-       struct i2c_adapter *adapter = client->adapter;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
-                                    | I2C_FUNC_SMBUS_READ_BYTE))
-               return -ENODEV;
-
-       /* Only check even addresses */
-       if (client->addr & 1)
-               return -ENODEV;
-
-       strlcpy(info->type, "max6875", I2C_NAME_SIZE);
-
-       return 0;
-}
-
-static int max6875_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
-{
-       struct max6875_data *data;
-       int err;
-
-       if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL)))
-               return -ENOMEM;
-
-       /* A fake client is created on the odd address */
-       data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1);
-       if (!data->fake_client) {
-               err = -ENOMEM;
-               goto exit_kfree;
-       }
-
-       /* Init real i2c_client */
-       i2c_set_clientdata(client, data);
-       mutex_init(&data->update_lock);
-
-       err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr);
-       if (err)
-               goto exit_remove_fake;
-
-       return 0;
-
-exit_remove_fake:
-       i2c_unregister_device(data->fake_client);
-exit_kfree:
-       kfree(data);
-       return err;
-}
-
-static int max6875_remove(struct i2c_client *client)
-{
-       struct max6875_data *data = i2c_get_clientdata(client);
-
-       i2c_unregister_device(data->fake_client);
-
-       sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
-       kfree(data);
-
-       return 0;
-}
-
-static const struct i2c_device_id max6875_id[] = {
-       { "max6875", 0 },
-       { }
-};
-
-static struct i2c_driver max6875_driver = {
-       .driver = {
-               .name   = "max6875",
-       },
-       .probe          = max6875_probe,
-       .remove         = max6875_remove,
-       .id_table       = max6875_id,
-
-       .detect         = max6875_detect,
-       .address_data   = &addr_data,
-};
-
-static int __init max6875_init(void)
-{
-       return i2c_add_driver(&max6875_driver);
-}
-
-static void __exit max6875_exit(void)
-{
-       i2c_del_driver(&max6875_driver);
-}
-
-
-MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
-MODULE_DESCRIPTION("MAX6875 driver");
-MODULE_LICENSE("GPL");
-
-module_init(max6875_init);
-module_exit(max6875_exit);
index 85e2e919d1cd86e36e0c07815edf2b098e87ae49..5ed622ee65c3bfaa45e3adc0481cfb6bc1a0c55c 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/idr.h>
-#include <linux/platform_device.h>
 #include <linux/mutex.h>
 #include <linux/completion.h>
 #include <linux/hardirq.h>
@@ -451,16 +450,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 
        mutex_lock(&core_lock);
 
-       /* Add the adapter to the driver core.
-        * If the parent pointer is not set up,
-        * we add this adapter to the host bus.
-        */
-       if (adap->dev.parent == NULL) {
-               adap->dev.parent = &platform_bus;
-               pr_debug("I2C adapter driver [%s] forgot to specify "
-                        "physical device\n", adap->name);
-       }
-
        /* Set default timeout to 1 second if not already set */
        if (adap->timeout == 0)
                adap->timeout = HZ;
@@ -1022,7 +1011,8 @@ module_exit(i2c_exit);
  */
 int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
-       int ret;
+       unsigned long orig_jiffies;
+       int ret, try;
 
        /* REVISIT the fault reporting model here is weak:
         *
@@ -1060,7 +1050,15 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        mutex_lock_nested(&adap->bus_lock, adap->level);
                }
 
-               ret = adap->algo->master_xfer(adap,msgs,num);
+               /* Retry automatically on arbitration loss */
+               orig_jiffies = jiffies;
+               for (ret = 0, try = 0; try <= adap->retries; try++) {
+                       ret = adap->algo->master_xfer(adap, msgs, num);
+                       if (ret != -EAGAIN)
+                               break;
+                       if (time_after(jiffies, orig_jiffies + adap->timeout))
+                               break;
+               }
                mutex_unlock(&adap->bus_lock);
 
                return ret;
@@ -1509,7 +1507,7 @@ struct i2c_adapter* i2c_get_adapter(int id)
        struct i2c_adapter *adapter;
 
        mutex_lock(&core_lock);
-       adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
+       adapter = idr_find(&i2c_adapter_idr, id);
        if (adapter && !try_module_get(adapter->owner))
                adapter = NULL;
 
@@ -1995,14 +1993,27 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
                   char read_write, u8 command, int protocol,
                   union i2c_smbus_data *data)
 {
+       unsigned long orig_jiffies;
+       int try;
        s32 res;
 
        flags &= I2C_M_TEN | I2C_CLIENT_PEC;
 
        if (adapter->algo->smbus_xfer) {
                mutex_lock(&adapter->bus_lock);
-               res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
-                                               command, protocol, data);
+
+               /* Retry automatically on arbitration loss */
+               orig_jiffies = jiffies;
+               for (res = 0, try = 0; try <= adapter->retries; try++) {
+                       res = adapter->algo->smbus_xfer(adapter, addr, flags,
+                                                       read_write, command,
+                                                       protocol, data);
+                       if (res != -EAGAIN)
+                               break;
+                       if (time_after(jiffies,
+                                      orig_jiffies + adapter->timeout))
+                               break;
+               }
                mutex_unlock(&adapter->bus_lock);
        } else
                res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
index ba1488bd84307bb90850977573d2e80c9778af69..c14ca144cffe035d7722b6bb9fb8720652ad11bc 100644 (file)
@@ -3,7 +3,8 @@
 
 int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 {
-       ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
+       ide_drive_t *drive = dev_get_drvdata(dev);
+       ide_drive_t *pair = ide_get_pair_dev(drive);
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq;
        struct request_pm_state rqpm;
@@ -34,7 +35,8 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 
 int generic_ide_resume(struct device *dev)
 {
-       ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
+       ide_drive_t *drive = dev_get_drvdata(dev);
+       ide_drive_t *pair = ide_get_pair_dev(drive);
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq;
        struct request_pm_state rqpm;
index f371b0de314f75374a6728d206dabb3a24ef676e..79e0af3fd158a229d2e1f2945e9d270297f4cc4f 100644 (file)
@@ -535,7 +535,7 @@ static int ide_register_port(ide_hwif_t *hwif)
 
        /* register with global device tree */
        dev_set_name(&hwif->gendev, hwif->name);
-       hwif->gendev.driver_data = hwif;
+       dev_set_drvdata(&hwif->gendev, hwif);
        if (hwif->gendev.parent == NULL)
                hwif->gendev.parent = hwif->dev;
        hwif->gendev.release = hwif_release_dev;
@@ -987,9 +987,9 @@ static void hwif_register_devices(ide_hwif_t *hwif)
                int ret;
 
                dev_set_name(dev, "%u.%u", hwif->index, i);
+               dev_set_drvdata(dev, drive);
                dev->parent = &hwif->gendev;
                dev->bus = &ide_bus_type;
-               dev->driver_data = drive;
                dev->release = drive_release_dev;
 
                ret = device_register(dev);
index ee9b55ecc62b10741d1c7693d00ca8209f66ca78..b579fbe88370c6c254c47ad4e681946b3a902a9d 100644 (file)
@@ -112,7 +112,7 @@ out:
 
 static int __devexit plat_ide_remove(struct platform_device *pdev)
 {
-       struct ide_host *host = pdev->dev.driver_data;
+       struct ide_host *host = dev_get_drvdata(&pdev->dev);
 
        ide_host_remove(host);
 
index 4ca103577c0a3d809964cd519ec4d793f7c2213e..f5c586c2bba658cdfbef07d7e268431c0f64bfdb 100644 (file)
@@ -361,7 +361,7 @@ static int eth1394_new_node(struct eth1394_host_info *hi,
        node_info->pdg.sz = 0;
        node_info->fifo = CSR1212_INVALID_ADDR_SPACE;
 
-       ud->device.driver_data = node_info;
+       dev_set_drvdata(&ud->device, node_info);
        new_node->ud = ud;
 
        priv = netdev_priv(hi->dev);
@@ -406,7 +406,7 @@ static int eth1394_remove(struct device *dev)
        list_del(&old_node->list);
        kfree(old_node);
 
-       node_info = (struct eth1394_node_info*)ud->device.driver_data;
+       node_info = dev_get_drvdata(&ud->device);
 
        spin_lock_irqsave(&node_info->pdg.lock, flags);
        /* The partial datagram list should be empty, but we'll just
@@ -416,7 +416,7 @@ static int eth1394_remove(struct device *dev)
        spin_unlock_irqrestore(&node_info->pdg.lock, flags);
 
        kfree(node_info);
-       ud->device.driver_data = NULL;
+       dev_set_drvdata(&ud->device, NULL);
        return 0;
 }
 
@@ -688,7 +688,7 @@ static void ether1394_host_reset(struct hpsb_host *host)
        ether1394_reset_priv(dev, 0);
 
        list_for_each_entry(node, &priv->ip_node_list, list) {
-               node_info = node->ud->device.driver_data;
+               node_info = dev_get_drvdata(&node->ud->device);
 
                spin_lock_irqsave(&node_info->pdg.lock, flags);
 
@@ -872,8 +872,7 @@ static __be16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
                if (!node)
                        return cpu_to_be16(0);
 
-               node_info =
-                   (struct eth1394_node_info *)node->ud->device.driver_data;
+               node_info = dev_get_drvdata(&node->ud->device);
 
                /* Update our speed/payload/fifo_offset table */
                node_info->maxpayload = maxpayload;
@@ -1080,7 +1079,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
                priv->ud_list[NODEID_TO_NODE(srcid)] = ud;
        }
 
-       node_info = (struct eth1394_node_info *)ud->device.driver_data;
+       node_info = dev_get_drvdata(&ud->device);
 
        /* First, did we receive a fragmented or unfragmented datagram? */
        hdr->words.word1 = ntohs(hdr->words.word1);
@@ -1617,8 +1616,7 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev)
                if (!node)
                        goto fail;
 
-               node_info =
-                   (struct eth1394_node_info *)node->ud->device.driver_data;
+               node_info = dev_get_drvdata(&node->ud->device);
                if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE)
                        goto fail;
 
index a51ab233342de0f3e9fbf4be79d499ca3ab044cd..83b734aec923f795a5e4d79dcc162e68f5efaf5d 100644 (file)
@@ -718,7 +718,7 @@ static int sbp2_remove(struct device *dev)
        struct scsi_device *sdev;
 
        ud = container_of(dev, struct unit_directory, device);
-       lu = ud->device.driver_data;
+       lu = dev_get_drvdata(&ud->device);
        if (!lu)
                return 0;
 
@@ -746,7 +746,7 @@ static int sbp2_remove(struct device *dev)
 
 static int sbp2_update(struct unit_directory *ud)
 {
-       struct sbp2_lu *lu = ud->device.driver_data;
+       struct sbp2_lu *lu = dev_get_drvdata(&ud->device);
 
        if (sbp2_reconnect_device(lu) != 0) {
                /*
@@ -815,7 +815,7 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
        atomic_set(&lu->state, SBP2LU_STATE_RUNNING);
        INIT_WORK(&lu->protocol_work, NULL);
 
-       ud->device.driver_data = lu;
+       dev_set_drvdata(&ud->device, lu);
 
        hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host);
        if (!hi) {
@@ -1051,7 +1051,7 @@ static void sbp2_remove_device(struct sbp2_lu *lu)
                hpsb_unregister_addrspace(&sbp2_highlevel, hi->host,
                                          lu->status_fifo_addr);
 
-       lu->ud->device.driver_data = NULL;
+       dev_set_drvdata(&lu->ud->device, NULL);
 
        module_put(hi->host->driver->owner);
 no_hi:
index 5c04cfb54cb9244dd93dd4f916a8be2538d7aa20..158a214da2f7fd36b3c215203edc368a1fdb1cb1 100644 (file)
@@ -760,9 +760,9 @@ int ib_device_register_sysfs(struct ib_device *device)
        int i;
 
        class_dev->class      = &ib_class;
-       class_dev->driver_data = device;
        class_dev->parent     = device->dma_device;
        dev_set_name(class_dev, device->name);
+       dev_set_drvdata(class_dev, device);
 
        INIT_LIST_HEAD(&device->port_list);
 
index 85905ab9391fec6703765117fcc29d0500d038d2..ce4e6eff4792519193ebe9aa29d6e8aff5aaf5c5 100644 (file)
@@ -636,7 +636,7 @@ static ssize_t  ehca_show_##name(struct device *dev,                       \
        struct hipz_query_hca *rblock;                                     \
        int data;                                                          \
                                                                           \
-       shca = dev->driver_data;                                           \
+       shca = dev_get_drvdata(dev);                                       \
                                                                           \
        rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);                      \
        if (!rblock) {                                                     \
@@ -680,7 +680,7 @@ static ssize_t ehca_show_adapter_handle(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       struct ehca_shca *shca = dev->driver_data;
+       struct ehca_shca *shca = dev_get_drvdata(dev);
 
        return sprintf(buf, "%llx\n", shca->ipz_hca_handle.handle);
 
@@ -749,7 +749,7 @@ static int __devinit ehca_probe(struct of_device *dev,
 
        shca->ofdev = dev;
        shca->ipz_hca_handle.handle = *handle;
-       dev->dev.driver_data = shca;
+       dev_set_drvdata(&dev->dev, shca);
 
        ret = ehca_sense_attributes(shca);
        if (ret < 0) {
@@ -878,7 +878,7 @@ probe1:
 
 static int __devexit ehca_remove(struct of_device *dev)
 {
-       struct ehca_shca *shca = dev->dev.driver_data;
+       struct ehca_shca *shca = dev_get_drvdata(&dev->dev);
        unsigned long flags;
        int ret;
 
index 5d445f48789b899528c1f30d1f1115f324d553a5..7c237e6ac7112f318c4a9fe941704948d612970e 100644 (file)
@@ -1265,8 +1265,14 @@ static struct device_type input_dev_type = {
        .uevent         = input_dev_uevent,
 };
 
+static char *input_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev));
+}
+
 struct class input_class = {
        .name           = "input",
+       .nodename       = input_nodename,
 };
 EXPORT_SYMBOL_GPL(input_class);
 
index 69af8385ab141bc78329e103653d55103eb53558..2957d48e0045fa05d68bb38aafe6ec8c9d3462d8 100644 (file)
@@ -569,7 +569,7 @@ static int wm97xx_probe(struct device *dev)
        mutex_init(&wm->codec_mutex);
 
        wm->dev = dev;
-       dev->driver_data = wm;
+       dev_set_drvdata(dev, wm);
        wm->ac97 = to_ac97_t(dev);
 
        /* check that we have a supported codec */
index 928d2ed8865f6b296b2fe9550d599b016d06f606..b115726dc088b169003a725ba29de8a4171e58a9 100644 (file)
@@ -114,7 +114,7 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev,
                xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
                return -ENOMEM;
        }
-       dev->dev.driver_data = info;
+       dev_set_drvdata(&dev->dev, info);
        info->xbdev = dev;
        info->irq = -1;
        snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
@@ -186,7 +186,7 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev,
 
 static int xenkbd_resume(struct xenbus_device *dev)
 {
-       struct xenkbd_info *info = dev->dev.driver_data;
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
 
        xenkbd_disconnect_backend(info);
        memset(info->page, 0, PAGE_SIZE);
@@ -195,7 +195,7 @@ static int xenkbd_resume(struct xenbus_device *dev)
 
 static int xenkbd_remove(struct xenbus_device *dev)
 {
-       struct xenkbd_info *info = dev->dev.driver_data;
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
 
        xenkbd_disconnect_backend(info);
        if (info->kbd)
@@ -266,7 +266,7 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *info)
 static void xenkbd_backend_changed(struct xenbus_device *dev,
                                   enum xenbus_state backend_state)
 {
-       struct xenkbd_info *info = dev->dev.driver_data;
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
        int ret, val;
 
        switch (backend_state) {
index 0ddf9044948aeeb0a8d8affefb1c1afec36c252d..fde377c60cca753eafe9c358f7e562c6d538ad7b 100644 (file)
@@ -72,7 +72,7 @@ MODULE_PARM_DESC(verbose,"Verbose log operations "
                 "(default 0)");
 
 struct thermostat {
-       struct i2c_client       clt;
+       struct i2c_client       *clt;
        u8                      temps[3];
        u8                      cached_temp[3];
        u8                      initial_limits[3];
@@ -87,9 +87,6 @@ static struct of_device * of_dev;
 static struct thermostat* thermostat;
 static struct task_struct *thread_therm = NULL;
 
-static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
-                                int busno);
-
 static void write_both_fan_speed(struct thermostat *th, int speed);
 static void write_fan_speed(struct thermostat *th, int speed, int fan);
 
@@ -101,7 +98,7 @@ write_reg(struct thermostat* th, int reg, u8 data)
        
        tmp[0] = reg;
        tmp[1] = data;
-       rc = i2c_master_send(&th->clt, (const char *)tmp, 2);
+       rc = i2c_master_send(th->clt, (const char *)tmp, 2);
        if (rc < 0)
                return rc;
        if (rc != 2)
@@ -116,12 +113,12 @@ read_reg(struct thermostat* th, int reg)
        int rc;
 
        reg_addr = (u8)reg;
-       rc = i2c_master_send(&th->clt, &reg_addr, 1);
+       rc = i2c_master_send(th->clt, &reg_addr, 1);
        if (rc < 0)
                return rc;
        if (rc != 1)
                return -ENODEV;
-       rc = i2c_master_recv(&th->clt, (char *)&data, 1);
+       rc = i2c_master_recv(th->clt, (char *)&data, 1);
        if (rc < 0)
                return rc;
        return data;
@@ -131,26 +128,36 @@ static int
 attach_thermostat(struct i2c_adapter *adapter)
 {
        unsigned long bus_no;
+       struct i2c_board_info info;
+       struct i2c_client *client;
 
        if (strncmp(adapter->name, "uni-n", 5))
                return -ENODEV;
        bus_no = simple_strtoul(adapter->name + 6, NULL, 10);
        if (bus_no != therm_bus)
                return -ENODEV;
-       return attach_one_thermostat(adapter, therm_address, bus_no);
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE);
+       info.addr = therm_address;
+       client = i2c_new_device(adapter, &info);
+       if (!client)
+               return -ENODEV;
+
+       /*
+        * Let i2c-core delete that device on driver removal.
+        * This is safe because i2c-core holds the core_lock mutex for us.
+        */
+       list_add_tail(&client->detected, &client->driver->clients);
+       return 0;
 }
 
 static int
-detach_thermostat(struct i2c_adapter *adapter)
+remove_thermostat(struct i2c_client *client)
 {
-       struct thermostat* th;
+       struct thermostat *th = i2c_get_clientdata(client);
        int i;
        
-       if (thermostat == NULL)
-               return 0;
-
-       th = thermostat;
-
        if (thread_therm != NULL) {
                kthread_stop(thread_therm);
        }
@@ -166,8 +173,6 @@ detach_thermostat(struct i2c_adapter *adapter)
 
        write_both_fan_speed(th, -1);
 
-       i2c_detach_client(&th->clt);
-
        thermostat = NULL;
 
        kfree(th);
@@ -175,14 +180,6 @@ detach_thermostat(struct i2c_adapter *adapter)
        return 0;
 }
 
-static struct i2c_driver thermostat_driver = {  
-       .driver = {
-               .name   = "therm_adt746x",
-       },
-       .attach_adapter = attach_thermostat,
-       .detach_adapter = detach_thermostat,
-};
-
 static int read_fan_speed(struct thermostat *th, u8 addr)
 {
        u8 tmp[2];
@@ -371,8 +368,8 @@ static void set_limit(struct thermostat *th, int i)
                th->limits[i] = default_limits_local[i] + limit_adjust;
 }
 
-static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
-                                int busno)
+static int probe_thermostat(struct i2c_client *client,
+                           const struct i2c_device_id *id)
 {
        struct thermostat* th;
        int rc;
@@ -385,16 +382,12 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
        if (!th)
                return -ENOMEM;
 
-       th->clt.addr = addr;
-       th->clt.adapter = adapter;
-       th->clt.driver = &thermostat_driver;
-       strcpy(th->clt.name, "thermostat");
+       i2c_set_clientdata(client, th);
+       th->clt = client;
 
        rc = read_reg(th, 0);
        if (rc < 0) {
-               printk(KERN_ERR "adt746x: Thermostat failed to read config "
-                               "from bus %d !\n",
-                               busno);
+               dev_err(&client->dev, "Thermostat failed to read config!\n");
                kfree(th);
                return -ENODEV;
        }
@@ -423,14 +416,6 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
 
        thermostat = th;
 
-       if (i2c_attach_client(&th->clt)) {
-               printk(KERN_INFO "adt746x: Thermostat failed to attach "
-                                "client !\n");
-               thermostat = NULL;
-               kfree(th);
-               return -ENODEV;
-       }
-
        /* be sure to really write fan speed the first time */
        th->last_speed[0] = -2;
        th->last_speed[1] = -2;
@@ -456,6 +441,21 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
        return 0;
 }
 
+static const struct i2c_device_id therm_adt746x_id[] = {
+       { "therm_adt746x", 0 },
+       { }
+};
+
+static struct i2c_driver thermostat_driver = {
+       .driver = {
+               .name   = "therm_adt746x",
+       },
+       .attach_adapter = attach_thermostat,
+       .probe = probe_thermostat,
+       .remove = remove_thermostat,
+       .id_table = therm_adt746x_id,
+};
+
 /* 
  * Now, unfortunately, sysfs doesn't give us a nice void * we could
  * pass around to the attribute functions, so we don't really have
index 817607e2af6a9c89193cc390ab16d2455dc7a0f7..a028598af2d32ae030596bff2e83145420271d65 100644 (file)
@@ -286,22 +286,6 @@ struct fcu_fan_table       fcu_fans[] = {
        },
 };
 
-/*
- * i2c_driver structure to attach to the host i2c controller
- */
-
-static int therm_pm72_attach(struct i2c_adapter *adapter);
-static int therm_pm72_detach(struct i2c_adapter *adapter);
-
-static struct i2c_driver therm_pm72_driver =
-{
-       .driver = {
-               .name   = "therm_pm72",
-       },
-       .attach_adapter = therm_pm72_attach,
-       .detach_adapter = therm_pm72_detach,
-};
-
 /*
  * Utility function to create an i2c_client structure and
  * attach it to one of u3 adapters
@@ -310,6 +294,7 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name)
 {
        struct i2c_client *clt;
        struct i2c_adapter *adap;
+       struct i2c_board_info info;
 
        if (id & 0x200)
                adap = k2;
@@ -320,31 +305,21 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name)
        if (adap == NULL)
                return NULL;
 
-       clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (clt == NULL)
-               return NULL;
-
-       clt->addr = (id >> 1) & 0x7f;
-       clt->adapter = adap;
-       clt->driver = &therm_pm72_driver;
-       strncpy(clt->name, name, I2C_NAME_SIZE-1);
-
-       if (i2c_attach_client(clt)) {
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = (id >> 1) & 0x7f;
+       strlcpy(info.type, "therm_pm72", I2C_NAME_SIZE);
+       clt = i2c_new_device(adap, &info);
+       if (!clt) {
                printk(KERN_ERR "therm_pm72: Failed to attach to i2c ID 0x%x\n", id);
-               kfree(clt);
                return NULL;
        }
-       return clt;
-}
 
-/*
- * Utility function to get rid of the i2c_client structure
- * (will also detach from the adapter hopepfully)
- */
-static void detach_i2c_chip(struct i2c_client *clt)
-{
-       i2c_detach_client(clt);
-       kfree(clt);
+       /*
+        * Let i2c-core delete that device on driver removal.
+        * This is safe because i2c-core holds the core_lock mutex for us.
+        */
+       list_add_tail(&clt->detected, &clt->driver->clients);
+       return clt;
 }
 
 /*
@@ -1203,8 +1178,6 @@ static int init_cpu_state(struct cpu_pid_state *state, int index)
 
        return 0;
  fail:
-       if (state->monitor)
-               detach_i2c_chip(state->monitor);
        state->monitor = NULL;
        
        return -ENODEV;
@@ -1232,7 +1205,6 @@ static void dispose_cpu_state(struct cpu_pid_state *state)
                device_remove_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm);
        }
 
-       detach_i2c_chip(state->monitor);
        state->monitor = NULL;
 }
 
@@ -1407,7 +1379,6 @@ static void dispose_backside_state(struct backside_pid_state *state)
        device_remove_file(&of_dev->dev, &dev_attr_backside_temperature);
        device_remove_file(&of_dev->dev, &dev_attr_backside_fan_pwm);
 
-       detach_i2c_chip(state->monitor);
        state->monitor = NULL;
 }
  
@@ -1532,7 +1503,6 @@ static void dispose_drives_state(struct drives_pid_state *state)
        device_remove_file(&of_dev->dev, &dev_attr_drives_temperature);
        device_remove_file(&of_dev->dev, &dev_attr_drives_fan_rpm);
 
-       detach_i2c_chip(state->monitor);
        state->monitor = NULL;
 }
 
@@ -1654,7 +1624,6 @@ static void dispose_dimms_state(struct dimm_pid_state *state)
 
        device_remove_file(&of_dev->dev, &dev_attr_dimms_temperature);
 
-       detach_i2c_chip(state->monitor);
        state->monitor = NULL;
 }
 
@@ -1779,7 +1748,6 @@ static void dispose_slots_state(struct slots_pid_state *state)
        device_remove_file(&of_dev->dev, &dev_attr_slots_temperature);
        device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
 
-       detach_i2c_chip(state->monitor);
        state->monitor = NULL;
 }
 
@@ -2008,8 +1976,6 @@ static int attach_fcu(void)
  */
 static void detach_fcu(void)
 {
-       if (fcu)
-               detach_i2c_chip(fcu);
        fcu = NULL;
 }
 
@@ -2060,12 +2026,21 @@ static int therm_pm72_attach(struct i2c_adapter *adapter)
        return 0;
 }
 
+static int therm_pm72_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       /* Always succeed, the real work was done in therm_pm72_attach() */
+       return 0;
+}
+
 /*
- * Called on every adapter when the driver or the i2c controller
+ * Called when any of the devices which participates into thermal management
  * is going away.
  */
-static int therm_pm72_detach(struct i2c_adapter *adapter)
+static int therm_pm72_remove(struct i2c_client *client)
 {
+       struct i2c_adapter *adapter = client->adapter;
+
        mutex_lock(&driver_lock);
 
        if (state != state_detached)
@@ -2096,6 +2071,30 @@ static int therm_pm72_detach(struct i2c_adapter *adapter)
        return 0;
 }
 
+/*
+ * i2c_driver structure to attach to the host i2c controller
+ */
+
+static const struct i2c_device_id therm_pm72_id[] = {
+       /*
+        * Fake device name, thermal management is done by several
+        * chips but we don't need to differentiate between them at
+        * this point.
+        */
+       { "therm_pm72", 0 },
+       { }
+};
+
+static struct i2c_driver therm_pm72_driver = {
+       .driver = {
+               .name   = "therm_pm72",
+       },
+       .attach_adapter = therm_pm72_attach,
+       .probe          = therm_pm72_probe,
+       .remove         = therm_pm72_remove,
+       .id_table       = therm_pm72_id,
+};
+
 static int fan_check_loc_match(const char *loc, int fan)
 {
        char    tmp[64];
index 3da0a02efd7668f6088dd28eb05f88b7c1d0b768..40023313a760ac9005b74e04c17b3f7def7daa6e 100644 (file)
 
 #define LOG_TEMP               0                       /* continously log temperature */
 
-static int                     do_probe( struct i2c_adapter *adapter, int addr, int kind);
-
-/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
-static const unsigned short    normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
-                                                0x4c, 0x4d, 0x4e, 0x4f,
-                                                0x2c, 0x2d, 0x2e, 0x2f,
-                                                I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
 static struct {
        volatile int            running;
        struct task_struct      *poll_task;
@@ -315,53 +305,54 @@ static int control_loop(void *dummy)
 static int
 do_attach( struct i2c_adapter *adapter )
 {
-       int ret = 0;
+       /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
+       static const unsigned short scan_ds1775[] = {
+               0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+               I2C_CLIENT_END
+       };
+       static const unsigned short scan_adm1030[] = {
+               0x2c, 0x2d, 0x2e, 0x2f,
+               I2C_CLIENT_END
+       };
 
        if( strncmp(adapter->name, "uni-n", 5) )
                return 0;
 
        if( !x.running ) {
-               ret = i2c_probe( adapter, &addr_data, &do_probe );
+               struct i2c_board_info info;
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "therm_ds1775", I2C_NAME_SIZE);
+               i2c_new_probed_device(adapter, &info, scan_ds1775);
+
+               strlcpy(info.type, "therm_adm1030", I2C_NAME_SIZE);
+               i2c_new_probed_device(adapter, &info, scan_adm1030);
+
                if( x.thermostat && x.fan ) {
                        x.running = 1;
                        x.poll_task = kthread_run(control_loop, NULL, "g4fand");
                }
        }
-       return ret;
+       return 0;
 }
 
 static int
-do_detach( struct i2c_client *client )
+do_remove(struct i2c_client *client)
 {
-       int err;
-
-       if( (err=i2c_detach_client(client)) )
-               printk(KERN_ERR "failed to detach thermostat client\n");
-       else {
-               if( x.running ) {
-                       x.running = 0;
-                       kthread_stop(x.poll_task);
-                       x.poll_task = NULL;
-               }
-               if( client == x.thermostat )
-                       x.thermostat = NULL;
-               else if( client == x.fan )
-                       x.fan = NULL;
-               else {
-                       printk(KERN_ERR "g4fan: bad client\n");
-               }
-               kfree( client );
+       if (x.running) {
+               x.running = 0;
+               kthread_stop(x.poll_task);
+               x.poll_task = NULL;
        }
-       return err;
-}
+       if (client == x.thermostat)
+               x.thermostat = NULL;
+       else if (client == x.fan)
+               x.fan = NULL;
+       else
+               printk(KERN_ERR "g4fan: bad client\n");
 
-static struct i2c_driver g4fan_driver = {  
-       .driver = {
-               .name   = "therm_windtunnel",
-       },
-       .attach_adapter = do_attach,
-       .detach_client  = do_detach,
-};
+       return 0;
+}
 
 static int
 attach_fan( struct i2c_client *cl )
@@ -374,13 +365,8 @@ attach_fan( struct i2c_client *cl )
                goto out;
        printk("ADM1030 fan controller [@%02x]\n", cl->addr );
 
-       strlcpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) );
-
-       if( !i2c_attach_client(cl) )
-               x.fan = cl;
+       x.fan = cl;
  out:
-       if( cl != x.fan )
-               kfree( cl );
        return 0;
 }
 
@@ -412,39 +398,47 @@ attach_thermostat( struct i2c_client *cl )
        x.temp = temp;
        x.overheat_temp = os_temp;
        x.overheat_hyst = hyst_temp;
-       
-       strlcpy( cl->name, "DS1775 thermostat", sizeof(cl->name) );
-
-       if( !i2c_attach_client(cl) )
-               x.thermostat = cl;
+       x.thermostat = cl;
 out:
-       if( cl != x.thermostat )
-               kfree( cl );
        return 0;
 }
 
+enum chip { ds1775, adm1030 };
+
+static const struct i2c_device_id therm_windtunnel_id[] = {
+       { "therm_ds1775", ds1775 },
+       { "therm_adm1030", adm1030 },
+       { }
+};
+
 static int
-do_probe( struct i2c_adapter *adapter, int addr, int kind )
+do_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 {
-       struct i2c_client *cl;
+       struct i2c_adapter *adapter = cl->adapter;
 
        if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA
                                     | I2C_FUNC_SMBUS_WRITE_BYTE) )
                return 0;
 
-       if( !(cl=kzalloc(sizeof(*cl), GFP_KERNEL)) )
-               return -ENOMEM;
-
-       cl->addr = addr;
-       cl->adapter = adapter;
-       cl->driver = &g4fan_driver;
-       cl->flags = 0;
-
-       if( addr < 0x48 )
+       switch (id->driver_data) {
+       case adm1030:
                return attach_fan( cl );
-       return attach_thermostat( cl );
+       case ds1775:
+               return attach_thermostat(cl);
+       }
+       return 0;
 }
 
+static struct i2c_driver g4fan_driver = {
+       .driver = {
+               .name   = "therm_windtunnel",
+       },
+       .attach_adapter = do_attach,
+       .probe          = do_probe,
+       .remove         = do_remove,
+       .id_table       = therm_windtunnel_id,
+};
+
 
 /************************************************************************/
 /*     initialization / cleanup                                        */
index b92b959fe16e3a9d57ad4a610bd137f138a3d25d..529886c7a8263ae4d4d01df89b7b513695d983c3 100644 (file)
 struct wf_lm75_sensor {
        int                     ds1775 : 1;
        int                     inited : 1;
-       struct  i2c_client      i2c;
+       struct  i2c_client      *i2c;
        struct  wf_sensor       sens;
 };
 #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
-#define i2c_to_lm75(c) container_of(c, struct wf_lm75_sensor, i2c)
-
-static int wf_lm75_attach(struct i2c_adapter *adapter);
-static int wf_lm75_detach(struct i2c_client *client);
-
-static struct i2c_driver wf_lm75_driver = {
-       .driver = {
-               .name   = "wf_lm75",
-       },
-       .attach_adapter = wf_lm75_attach,
-       .detach_client  = wf_lm75_detach,
-};
 
 static int wf_lm75_get(struct wf_sensor *sr, s32 *value)
 {
        struct wf_lm75_sensor *lm = wf_to_lm75(sr);
        s32 data;
 
-       if (lm->i2c.adapter == NULL)
+       if (lm->i2c == NULL)
                return -ENODEV;
 
        /* Init chip if necessary */
        if (!lm->inited) {
-               u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(&lm->i2c, 1);
+               u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(lm->i2c, 1);
 
                DBG("wf_lm75: Initializing %s, cfg was: %02x\n",
                    sr->name, cfg);
@@ -73,7 +61,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value)
                 * the firmware for now
                 */
                cfg_new = cfg & ~0x01;
-               i2c_smbus_write_byte_data(&lm->i2c, 1, cfg_new);
+               i2c_smbus_write_byte_data(lm->i2c, 1, cfg_new);
                lm->inited = 1;
 
                /* If we just powered it up, let's wait 200 ms */
@@ -81,7 +69,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value)
        }
 
        /* Read temperature register */
-       data = (s32)le16_to_cpu(i2c_smbus_read_word_data(&lm->i2c, 0));
+       data = (s32)le16_to_cpu(i2c_smbus_read_word_data(lm->i2c, 0));
        data <<= 8;
        *value = data;
 
@@ -92,12 +80,6 @@ static void wf_lm75_release(struct wf_sensor *sr)
 {
        struct wf_lm75_sensor *lm = wf_to_lm75(sr);
 
-       /* check if client is registered and detach from i2c */
-       if (lm->i2c.adapter) {
-               i2c_detach_client(&lm->i2c);
-               lm->i2c.adapter = NULL;
-       }
-
        kfree(lm);
 }
 
@@ -107,59 +89,77 @@ static struct wf_sensor_ops wf_lm75_ops = {
        .owner          = THIS_MODULE,
 };
 
-static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
-                                            u8 addr, int ds1775,
-                                            const char *loc)
+static int wf_lm75_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct wf_lm75_sensor *lm;
        int rc;
 
-       DBG("wf_lm75: creating  %s device at address 0x%02x\n",
-           ds1775 ? "ds1775" : "lm75", addr);
-
        lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
        if (lm == NULL)
-               return NULL;
+               return -ENODEV;
+
+       lm->inited = 0;
+       lm->ds1775 = id->driver_data;
+       lm->i2c = client;
+       lm->sens.name = client->dev.platform_data;
+       lm->sens.ops = &wf_lm75_ops;
+       i2c_set_clientdata(client, lm);
+
+       rc = wf_register_sensor(&lm->sens);
+       if (rc) {
+               i2c_set_clientdata(client, NULL);
+               kfree(lm);
+       }
+
+       return rc;
+}
+
+static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
+                                            u8 addr, int ds1775,
+                                            const char *loc)
+{
+       struct i2c_board_info info;
+       struct i2c_client *client;
+       char *name;
+
+       DBG("wf_lm75: creating  %s device at address 0x%02x\n",
+           ds1775 ? "ds1775" : "lm75", addr);
 
        /* Usual rant about sensor names not beeing very consistent in
         * the device-tree, oh well ...
         * Add more entries below as you deal with more setups
         */
        if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY"))
-               lm->sens.name = "hd-temp";
+               name = "hd-temp";
        else if (!strcmp(loc, "Incoming Air Temp"))
-               lm->sens.name = "incoming-air-temp";
+               name = "incoming-air-temp";
        else if (!strcmp(loc, "ODD Temp"))
-               lm->sens.name = "optical-drive-temp";
+               name = "optical-drive-temp";
        else if (!strcmp(loc, "HD Temp"))
-               lm->sens.name = "hard-drive-temp";
+               name = "hard-drive-temp";
        else
                goto fail;
 
-       lm->inited = 0;
-       lm->sens.ops = &wf_lm75_ops;
-       lm->ds1775 = ds1775;
-       lm->i2c.addr = (addr >> 1) & 0x7f;
-       lm->i2c.adapter = adapter;
-       lm->i2c.driver = &wf_lm75_driver;
-       strncpy(lm->i2c.name, lm->sens.name, I2C_NAME_SIZE-1);
-
-       rc = i2c_attach_client(&lm->i2c);
-       if (rc) {
-               printk(KERN_ERR "windfarm: failed to attach %s %s to i2c,"
-                      " err %d\n", ds1775 ? "ds1775" : "lm75",
-                      lm->i2c.name, rc);
-               goto fail;
-       }
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = (addr >> 1) & 0x7f;
+       info.platform_data = name;
+       strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE);
 
-       if (wf_register_sensor(&lm->sens)) {
-               i2c_detach_client(&lm->i2c);
+       client = i2c_new_device(adapter, &info);
+       if (client == NULL) {
+               printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n",
+                      ds1775 ? "ds1775" : "lm75", name);
                goto fail;
        }
 
-       return lm;
+       /*
+        * Let i2c-core delete that device on driver removal.
+        * This is safe because i2c-core holds the core_lock mutex for us.
+        */
+       list_add_tail(&client->detected, &client->driver->clients);
+       return client;
  fail:
-       kfree(lm);
        return NULL;
 }
 
@@ -202,21 +202,38 @@ static int wf_lm75_attach(struct i2c_adapter *adapter)
        return 0;
 }
 
-static int wf_lm75_detach(struct i2c_client *client)
+static int wf_lm75_remove(struct i2c_client *client)
 {
-       struct wf_lm75_sensor *lm = i2c_to_lm75(client);
+       struct wf_lm75_sensor *lm = i2c_get_clientdata(client);
 
        DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name);
 
        /* Mark client detached */
-       lm->i2c.adapter = NULL;
+       lm->i2c = NULL;
 
        /* release sensor */
        wf_unregister_sensor(&lm->sens);
 
+       i2c_set_clientdata(client, NULL);
        return 0;
 }
 
+static const struct i2c_device_id wf_lm75_id[] = {
+       { "wf_lm75", 0 },
+       { "wf_ds1775", 1 },
+       { }
+};
+
+static struct i2c_driver wf_lm75_driver = {
+       .driver = {
+               .name   = "wf_lm75",
+       },
+       .attach_adapter = wf_lm75_attach,
+       .probe          = wf_lm75_probe,
+       .remove         = wf_lm75_remove,
+       .id_table       = wf_lm75_id,
+};
+
 static int __init wf_lm75_sensor_init(void)
 {
        /* Don't register on old machines that use therm_pm72 for now */
index e207a90d6b2762fa887bdfdc30344958f00a8373..e2a55ecda2b28aa2c80114dd7d6c7ec0cd519827 100644 (file)
 #define MAX6690_EXTERNAL_TEMP  1
 
 struct wf_6690_sensor {
-       struct i2c_client       i2c;
+       struct i2c_client       *i2c;
        struct wf_sensor        sens;
 };
 
 #define wf_to_6690(x)  container_of((x), struct wf_6690_sensor, sens)
-#define i2c_to_6690(x) container_of((x), struct wf_6690_sensor, i2c)
-
-static int wf_max6690_attach(struct i2c_adapter *adapter);
-static int wf_max6690_detach(struct i2c_client *client);
-
-static struct i2c_driver wf_max6690_driver = {
-       .driver = {
-               .name           = "wf_max6690",
-       },
-       .attach_adapter = wf_max6690_attach,
-       .detach_client  = wf_max6690_detach,
-};
 
 static int wf_max6690_get(struct wf_sensor *sr, s32 *value)
 {
        struct wf_6690_sensor *max = wf_to_6690(sr);
        s32 data;
 
-       if (max->i2c.adapter == NULL)
+       if (max->i2c == NULL)
                return -ENODEV;
 
        /* chip gets initialized by firmware */
-       data = i2c_smbus_read_byte_data(&max->i2c, MAX6690_EXTERNAL_TEMP);
+       data = i2c_smbus_read_byte_data(max->i2c, MAX6690_EXTERNAL_TEMP);
        if (data < 0)
                return data;
        *value = data << 16;
@@ -64,10 +52,6 @@ static void wf_max6690_release(struct wf_sensor *sr)
 {
        struct wf_6690_sensor *max = wf_to_6690(sr);
 
-       if (max->i2c.adapter) {
-               i2c_detach_client(&max->i2c);
-               max->i2c.adapter = NULL;
-       }
        kfree(max);
 }
 
@@ -77,19 +61,40 @@ static struct wf_sensor_ops wf_max6690_ops = {
        .owner          = THIS_MODULE,
 };
 
-static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr,
-                             const char *loc)
+static int wf_max6690_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
 {
        struct wf_6690_sensor *max;
-       char *name;
+       int rc;
 
        max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
        if (max == NULL) {
-               printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: "
-                      "no memory\n", loc);
-               return;
+               printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: "
+                      "no memory\n");
+               return -ENOMEM;
+       }
+
+       max->i2c = client;
+       max->sens.name = client->dev.platform_data;
+       max->sens.ops = &wf_max6690_ops;
+       i2c_set_clientdata(client, max);
+
+       rc = wf_register_sensor(&max->sens);
+       if (rc) {
+               i2c_set_clientdata(client, NULL);
+               kfree(max);
        }
 
+       return rc;
+}
+
+static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter,
+                                           u8 addr, const char *loc)
+{
+       struct i2c_board_info info;
+       struct i2c_client *client;
+       char *name;
+
        if (!strcmp(loc, "BACKSIDE"))
                name = "backside-temp";
        else if (!strcmp(loc, "NB Ambient"))
@@ -99,27 +104,26 @@ static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr,
        else
                goto fail;
 
-       max->sens.ops = &wf_max6690_ops;
-       max->sens.name = name;
-       max->i2c.addr = addr >> 1;
-       max->i2c.adapter = adapter;
-       max->i2c.driver = &wf_max6690_driver;
-       strncpy(max->i2c.name, name, I2C_NAME_SIZE-1);
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = addr >> 1;
+       info.platform_data = name;
+       strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE);
 
-       if (i2c_attach_client(&max->i2c)) {
+       client = i2c_new_device(adapter, &info);
+       if (client == NULL) {
                printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n");
                goto fail;
        }
 
-       if (wf_register_sensor(&max->sens)) {
-               i2c_detach_client(&max->i2c);
-               goto fail;
-       }
-
-       return;
+       /*
+        * Let i2c-core delete that device on driver removal.
+        * This is safe because i2c-core holds the core_lock mutex for us.
+        */
+       list_add_tail(&client->detected, &client->driver->clients);
+       return client;
 
  fail:
-       kfree(max);
+       return NULL;
 }
 
 static int wf_max6690_attach(struct i2c_adapter *adapter)
@@ -154,16 +158,31 @@ static int wf_max6690_attach(struct i2c_adapter *adapter)
        return 0;
 }
 
-static int wf_max6690_detach(struct i2c_client *client)
+static int wf_max6690_remove(struct i2c_client *client)
 {
-       struct wf_6690_sensor *max = i2c_to_6690(client);
+       struct wf_6690_sensor *max = i2c_get_clientdata(client);
 
-       max->i2c.adapter = NULL;
+       max->i2c = NULL;
        wf_unregister_sensor(&max->sens);
 
        return 0;
 }
 
+static const struct i2c_device_id wf_max6690_id[] = {
+       { "wf_max6690", 0 },
+       { }
+};
+
+static struct i2c_driver wf_max6690_driver = {
+       .driver = {
+               .name           = "wf_max6690",
+       },
+       .attach_adapter = wf_max6690_attach,
+       .probe          = wf_max6690_probe,
+       .remove         = wf_max6690_remove,
+       .id_table       = wf_max6690_id,
+};
+
 static int __init wf_max6690_sensor_init(void)
 {
        /* Don't register on old machines that use therm_pm72 for now */
index 7847e981ac33eaeaead929137aa68e0ef13937f2..5da729e58f99294ec43cd23ec7bee680da7e70b7 100644 (file)
@@ -39,7 +39,7 @@ struct wf_sat {
        struct mutex            mutex;
        unsigned long           last_read; /* jiffies when cache last updated */
        u8                      cache[16];
-       struct i2c_client       i2c;
+       struct i2c_client       *i2c;
        struct device_node      *node;
 };
 
@@ -54,18 +54,6 @@ struct wf_sat_sensor {
 };
 
 #define wf_to_sat(c)   container_of(c, struct wf_sat_sensor, sens)
-#define i2c_to_sat(c)  container_of(c, struct wf_sat, i2c)
-
-static int wf_sat_attach(struct i2c_adapter *adapter);
-static int wf_sat_detach(struct i2c_client *client);
-
-static struct i2c_driver wf_sat_driver = {
-       .driver = {
-               .name           = "wf_smu_sat",
-       },
-       .attach_adapter = wf_sat_attach,
-       .detach_client  = wf_sat_detach,
-};
 
 struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
                                                  unsigned int *size)
@@ -81,13 +69,13 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
        if (sat_id > 1 || (sat = sats[sat_id]) == NULL)
                return NULL;
 
-       err = i2c_smbus_write_word_data(&sat->i2c, 8, id << 8);
+       err = i2c_smbus_write_word_data(sat->i2c, 8, id << 8);
        if (err) {
                printk(KERN_ERR "smu_sat_get_sdb_part wr error %d\n", err);
                return NULL;
        }
 
-       err = i2c_smbus_read_word_data(&sat->i2c, 9);
+       err = i2c_smbus_read_word_data(sat->i2c, 9);
        if (err < 0) {
                printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n");
                return NULL;
@@ -105,7 +93,7 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
                return NULL;
 
        for (i = 0; i < len; i += 4) {
-               err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0xa, 4, data);
+               err = i2c_smbus_read_i2c_block_data(sat->i2c, 0xa, 4, data);
                if (err < 0) {
                        printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n",
                               err);
@@ -138,7 +126,7 @@ static int wf_sat_read_cache(struct wf_sat *sat)
 {
        int err;
 
-       err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0x3f, 16, sat->cache);
+       err = i2c_smbus_read_i2c_block_data(sat->i2c, 0x3f, 16, sat->cache);
        if (err < 0)
                return err;
        sat->last_read = jiffies;
@@ -161,7 +149,7 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value)
        int i, err;
        s32 val;
 
-       if (sat->i2c.adapter == NULL)
+       if (sat->i2c == NULL)
                return -ENODEV;
 
        mutex_lock(&sat->mutex);
@@ -193,10 +181,6 @@ static void wf_sat_release(struct wf_sensor *sr)
        struct wf_sat *sat = sens->sat;
 
        if (atomic_dec_and_test(&sat->refcnt)) {
-               if (sat->i2c.adapter) {
-                       i2c_detach_client(&sat->i2c);
-                       sat->i2c.adapter = NULL;
-               }
                if (sat->nr >= 0)
                        sats[sat->nr] = NULL;
                kfree(sat);
@@ -212,38 +196,58 @@ static struct wf_sensor_ops wf_sat_ops = {
 
 static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
 {
+       struct i2c_board_info info;
+       struct i2c_client *client;
+       const u32 *reg;
+       u8 addr;
+
+       reg = of_get_property(dev, "reg", NULL);
+       if (reg == NULL)
+               return;
+       addr = *reg;
+       DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr);
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = (addr >> 1) & 0x7f;
+       info.platform_data = dev;
+       strlcpy(info.type, "wf_sat", I2C_NAME_SIZE);
+
+       client = i2c_new_device(adapter, &info);
+       if (client == NULL) {
+               printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n");
+               return;
+       }
+
+       /*
+        * Let i2c-core delete that device on driver removal.
+        * This is safe because i2c-core holds the core_lock mutex for us.
+        */
+       list_add_tail(&client->detected, &client->driver->clients);
+}
+
+static int wf_sat_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct device_node *dev = client->dev.platform_data;
        struct wf_sat *sat;
        struct wf_sat_sensor *sens;
        const u32 *reg;
        const char *loc, *type;
-       u8 addr, chip, core;
+       u8 chip, core;
        struct device_node *child;
        int shift, cpu, index;
        char *name;
        int vsens[2], isens[2];
 
-       reg = of_get_property(dev, "reg", NULL);
-       if (reg == NULL)
-               return;
-       addr = *reg;
-       DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr);
-
        sat = kzalloc(sizeof(struct wf_sat), GFP_KERNEL);
        if (sat == NULL)
-               return;
+               return -ENOMEM;
        sat->nr = -1;
        sat->node = of_node_get(dev);
        atomic_set(&sat->refcnt, 0);
        mutex_init(&sat->mutex);
-       sat->i2c.addr = (addr >> 1) & 0x7f;
-       sat->i2c.adapter = adapter;
-       sat->i2c.driver = &wf_sat_driver;
-       strncpy(sat->i2c.name, "smu-sat", I2C_NAME_SIZE-1);
-
-       if (i2c_attach_client(&sat->i2c)) {
-               printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n");
-               goto fail;
-       }
+       sat->i2c = client;
+       i2c_set_clientdata(client, sat);
 
        vsens[0] = vsens[1] = -1;
        isens[0] = isens[1] = -1;
@@ -344,10 +348,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
        if (sat->nr >= 0)
                sats[sat->nr] = sat;
 
-       return;
-
- fail:
-       kfree(sat);
+       return 0;
 }
 
 static int wf_sat_attach(struct i2c_adapter *adapter)
@@ -366,16 +367,32 @@ static int wf_sat_attach(struct i2c_adapter *adapter)
        return 0;
 }
 
-static int wf_sat_detach(struct i2c_client *client)
+static int wf_sat_remove(struct i2c_client *client)
 {
-       struct wf_sat *sat = i2c_to_sat(client);
+       struct wf_sat *sat = i2c_get_clientdata(client);
 
        /* XXX TODO */
 
-       sat->i2c.adapter = NULL;
+       sat->i2c = NULL;
+       i2c_set_clientdata(client, NULL);
        return 0;
 }
 
+static const struct i2c_device_id wf_sat_id[] = {
+       { "wf_sat", 0 },
+       { }
+};
+
+static struct i2c_driver wf_sat_driver = {
+       .driver = {
+               .name           = "wf_smu_sat",
+       },
+       .attach_adapter = wf_sat_attach,
+       .probe          = wf_sat_probe,
+       .remove         = wf_sat_remove,
+       .id_table       = wf_sat_id,
+};
+
 static int __init sat_sensors_init(void)
 {
        return i2c_add_driver(&wf_sat_driver);
index 823ceba6efa8dcccc95b14cf72986195c52b3ae8..1128d3fba797f38a89f39849eea012bc9daa22d1 100644 (file)
@@ -1513,6 +1513,7 @@ static const struct file_operations _ctl_fops = {
 static struct miscdevice _dm_misc = {
        .minor          = MISC_DYNAMIC_MINOR,
        .name           = DM_NAME,
+       .devnode        = "mapper/control",
        .fops           = &_ctl_fops
 };
 
index 3fd8b1e65483da53070f0fe633e82843ac1a5ba0..48db308fae67103b221eeb1c10e4411560b88135 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/slab.h>
 #include <linux/idr.h>
 #include <linux/hdreg.h>
-#include <linux/blktrace_api.h>
 
 #include <trace/events/block.h>
 
index 1adce9ff52ce0fea7daee80fa46f94e15f85d1b4..7636c33bc1e97dc8ee783f3ef353c87f5f0c3042 100644 (file)
@@ -48,7 +48,7 @@ MODULE_PARM_DESC(audio_std,
        "NICAM/A\n"
        "NICAM/B\n");
 
-static char firmware_name[FIRMWARE_NAME_MAX];
+static char firmware_name[30];
 module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
 MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
                                "default firmware name\n");
index a454ee8f1e438939ecfd584d7fa90cdd2ec9c7b1..479dd05762a5d57a3bbcccad3aeb14807f2e0665 100644 (file)
@@ -447,6 +447,15 @@ static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
+static char *dvb_nodename(struct device *dev)
+{
+       struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+       return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
+               dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);
+}
+
+
 static int __init init_dvbdev(void)
 {
        int retval;
@@ -469,6 +478,7 @@ static int __init init_dvbdev(void)
                goto error;
        }
        dvb_class->dev_uevent = dvb_uevent;
+       dvb_class->nodename = dvb_nodename;
        return 0;
 
 error:
index 2d5352e54dc018d05959ab9d83f5634e126d2b83..b5157518a300f01b06eda411862ea106c88ab7d3 100644 (file)
@@ -196,7 +196,7 @@ struct dvb_usb_device_properties {
 #define CYPRESS_FX2     3
        int        usb_ctrl;
        int        (*download_firmware) (struct usb_device *, const struct firmware *);
-       const char firmware[FIRMWARE_NAME_MAX];
+       const char *firmware;
        int        no_reconnect;
 
        int size_of_priv;
index 4e207658c5d95a0c58dca4d62e6b664ad7e41f3f..2b6eeeab5b257ff2e2469afb8f0587da98a4ea0f 100644 (file)
@@ -225,7 +225,7 @@ fail_free:
 
 static int node_remove(struct device *dev)
 {
-       struct firedtv *fdtv = dev->driver_data;
+       struct firedtv *fdtv = dev_get_drvdata(dev);
 
        fdtv_dvb_unregister(fdtv);
 
@@ -242,7 +242,7 @@ static int node_remove(struct device *dev)
 
 static int node_update(struct unit_directory *ud)
 {
-       struct firedtv *fdtv = ud->device.driver_data;
+       struct firedtv *fdtv = dev_get_drvdata(&ud->device);
 
        if (fdtv->isochannel >= 0)
                cmp_establish_pp_connection(fdtv, fdtv->subunit,
index 9d308dd32a5ce4337efe97f594b2663aebe5570f..5742fde79d99d71f25bc62d390984a42294d1ab8 100644 (file)
@@ -268,7 +268,7 @@ struct firedtv *fdtv_alloc(struct device *dev,
        if (!fdtv)
                return NULL;
 
-       dev->driver_data        = fdtv;
+       dev_set_drvdata(dev, fdtv);
        fdtv->device            = dev;
        fdtv->isochannel        = -1;
        fdtv->voltage           = 0xff;
index ba3709bec3f0a42d84d34d2ba88e8bd62feb104a..ec2f45dde1643d72a849aa15004bbde91a1ff2c3 100644 (file)
@@ -747,8 +747,14 @@ static const struct file_operations dabusb_fops =
        .release =      dabusb_release,
 };
 
+static char *dabusb_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
 static struct usb_class_driver dabusb_class = {
        .name =         "dabusb%d",
+       .nodename =     dabusb_nodename,
        .fops =         &dabusb_fops,
        .minor_base =   DABUSB_MINOR,
 };
index 299c1cbc38329ca5c87423b4af78e0a2123ae638..6c23456e0bda2c2661030deb5737fb8ca120e2a5 100644 (file)
@@ -539,7 +539,7 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
                                         &sfp->attr_unit_number);
        }
        pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
-       sfp->class_dev->driver_data = NULL;
+       dev_set_drvdata(sfp->class_dev, NULL);
        device_unregister(sfp->class_dev);
        sfp->class_dev = NULL;
 }
@@ -549,7 +549,7 @@ static ssize_t v4l_minor_number_show(struct device *class_dev,
                                     struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%d\n",
                         pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
@@ -561,7 +561,7 @@ static ssize_t bus_info_show(struct device *class_dev,
                             struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%s\n",
                         pvr2_hdw_get_bus_info(sfp->channel.hdw));
@@ -572,7 +572,7 @@ static ssize_t hdw_name_show(struct device *class_dev,
                             struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%s\n",
                         pvr2_hdw_get_type(sfp->channel.hdw));
@@ -583,7 +583,7 @@ static ssize_t hdw_desc_show(struct device *class_dev,
                             struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%s\n",
                         pvr2_hdw_get_desc(sfp->channel.hdw));
@@ -595,7 +595,7 @@ static ssize_t v4l_radio_minor_number_show(struct device *class_dev,
                                           char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%d\n",
                         pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
@@ -607,7 +607,7 @@ static ssize_t unit_number_show(struct device *class_dev,
                                struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%d\n",
                         pvr2_hdw_get_unit_number(sfp->channel.hdw));
@@ -635,7 +635,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
        class_dev->parent = &usb_dev->dev;
 
        sfp->class_dev = class_dev;
-       class_dev->driver_data = sfp;
+       dev_set_drvdata(class_dev, sfp);
        ret = device_register(class_dev);
        if (ret) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
@@ -792,7 +792,7 @@ static ssize_t debuginfo_show(struct device *class_dev,
                              struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        pvr2_hdw_trigger_module_log(sfp->channel.hdw);
        return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE);
@@ -803,7 +803,7 @@ static ssize_t debugcmd_show(struct device *class_dev,
                             struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE);
 }
@@ -816,7 +816,7 @@ static ssize_t debugcmd_store(struct device *class_dev,
        struct pvr2_sysfs *sfp;
        int ret;
 
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
 
        ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count);
index 386da1566fccb41f76a6828e3e5de2dde965ccfb..cb73051e43db8ca04e1eabbdafd65af4966f47ef 100644 (file)
@@ -35,7 +35,7 @@ struct pasic3_data {
  */
 void pasic3_write_register(struct device *dev, u32 reg, u8 val)
 {
-       struct pasic3_data *asic = dev->driver_data;
+       struct pasic3_data *asic = dev_get_drvdata(dev);
        int bus_shift = asic->bus_shift;
        void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift);
        void __iomem *data = asic->mapping + (REG_DATA << bus_shift);
@@ -50,7 +50,7 @@ EXPORT_SYMBOL(pasic3_write_register); /* for leds-pasic3 */
  */
 u8 pasic3_read_register(struct device *dev, u32 reg)
 {
-       struct pasic3_data *asic = dev->driver_data;
+       struct pasic3_data *asic = dev_get_drvdata(dev);
        int bus_shift = asic->bus_shift;
        void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift);
        void __iomem *data = asic->mapping + (REG_DATA << bus_shift);
index 11a6248cc1c1dd0af3a57ace1ec228ccdb3ed257..082c197ab9b861f3071f4dac1677bbcfb512dca4 100644 (file)
@@ -618,7 +618,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
 
                pdev->dev.parent = pcf->dev;
                pdev->dev.platform_data = &pdata->reg_init_data[i];
-               pdev->dev.driver_data = pcf;
+               dev_set_drvdata(&pdev->dev, pcf);
                pcf->regulator_pdev[i] = pdev;
 
                platform_device_add(pdev);
index cf30d06a0104a6ab4f6295a7abf2a8ad85700a9a..7c21bf7915696253b75064b3146a89bdf5a9c905 100644 (file)
@@ -265,7 +265,7 @@ static int wm8400_init(struct wm8400 *wm8400,
 
        mutex_init(&wm8400->io_lock);
 
-       wm8400->dev->driver_data = wm8400;
+       dev_set_drvdata(wm8400->dev, wm8400);
 
        /* Check that this is actually a WM8400 */
        ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, &reg);
index 89fec052f3b45ee7bf774028349d634c700200fc..9118613af3210b1f0d52c8ad9ac73ba7f5793992 100644 (file)
@@ -48,6 +48,20 @@ config EEPROM_LEGACY
          This driver can also be built as a module.  If so, the module
          will be called eeprom.
 
+config EEPROM_MAX6875
+       tristate "Maxim MAX6874/5 power supply supervisor"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get read-only support for the user EEPROM of
+         the Maxim MAX6874/5 EEPROM-programmable, quad power-supply
+         sequencer/supervisor.
+
+         All other features of this chip should be accessed via i2c-dev.
+
+         This driver can also be built as a module.  If so, the module
+         will be called max6875.
+
+
 config EEPROM_93CX6
        tristate "EEPROM 93CX6 support"
        help
index 539dd8f881281f96f3c88c5cf16e2ca3045508c1..df3d68ffa9d18f20506cff8fd9b719d2a6cb8f22 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_EEPROM_AT24)      += at24.o
 obj-$(CONFIG_EEPROM_AT25)      += at25.o
 obj-$(CONFIG_EEPROM_LEGACY)    += eeprom.o
+obj-$(CONFIG_EEPROM_MAX6875)   += max6875.o
 obj-$(CONFIG_EEPROM_93CX6)     += eeprom_93cx6.o
diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c
new file mode 100644 (file)
index 0000000..3c0c58e
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+    max6875.c - driver for MAX6874/MAX6875
+
+    Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
+
+    Based on eeprom.c
+
+    The MAX6875 has a bank of registers and two banks of EEPROM.
+    Address ranges are defined as follows:
+     * 0x0000 - 0x0046 = configuration registers
+     * 0x8000 - 0x8046 = configuration EEPROM
+     * 0x8100 - 0x82FF = user EEPROM
+
+    This driver makes the user EEPROM available for read.
+
+    The registers & config EEPROM should be accessed via i2c-dev.
+
+    The MAX6875 ignores the lowest address bit, so each chip responds to
+    two addresses - 0x50/0x51 and 0x52/0x53.
+
+    Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read
+    address, so this driver is destructive if loaded for the wrong EEPROM chip.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; version 2 of the License.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+/* Do not scan - the MAX6875 access method will write to some EEPROM chips */
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(max6875);
+
+/* The MAX6875 can only read/write 16 bytes at a time */
+#define SLICE_SIZE                     16
+#define SLICE_BITS                     4
+
+/* USER EEPROM is at addresses 0x8100 - 0x82FF */
+#define USER_EEPROM_BASE               0x8100
+#define USER_EEPROM_SIZE               0x0200
+#define USER_EEPROM_SLICES             32
+
+/* MAX6875 commands */
+#define MAX6875_CMD_BLK_READ           0x84
+
+/* Each client has this additional data */
+struct max6875_data {
+       struct i2c_client       *fake_client;
+       struct mutex            update_lock;
+
+       u32                     valid;
+       u8                      data[USER_EEPROM_SIZE];
+       unsigned long           last_updated[USER_EEPROM_SLICES];
+};
+
+static void max6875_update_slice(struct i2c_client *client, int slice)
+{
+       struct max6875_data *data = i2c_get_clientdata(client);
+       int i, j, addr;
+       u8 *buf;
+
+       if (slice >= USER_EEPROM_SLICES)
+               return;
+
+       mutex_lock(&data->update_lock);
+
+       buf = &data->data[slice << SLICE_BITS];
+
+       if (!(data->valid & (1 << slice)) ||
+           time_after(jiffies, data->last_updated[slice])) {
+
+               dev_dbg(&client->dev, "Starting update of slice %u\n", slice);
+
+               data->valid &= ~(1 << slice);
+
+               addr = USER_EEPROM_BASE + (slice << SLICE_BITS);
+
+               /* select the eeprom address */
+               if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) {
+                       dev_err(&client->dev, "address set failed\n");
+                       goto exit_up;
+               }
+
+               if (i2c_check_functionality(client->adapter,
+                                           I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+                       if (i2c_smbus_read_i2c_block_data(client,
+                                                         MAX6875_CMD_BLK_READ,
+                                                         SLICE_SIZE,
+                                                         buf) != SLICE_SIZE) {
+                               goto exit_up;
+                       }
+               } else {
+                       for (i = 0; i < SLICE_SIZE; i++) {
+                               j = i2c_smbus_read_byte(client);
+                               if (j < 0) {
+                                       goto exit_up;
+                               }
+                               buf[i] = j;
+                       }
+               }
+               data->last_updated[slice] = jiffies;
+               data->valid |= (1 << slice);
+       }
+exit_up:
+       mutex_unlock(&data->update_lock);
+}
+
+static ssize_t max6875_read(struct kobject *kobj,
+                           struct bin_attribute *bin_attr,
+                           char *buf, loff_t off, size_t count)
+{
+       struct i2c_client *client = kobj_to_i2c_client(kobj);
+       struct max6875_data *data = i2c_get_clientdata(client);
+       int slice, max_slice;
+
+       if (off > USER_EEPROM_SIZE)
+               return 0;
+
+       if (off + count > USER_EEPROM_SIZE)
+               count = USER_EEPROM_SIZE - off;
+
+       /* refresh slices which contain requested bytes */
+       max_slice = (off + count - 1) >> SLICE_BITS;
+       for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++)
+               max6875_update_slice(client, slice);
+
+       memcpy(buf, &data->data[off], count);
+
+       return count;
+}
+
+static struct bin_attribute user_eeprom_attr = {
+       .attr = {
+               .name = "eeprom",
+               .mode = S_IRUGO,
+       },
+       .size = USER_EEPROM_SIZE,
+       .read = max6875_read,
+};
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max6875_detect(struct i2c_client *client, int kind,
+                         struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
+                                    | I2C_FUNC_SMBUS_READ_BYTE))
+               return -ENODEV;
+
+       /* Only check even addresses */
+       if (client->addr & 1)
+               return -ENODEV;
+
+       strlcpy(info->type, "max6875", I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int max6875_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct max6875_data *data;
+       int err;
+
+       if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL)))
+               return -ENOMEM;
+
+       /* A fake client is created on the odd address */
+       data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1);
+       if (!data->fake_client) {
+               err = -ENOMEM;
+               goto exit_kfree;
+       }
+
+       /* Init real i2c_client */
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr);
+       if (err)
+               goto exit_remove_fake;
+
+       return 0;
+
+exit_remove_fake:
+       i2c_unregister_device(data->fake_client);
+exit_kfree:
+       kfree(data);
+       return err;
+}
+
+static int max6875_remove(struct i2c_client *client)
+{
+       struct max6875_data *data = i2c_get_clientdata(client);
+
+       i2c_unregister_device(data->fake_client);
+
+       sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
+       kfree(data);
+
+       return 0;
+}
+
+static const struct i2c_device_id max6875_id[] = {
+       { "max6875", 0 },
+       { }
+};
+
+static struct i2c_driver max6875_driver = {
+       .driver = {
+               .name   = "max6875",
+       },
+       .probe          = max6875_probe,
+       .remove         = max6875_remove,
+       .id_table       = max6875_id,
+
+       .detect         = max6875_detect,
+       .address_data   = &addr_data,
+};
+
+static int __init max6875_init(void)
+{
+       return i2c_add_driver(&max6875_driver);
+}
+
+static void __exit max6875_exit(void)
+{
+       i2c_del_driver(&max6875_driver);
+}
+
+
+MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>");
+MODULE_DESCRIPTION("MAX6875 driver");
+MODULE_LICENSE("GPL");
+
+module_init(max6875_init);
+module_exit(max6875_exit);
index 01f282cd0989d7123b0cb1b74477cded1571919d..3b6383168c6916cf57c41015d8a10c22dee0d015 100644 (file)
@@ -2206,7 +2206,7 @@ config SKGE_DEBUG
        depends on SKGE && DEBUG_FS
        help
         This option adds the ability to dump driver state for debugging.
-        The file debugfs/skge/ethX displays the state of the internal
+        The file /sys/kernel/debug/skge/ethX displays the state of the internal
         transmit and receive rings.
 
         If unsure, say N.
@@ -2232,7 +2232,7 @@ config SKY2_DEBUG
        depends on SKY2 && DEBUG_FS
        help
         This option adds the ability to dump driver state for debugging.
-        The file debugfs/sky2/ethX displays the state of the internal
+        The file /sys/kernel/debug/sky2/ethX displays the state of the internal
         transmit and receive rings.
 
         If unsure, say N.
index 30900b30d532e9dedf2b040a672d47d0921e6203..2b38f39924a67df3e6cd1ce657ac949535f18d1a 100644 (file)
@@ -1648,7 +1648,7 @@ static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev)
                result = -ENOMEM;
                goto fail_alloc_card;
        }
-       ps3_system_bus_set_driver_data(dev, card);
+       ps3_system_bus_set_drvdata(dev, card);
        card->dev = dev;
 
        /* get internal vlan info */
@@ -1749,7 +1749,7 @@ fail_alloc_irq:
                                               bus_id(card),
                                               0, 0);
 fail_status_indicator:
-       ps3_system_bus_set_driver_data(dev, NULL);
+       ps3_system_bus_set_drvdata(dev, NULL);
        kfree(netdev_card(netdev)->unalign);
        free_netdev(netdev);
 fail_alloc_card:
@@ -1766,7 +1766,7 @@ fail_open:
 
 static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev)
 {
-       struct gelic_card *card = ps3_system_bus_get_driver_data(dev);
+       struct gelic_card *card = ps3_system_bus_get_drvdata(dev);
        struct net_device *netdev0;
        pr_debug("%s: called\n", __func__);
 
@@ -1803,7 +1803,7 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev)
        kfree(netdev_card(netdev0)->unalign);
        free_netdev(netdev0);
 
-       ps3_system_bus_set_driver_data(dev, NULL);
+       ps3_system_bus_set_drvdata(dev, NULL);
 
        ps3_dma_region_free(dev->d_region);
 
index 811d3517fce0c99895b4738df64a60d934f86fcf..11a0ba47b67782d920f3bf5cb36d3e24d4874b63 100644 (file)
@@ -1366,6 +1366,7 @@ static const struct file_operations tun_fops = {
 static struct miscdevice tun_miscdev = {
        .minor = TUN_MINOR,
        .name = "tun",
+       .devnode = "net/tun",
        .fops = &tun_fops,
 };
 
index 1fe5da4cf0a02d918942e0f19f7a36aaf9ef1264..60330f313f2781ea65630a484564ef7750011487 100644 (file)
@@ -432,7 +432,7 @@ struct i2400m {
        unsigned ready:1;               /* all probing steps done */
        unsigned rx_reorder:1;          /* RX reorder is enabled */
        u8 trace_msg_from_user;         /* echo rx msgs to 'trace' pipe */
-                                       /* typed u8 so debugfs/u8 can tweak */
+                                       /* typed u8 so /sys/kernel/debug/u8 can tweak */
        enum i2400m_system_state state;
        wait_queue_head_t state_wq;     /* Woken up when on state updates */
 
index 509b6f94f73b94930ad95f90441e6b4002223ee9..daf0c83527d88cd0f6e64ff29e26ef7c5387fe4b 100644 (file)
@@ -28,11 +28,10 @@ config ATH5K_DEBUG
          Say Y, if and you will get debug options for ath5k.
          To use this, you need to mount debugfs:
 
-         mkdir /debug/
-         mount -t debugfs debug /debug/
+         mount -t debugfs debug /sys/kernel/debug
 
          You will get access to files under:
-         /debug/ath5k/phy0/
+         /sys/kernel/debug/ath5k/phy0/
 
          To enable debug, pass the debug level to the debug module
          parameter. For example:
index d860fc375752d928b3d51e2ec7e6cca1fdd416d8..ab6a2d518af0ff07f0cd1ff1aec21f777208a644 100644 (file)
@@ -72,7 +72,7 @@ rdrf
        location that is to be read.  This parameter must be specified in
        hexadecimal (its possible to preceed preceding the number with a "0x").
 
-       Path: /debugfs/libertas_wireless/ethX/registers/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/registers/
 
        Usage:
                echo "0xa123" > rdmac ; cat rdmac
@@ -95,7 +95,7 @@ wrrf
 sleepparams
        This command is used to set the sleepclock configurations
 
-       Path: /debugfs/libertas_wireless/ethX/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
 
        Usage:
                cat sleepparams: reads the current sleepclock configuration
@@ -115,7 +115,7 @@ subscribed_events
        The subscribed_events directory contains the interface for the
        subscribed events API.
 
-       Path: /debugfs/libertas_wireless/ethX/subscribed_events/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/subscribed_events/
 
        Each event is represented by a filename. Each filename consists of the
        following three fields:
@@ -165,7 +165,7 @@ subscribed_events
 extscan
        This command is used to do a specific scan.
 
-       Path: /debugfs/libertas_wireless/ethX/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
 
        Usage: echo "SSID" > extscan
 
@@ -179,7 +179,7 @@ getscantable
        Display the current contents of the driver scan table (ie. get the
        scan results).
 
-       Path: /debugfs/libertas_wireless/ethX/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
 
        Usage:
                cat getscantable
@@ -188,7 +188,7 @@ setuserscan
        Initiate a customized scan and retrieve the results
 
 
-       Path: /debugfs/libertas_wireless/ethX/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
 
     Usage:
        echo "[ARGS]" > setuserscan
index f8c2898d82b05b305e69c566e52e8291b5118348..06a46d7b3d6c2460aecd793d2827033c7c0348f6 100644 (file)
@@ -43,8 +43,8 @@ struct if_spi_card {
        struct lbs_private              *priv;
        struct libertas_spi_platform_data *pdata;
 
-       char                            helper_fw_name[FIRMWARE_NAME_MAX];
-       char                            main_fw_name[FIRMWARE_NAME_MAX];
+       char                            helper_fw_name[IF_SPI_FW_NAME_MAX];
+       char                            main_fw_name[IF_SPI_FW_NAME_MAX];
 
        /* The card ID and card revision, as reported by the hardware. */
        u16                             card_id;
@@ -1019,9 +1019,9 @@ static int if_spi_calculate_fw_names(u16 card_id,
                lbs_pr_err("Unsupported chip_id: 0x%02x\n", card_id);
                return -EAFNOSUPPORT;
        }
-       snprintf(helper_fw, FIRMWARE_NAME_MAX, "libertas/gspi%d_hlp.bin",
+       snprintf(helper_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d_hlp.bin",
                 chip_id_to_device_name[i].name);
-       snprintf(main_fw, FIRMWARE_NAME_MAX, "libertas/gspi%d.bin",
+       snprintf(main_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d.bin",
                 chip_id_to_device_name[i].name);
        return 0;
 }
index 2103869cc5b06dc8940eb2a3c8c00cd89af6c8a5..f87eec410848fb023416170c0241a84938949f55 100644 (file)
@@ -22,6 +22,9 @@
 #define IF_SPI_CMD_BUF_SIZE 2400
 
 /***************** Firmware *****************/
+
+#define IF_SPI_FW_NAME_MAX 30
+
 struct chip_ident {
        u16 chip_id;
        u16 name;
index d649caebf08a1e93ffd9a136f7682340fe380f33..1844c5adf6e9fb1ad3807f5346174a75654a71c8 100644 (file)
@@ -61,11 +61,9 @@ static ssize_t if_usb_firmware_set(struct device *dev,
 {
        struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct if_usb_card *cardp = priv->card;
-       char fwname[FIRMWARE_NAME_MAX];
        int ret;
 
-       sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */
-       ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_FW);
+       ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_FW);
        if (ret == 0)
                return count;
 
@@ -88,11 +86,9 @@ static ssize_t if_usb_boot2_set(struct device *dev,
 {
        struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct if_usb_card *cardp = priv->card;
-       char fwname[FIRMWARE_NAME_MAX];
        int ret;
 
-       sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */
-       ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_BOOT2);
+       ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_BOOT2);
        if (ret == 0)
                return count;
 
index f673253879024d18b90557be62b145feb7e99ec7..8d88daeed0c6e51c7b73046468a6e8a2606de77d 100644 (file)
@@ -1212,7 +1212,7 @@ static int __devinit netfront_probe(struct xenbus_device *dev,
        }
 
        info = netdev_priv(netdev);
-       dev->dev.driver_data = info;
+       dev_set_drvdata(&dev->dev, info);
 
        err = register_netdev(info->netdev);
        if (err) {
@@ -1233,7 +1233,7 @@ static int __devinit netfront_probe(struct xenbus_device *dev,
 
  fail:
        free_netdev(netdev);
-       dev->dev.driver_data = NULL;
+       dev_set_drvdata(&dev->dev, NULL);
        return err;
 }
 
@@ -1275,7 +1275,7 @@ static void xennet_disconnect_backend(struct netfront_info *info)
  */
 static int netfront_resume(struct xenbus_device *dev)
 {
-       struct netfront_info *info = dev->dev.driver_data;
+       struct netfront_info *info = dev_get_drvdata(&dev->dev);
 
        dev_dbg(&dev->dev, "%s\n", dev->nodename);
 
@@ -1600,7 +1600,7 @@ static int xennet_connect(struct net_device *dev)
 static void backend_changed(struct xenbus_device *dev,
                            enum xenbus_state backend_state)
 {
-       struct netfront_info *np = dev->dev.driver_data;
+       struct netfront_info *np = dev_get_drvdata(&dev->dev);
        struct net_device *netdev = np->netdev;
 
        dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state));
@@ -1774,7 +1774,7 @@ static struct xenbus_device_id netfront_ids[] = {
 
 static int __devexit xennet_remove(struct xenbus_device *dev)
 {
-       struct netfront_info *info = dev->dev.driver_data;
+       struct netfront_info *info = dev_get_drvdata(&dev->dev);
 
        dev_dbg(&dev->dev, "%s\n", dev->nodename);
 
index f415fdd9a88599296a9c5195854c25192b8fbc0b..5b89f404e668876f53da1f0278523763e3512e16 100644 (file)
@@ -373,7 +373,7 @@ static int __init eisa_probe(struct parisc_device *dev)
        if (result >= 0) {
                /* FIXME : Don't enumerate the bus twice. */
                eisa_dev.root.dev = &dev->dev;
-               dev->dev.driver_data = &eisa_dev.root;
+               dev_set_drvdata(&dev->dev, &eisa_dev.root);
                eisa_dev.root.bus_base_addr = 0;
                eisa_dev.root.res = &eisa_dev.hba.io_space;
                eisa_dev.root.slots = result;
index e5999c4cedc81d64aad819f25a9d38a78de06f78..d46dd57450acd151d4d97a7d7016e54cedab1f54 100644 (file)
@@ -2010,7 +2010,7 @@ void __init sba_init(void)
 void * sba_get_iommu(struct parisc_device *pci_hba)
 {
        struct parisc_device *sba_dev = parisc_parent(pci_hba);
-       struct sba_device *sba = sba_dev->dev.driver_data;
+       struct sba_device *sba = dev_get_drvdata(&sba_dev->dev);
        char t = sba_dev->id.hw_type;
        int iocnum = (pci_hba->hw_path >> 3);   /* rope # */
 
@@ -2031,7 +2031,7 @@ void * sba_get_iommu(struct parisc_device *pci_hba)
 void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r)
 {
        struct parisc_device *sba_dev = parisc_parent(pci_hba);
-       struct sba_device *sba = sba_dev->dev.driver_data;
+       struct sba_device *sba = dev_get_drvdata(&sba_dev->dev);
        char t = sba_dev->id.hw_type;
        int i;
        int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1));  /* rope # */
@@ -2073,7 +2073,7 @@ void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r)
 void sba_distributed_lmmio(struct parisc_device *pci_hba, struct resource *r )
 {
        struct parisc_device *sba_dev = parisc_parent(pci_hba);
-       struct sba_device *sba = sba_dev->dev.driver_data;
+       struct sba_device *sba = dev_get_drvdata(&sba_dev->dev);
        char t = sba_dev->id.hw_type;
        int base, size;
        int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1));  /* rope # */
index ea31a452b153e55e8ce378000e02ee952a5e8991..5d6de380e42ba87526cdfa2b87f658431223be86 100644 (file)
@@ -376,14 +376,14 @@ static int __devinit parport_init_chip(struct parisc_device *dev)
                        /* PARPORT_IRQ_NONE */ PARPORT_DMA_NONE, NULL);
        if (p)
                parport_count++;
-       dev->dev.driver_data = p;
+       dev_set_drvdata(&dev->dev, p);
 
        return 0;
 }
 
 static int __devexit parport_remove_chip(struct parisc_device *dev)
 {
-       struct parport *p = dev->dev.driver_data;
+       struct parport *p = dev_get_drvdata(&dev->dev);
        if (p) {
                struct parport_gsc_private *priv = p->private_data;
                struct parport_operations *ops = p->ops;
index e39982503863e4a1539d4f1f968a9dbf47bc3242..13ffdc35ea0eb2573f47d81953871ef61ffc8b48 100644 (file)
@@ -275,7 +275,7 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
        memset(device, 0, sizeof(struct device));
        device->bus = &pcie_port_bus_type;
        device->driver = NULL;
-       device->driver_data = NULL;
+       dev_set_drvdata(device, NULL);
        device->release = release_pcie_device;  /* callback to free pcie dev */
        dev_set_name(device, "%s:pcie%02x",
                 pci_name(parent), get_descriptor_id(port_type, service_type));
index 47cab31ff6e49c0780692ead159cf81fb4113c58..304ff6d5cf3b2ec13850a253bc908481027cd844 100644 (file)
@@ -394,7 +394,7 @@ static int pcmcia_device_probe(struct device * dev)
        p_drv = to_pcmcia_drv(dev->driver);
        s = p_dev->socket;
 
-       /* The PCMCIA code passes the match data in via dev->driver_data
+       /* The PCMCIA code passes the match data in via dev_set_drvdata(dev)
         * which is an ugly hack. Once the driver probe is called it may
         * and often will overwrite the match data so we must save it first
         *
@@ -404,7 +404,7 @@ static int pcmcia_device_probe(struct device * dev)
         * call which will then check whether there are two
         * pseudo devices, and if not, add the second one.
         */
-       did = p_dev->dev.driver_data;
+       did = dev_get_drvdata(&p_dev->dev);
 
        ds_dev_dbg(1, dev, "trying to bind to %s\n", p_drv->drv.name);
 
@@ -499,7 +499,7 @@ static int pcmcia_device_remove(struct device * dev)
         * pseudo multi-function card, we need to unbind
         * all devices
         */
-       did = p_dev->dev.driver_data;
+       did = dev_get_drvdata(&p_dev->dev);
        if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
            (p_dev->socket->device_count != 0) &&
            (p_dev->device_no == 0))
@@ -828,7 +828,6 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
 {
        struct pcmcia_socket *s = dev->socket;
        const struct firmware *fw;
-       char path[FIRMWARE_NAME_MAX];
        int ret = -ENOMEM;
        int no_funcs;
        int old_funcs;
@@ -839,16 +838,7 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
 
        ds_dev_dbg(1, &dev->dev, "trying to load CIS file %s\n", filename);
 
-       if (strlen(filename) > (FIRMWARE_NAME_MAX - 1)) {
-               dev_printk(KERN_WARNING, &dev->dev,
-                          "pcmcia: CIS filename is too long [%s]\n",
-                          filename);
-               return -EINVAL;
-       }
-
-       snprintf(path, sizeof(path), "%s", filename);
-
-       if (request_firmware(&fw, path, &dev->dev) == 0) {
+       if (request_firmware(&fw, filename, &dev->dev) == 0) {
                if (fw->size >= CISTPL_MAX_CIS_SIZE) {
                        ret = -EINVAL;
                        dev_printk(KERN_ERR, &dev->dev,
@@ -988,7 +978,7 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
                        return 0;
        }
 
-       dev->dev.driver_data = (void *) did;
+       dev_set_drvdata(&dev->dev, did);
 
        return 1;
 }
index f17513dd9d4ba4a340effd9cb63f5fa6e1a04eeb..88cb74088611be6258013f53a9ec28c0a1c86d09 100644 (file)
@@ -706,7 +706,7 @@ static void ps3_sys_manager_work(struct ps3_system_bus_device *dev)
        ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
 }
 
-static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
+static int __devinit ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
 {
        int result;
        struct ps3_sys_manager_ops ops;
index 235e87fcb49f5c5ab5979c2dc2fd6eeaa4b5feef..e82d8c9c6cda6a6c098ce2c7bd685d30515fcb5b 100644 (file)
@@ -80,12 +80,12 @@ static const struct avset_video_mode {
        {     0, }, /* auto */
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I,       A_N,  720,  480},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P,       A_N,  720,  480},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ,  A_N, 1280,  720},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ,  A_W, 1280,  720},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I,       A_N,  720,  576},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P,       A_N,  720,  576},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ,  A_N, 1280,  720},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ,  A_W, 1280,  720},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080},
        {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA,       A_W, 1280,  768},
@@ -937,7 +937,7 @@ int ps3av_audio_mute(int mute)
 
 EXPORT_SYMBOL_GPL(ps3av_audio_mute);
 
-static int ps3av_probe(struct ps3_system_bus_device *dev)
+static int __devinit ps3av_probe(struct ps3_system_bus_device *dev)
 {
        int res;
        int id;
@@ -1048,7 +1048,7 @@ static struct ps3_vuart_port_driver ps3av_driver = {
        .shutdown = ps3av_shutdown,
 };
 
-static int ps3av_module_init(void)
+static int __init ps3av_module_init(void)
 {
        int error;
 
index 716596e8e5b0acdc26d92d607af85516897f932d..f555fedd5073270a7624995e09417b1e41119663 100644 (file)
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+
 #include <asm/ps3av.h>
-#include <asm/ps3fb.h>
 #include <asm/ps3.h>
+#include <asm/ps3gpu.h>
 
 #include "vuart.h"
 
index 442bb98a2821c5a34519b08e452bfb9ffa1bf629..e5b84db0aa037d97bd6df4fb0ee234b3a49ce5ab 100644 (file)
@@ -5,8 +5,7 @@
  *                 Carsten Otte <Cotte@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
- *
+ * Copyright IBM Corp. 1999, 2009
  */
 
 #define KMSG_COMPONENT "dasd"
@@ -61,6 +60,7 @@ static int dasd_flush_block_queue(struct dasd_block *);
 static void dasd_device_tasklet(struct dasd_device *);
 static void dasd_block_tasklet(struct dasd_block *);
 static void do_kick_device(struct work_struct *);
+static void do_restore_device(struct work_struct *);
 static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
 static void dasd_device_timeout(unsigned long);
 static void dasd_block_timeout(unsigned long);
@@ -109,6 +109,7 @@ struct dasd_device *dasd_alloc_device(void)
        device->timer.function = dasd_device_timeout;
        device->timer.data = (unsigned long) device;
        INIT_WORK(&device->kick_work, do_kick_device);
+       INIT_WORK(&device->restore_device, do_restore_device);
        device->state = DASD_STATE_NEW;
        device->target = DASD_STATE_NEW;
 
@@ -511,6 +512,25 @@ void dasd_kick_device(struct dasd_device *device)
        schedule_work(&device->kick_work);
 }
 
+/*
+ * dasd_restore_device will schedule a call do do_restore_device to the kernel
+ * event daemon.
+ */
+static void do_restore_device(struct work_struct *work)
+{
+       struct dasd_device *device = container_of(work, struct dasd_device,
+                                                 restore_device);
+       device->cdev->drv->restore(device->cdev);
+       dasd_put_device(device);
+}
+
+void dasd_restore_device(struct dasd_device *device)
+{
+       dasd_get_device(device);
+       /* queue call to dasd_restore_device to the kernel event daemon. */
+       schedule_work(&device->restore_device);
+}
+
 /*
  * Set the target state for a device and starts the state change.
  */
@@ -908,6 +928,12 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
                DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
                              "start_IO: -EIO device gone, retry");
                break;
+       case -EINVAL:
+               /* most likely caused in power management context */
+               DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
+                             "start_IO: -EINVAL device currently "
+                             "not accessible");
+               break;
        default:
                /* internal error 11 - unknown rc */
                snprintf(errorstring, ERRORLENGTH, "11 %d", rc);
@@ -2400,6 +2426,12 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
        case CIO_OPER:
                /* FIXME: add a sanity check. */
                device->stopped &= ~DASD_STOPPED_DC_WAIT;
+               if (device->stopped & DASD_UNRESUMED_PM) {
+                       device->stopped &= ~DASD_UNRESUMED_PM;
+                       dasd_restore_device(device);
+                       ret = 1;
+                       break;
+               }
                dasd_schedule_device_bh(device);
                if (device->block)
                        dasd_schedule_block_bh(device->block);
@@ -2410,6 +2442,79 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
        return ret;
 }
 
+int dasd_generic_pm_freeze(struct ccw_device *cdev)
+{
+       struct dasd_ccw_req *cqr, *n;
+       int rc;
+       struct list_head freeze_queue;
+       struct dasd_device *device = dasd_device_from_cdev(cdev);
+
+       if (IS_ERR(device))
+               return PTR_ERR(device);
+       /* disallow new I/O  */
+       device->stopped |= DASD_STOPPED_PM;
+       /* clear active requests */
+       INIT_LIST_HEAD(&freeze_queue);
+       spin_lock_irq(get_ccwdev_lock(cdev));
+       rc = 0;
+       list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) {
+               /* Check status and move request to flush_queue */
+               if (cqr->status == DASD_CQR_IN_IO) {
+                       rc = device->discipline->term_IO(cqr);
+                       if (rc) {
+                               /* unable to terminate requeust */
+                               dev_err(&device->cdev->dev,
+                                       "Unable to terminate request %p "
+                                       "on suspend\n", cqr);
+                               spin_unlock_irq(get_ccwdev_lock(cdev));
+                               dasd_put_device(device);
+                               return rc;
+                       }
+               }
+               list_move_tail(&cqr->devlist, &freeze_queue);
+       }
+
+       spin_unlock_irq(get_ccwdev_lock(cdev));
+
+       list_for_each_entry_safe(cqr, n, &freeze_queue, devlist) {
+               wait_event(dasd_flush_wq,
+                          (cqr->status != DASD_CQR_CLEAR_PENDING));
+               if (cqr->status == DASD_CQR_CLEARED)
+                       cqr->status = DASD_CQR_QUEUED;
+       }
+       /* move freeze_queue to start of the ccw_queue */
+       spin_lock_irq(get_ccwdev_lock(cdev));
+       list_splice_tail(&freeze_queue, &device->ccw_queue);
+       spin_unlock_irq(get_ccwdev_lock(cdev));
+
+       if (device->discipline->freeze)
+               rc = device->discipline->freeze(device);
+
+       dasd_put_device(device);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(dasd_generic_pm_freeze);
+
+int dasd_generic_restore_device(struct ccw_device *cdev)
+{
+       struct dasd_device *device = dasd_device_from_cdev(cdev);
+       int rc = 0;
+
+       if (IS_ERR(device))
+               return PTR_ERR(device);
+
+       dasd_schedule_device_bh(device);
+       if (device->block)
+               dasd_schedule_block_bh(device->block);
+
+       if (device->discipline->restore)
+               rc = device->discipline->restore(device);
+
+       dasd_put_device(device);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(dasd_generic_restore_device);
+
 static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
                                                   void *rdc_buffer,
                                                   int rdc_buffer_size,
index e77666c8e6c01af8df79963215c686112b8a2a42..4cac5b54f26a6fff837c17983d4fe79a05811af5 100644 (file)
@@ -1098,6 +1098,7 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
        spin_unlock(&dasd_devmap_lock);
        return 0;
 }
+EXPORT_SYMBOL_GPL(dasd_get_uid);
 
 /*
  * Register the given device unique identifier into devmap struct.
index cf0cfdba1244bb95891955820f6e873b24bdb6c7..1c28ec3e4ccb63bb554563c292173d19faa2efa6 100644 (file)
@@ -5,10 +5,9 @@
  *                 Carsten Otte <Cotte@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * Copyright IBM Corp. 1999, 2009
  * EMC Symmetrix ioctl Copyright EMC Corporation, 2008
  * Author.........: Nigel Hislop <hislop_nigel@emc.com>
- *
  */
 
 #define KMSG_COMPONENT "dasd"
@@ -104,17 +103,6 @@ dasd_eckd_set_online(struct ccw_device *cdev)
        return dasd_generic_set_online(cdev, &dasd_eckd_discipline);
 }
 
-static struct ccw_driver dasd_eckd_driver = {
-       .name        = "dasd-eckd",
-       .owner       = THIS_MODULE,
-       .ids         = dasd_eckd_ids,
-       .probe       = dasd_eckd_probe,
-       .remove      = dasd_generic_remove,
-       .set_offline = dasd_generic_set_offline,
-       .set_online  = dasd_eckd_set_online,
-       .notify      = dasd_generic_notify,
-};
-
 static const int sizes_trk0[] = { 28, 148, 84 };
 #define LABEL_SIZE 140
 
@@ -3236,6 +3224,98 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
                dasd_eckd_dump_sense_ccw(device, req, irb);
 }
 
+int dasd_eckd_pm_freeze(struct dasd_device *device)
+{
+       /*
+        * the device should be disconnected from our LCU structure
+        * on restore we will reconnect it and reread LCU specific
+        * information like PAV support that might have changed
+        */
+       dasd_alias_remove_device(device);
+       dasd_alias_disconnect_device_from_lcu(device);
+
+       return 0;
+}
+
+int dasd_eckd_restore_device(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private;
+       int is_known, rc;
+       struct dasd_uid temp_uid;
+
+       /* allow new IO again */
+       device->stopped &= ~DASD_STOPPED_PM;
+
+       private = (struct dasd_eckd_private *) device->private;
+
+       /* Read Configuration Data */
+       rc = dasd_eckd_read_conf(device);
+       if (rc)
+               goto out_err;
+
+       /* Generate device unique id and register in devmap */
+       rc = dasd_eckd_generate_uid(device, &private->uid);
+       dasd_get_uid(device->cdev, &temp_uid);
+       if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0)
+               dev_err(&device->cdev->dev, "The UID of the DASD has changed\n");
+       if (rc)
+               goto out_err;
+       dasd_set_uid(device->cdev, &private->uid);
+
+       /* register lcu with alias handling, enable PAV if this is a new lcu */
+       is_known = dasd_alias_make_device_known_to_lcu(device);
+       if (is_known < 0)
+               return is_known;
+       if (!is_known) {
+               /* new lcu found */
+               rc = dasd_eckd_validate_server(device); /* will switch pav on */
+               if (rc)
+                       goto out_err;
+       }
+
+       /* Read Feature Codes */
+       rc = dasd_eckd_read_features(device);
+       if (rc)
+               goto out_err;
+
+       /* Read Device Characteristics */
+       memset(&private->rdc_data, 0, sizeof(private->rdc_data));
+       rc = dasd_generic_read_dev_chars(device, "ECKD",
+                                        &private->rdc_data, 64);
+       if (rc) {
+               DBF_EVENT(DBF_WARNING,
+                         "Read device characteristics failed, rc=%d for "
+                         "device: %s", rc, dev_name(&device->cdev->dev));
+               goto out_err;
+       }
+
+       /* add device to alias management */
+       dasd_alias_add_device(device);
+
+       return 0;
+
+out_err:
+       /*
+        * if the resume failed for the DASD we put it in
+        * an UNRESUMED stop state
+        */
+       device->stopped |= DASD_UNRESUMED_PM;
+       return 0;
+}
+
+static struct ccw_driver dasd_eckd_driver = {
+       .name        = "dasd-eckd",
+       .owner       = THIS_MODULE,
+       .ids         = dasd_eckd_ids,
+       .probe       = dasd_eckd_probe,
+       .remove      = dasd_generic_remove,
+       .set_offline = dasd_generic_set_offline,
+       .set_online  = dasd_eckd_set_online,
+       .notify      = dasd_generic_notify,
+       .freeze      = dasd_generic_pm_freeze,
+       .thaw        = dasd_generic_restore_device,
+       .restore     = dasd_generic_restore_device,
+};
 
 /*
  * max_blocks is dependent on the amount of storage that is available
@@ -3274,6 +3354,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
        .dump_sense_dbf = dasd_eckd_dump_sense_dbf,
        .fill_info = dasd_eckd_fill_info,
        .ioctl = dasd_eckd_ioctl,
+       .freeze = dasd_eckd_pm_freeze,
+       .restore = dasd_eckd_restore_device,
 };
 
 static int __init
index 597c6ffdb9f2308258a292a0b584f440f9c0ec6a..e21ee735f92673c4df91fb91a4c788f0b1d97b46 100644 (file)
@@ -2,8 +2,7 @@
  * File...........: linux/drivers/s390/block/dasd_fba.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- *
+ * Copyright IBM Corp. 1999, 2009
  */
 
 #define KMSG_COMPONENT "dasd"
@@ -75,6 +74,9 @@ static struct ccw_driver dasd_fba_driver = {
        .set_offline = dasd_generic_set_offline,
        .set_online  = dasd_fba_set_online,
        .notify      = dasd_generic_notify,
+       .freeze      = dasd_generic_pm_freeze,
+       .thaw        = dasd_generic_restore_device,
+       .restore     = dasd_generic_restore_device,
 };
 
 static void
index f97ceb795078ee9c1cb0df2bba09c0755575dc9f..fd63b2f2bda9baeaefb4e0edefb2bd2407c4c913 100644 (file)
@@ -4,8 +4,7 @@
  *                 Horst Hummel <Horst.Hummel@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- *
+ * Copyright IBM Corp. 1999, 2009
  */
 
 #ifndef DASD_INT_H
@@ -295,6 +294,10 @@ struct dasd_discipline {
        int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
        int (*fill_info) (struct dasd_device *, struct dasd_information2_t *);
        int (*ioctl) (struct dasd_block *, unsigned int, void __user *);
+
+       /* suspend/resume functions */
+       int (*freeze) (struct dasd_device *);
+       int (*restore) (struct dasd_device *);
 };
 
 extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -367,6 +370,7 @@ struct dasd_device {
        atomic_t tasklet_scheduled;
         struct tasklet_struct tasklet;
        struct work_struct kick_work;
+       struct work_struct restore_device;
        struct timer_list timer;
 
        debug_info_t *debug_area;
@@ -410,6 +414,8 @@ struct dasd_block {
 #define DASD_STOPPED_PENDING 4         /* long busy */
 #define DASD_STOPPED_DC_WAIT 8         /* disconnected, wait */
 #define DASD_STOPPED_SU      16        /* summary unit check handling */
+#define DASD_STOPPED_PM      32        /* pm state transition */
+#define DASD_UNRESUMED_PM    64        /* pm resume failed state */
 
 /* per device flags */
 #define DASD_FLAG_OFFLINE      3       /* device is in offline processing */
@@ -556,6 +562,7 @@ void dasd_free_block(struct dasd_block *);
 void dasd_enable_device(struct dasd_device *);
 void dasd_set_target_state(struct dasd_device *, int);
 void dasd_kick_device(struct dasd_device *);
+void dasd_restore_device(struct dasd_device *);
 
 void dasd_add_request_head(struct dasd_ccw_req *);
 void dasd_add_request_tail(struct dasd_ccw_req *);
@@ -578,6 +585,8 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
 int dasd_generic_set_offline (struct ccw_device *cdev);
 int dasd_generic_notify(struct ccw_device *, int);
 void dasd_generic_handle_state_change(struct dasd_device *);
+int dasd_generic_pm_freeze(struct ccw_device *);
+int dasd_generic_restore_device(struct ccw_device *);
 
 int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int);
 char *dasd_get_sense(struct irb *);
index b21caf177e370ef929f637c0f289b96a0db713db..016f9e9d259186e14351168b682b168fb25ab58b 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
-#include <asm/extmem.h>
-#include <asm/io.h>
 #include <linux/completion.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/extmem.h>
+#include <asm/io.h>
 
 #define DCSSBLK_NAME "dcssblk"
 #define DCSSBLK_MINORS_PER_DISK 1
@@ -939,12 +940,95 @@ dcssblk_check_params(void)
        }
 }
 
+/*
+ * Suspend / Resume
+ */
+static int dcssblk_freeze(struct device *dev)
+{
+       struct dcssblk_dev_info *dev_info;
+       int rc = 0;
+
+       list_for_each_entry(dev_info, &dcssblk_devices, lh) {
+               switch (dev_info->segment_type) {
+                       case SEG_TYPE_SR:
+                       case SEG_TYPE_ER:
+                       case SEG_TYPE_SC:
+                               if (!dev_info->is_shared)
+                                       rc = -EINVAL;
+                               break;
+                       default:
+                               rc = -EINVAL;
+                               break;
+               }
+               if (rc)
+                       break;
+       }
+       if (rc)
+               pr_err("Suspend failed because device %s is writeable.\n",
+                      dev_info->segment_name);
+       return rc;
+}
+
+static int dcssblk_restore(struct device *dev)
+{
+       struct dcssblk_dev_info *dev_info;
+       struct segment_info *entry;
+       unsigned long start, end;
+       int rc = 0;
+
+       list_for_each_entry(dev_info, &dcssblk_devices, lh) {
+               list_for_each_entry(entry, &dev_info->seg_list, lh) {
+                       segment_unload(entry->segment_name);
+                       rc = segment_load(entry->segment_name, SEGMENT_SHARED,
+                                         &start, &end);
+                       if (rc < 0) {
+// TODO in_use check ?
+                               segment_warning(rc, entry->segment_name);
+                               goto out_panic;
+                       }
+                       if (start != entry->start || end != entry->end) {
+                               pr_err("Mismatch of start / end address after "
+                                      "resuming device %s\n",
+                                      entry->segment_name);
+                               goto out_panic;
+                       }
+               }
+       }
+       return 0;
+out_panic:
+       panic("fatal dcssblk resume error\n");
+}
+
+static int dcssblk_thaw(struct device *dev)
+{
+       return 0;
+}
+
+static struct dev_pm_ops dcssblk_pm_ops = {
+       .freeze         = dcssblk_freeze,
+       .thaw           = dcssblk_thaw,
+       .restore        = dcssblk_restore,
+};
+
+static struct platform_driver dcssblk_pdrv = {
+       .driver = {
+               .name   = "dcssblk",
+               .owner  = THIS_MODULE,
+               .pm     = &dcssblk_pm_ops,
+       },
+};
+
+static struct platform_device *dcssblk_pdev;
+
+
 /*
  * The init/exit functions.
  */
 static void __exit
 dcssblk_exit(void)
 {
+       platform_device_unregister(dcssblk_pdev);
+       platform_driver_unregister(&dcssblk_pdrv);
        root_device_unregister(dcssblk_root_dev);
        unregister_blkdev(dcssblk_major, DCSSBLK_NAME);
 }
@@ -954,30 +1038,44 @@ dcssblk_init(void)
 {
        int rc;
 
-       dcssblk_root_dev = root_device_register("dcssblk");
-       if (IS_ERR(dcssblk_root_dev))
-               return PTR_ERR(dcssblk_root_dev);
-       rc = device_create_file(dcssblk_root_dev, &dev_attr_add);
-       if (rc) {
-               root_device_unregister(dcssblk_root_dev);
+       rc = platform_driver_register(&dcssblk_pdrv);
+       if (rc)
                return rc;
+
+       dcssblk_pdev = platform_device_register_simple("dcssblk", -1, NULL,
+                                                       0);
+       if (IS_ERR(dcssblk_pdev)) {
+               rc = PTR_ERR(dcssblk_pdev);
+               goto out_pdrv;
        }
-       rc = device_create_file(dcssblk_root_dev, &dev_attr_remove);
-       if (rc) {
-               root_device_unregister(dcssblk_root_dev);
-               return rc;
+
+       dcssblk_root_dev = root_device_register("dcssblk");
+       if (IS_ERR(dcssblk_root_dev)) {
+               rc = PTR_ERR(dcssblk_root_dev);
+               goto out_pdev;
        }
+       rc = device_create_file(dcssblk_root_dev, &dev_attr_add);
+       if (rc)
+               goto out_root;
+       rc = device_create_file(dcssblk_root_dev, &dev_attr_remove);
+       if (rc)
+               goto out_root;
        rc = register_blkdev(0, DCSSBLK_NAME);
-       if (rc < 0) {
-               root_device_unregister(dcssblk_root_dev);
-               return rc;
-       }
+       if (rc < 0)
+               goto out_root;
        dcssblk_major = rc;
        init_rwsem(&dcssblk_devices_sem);
 
        dcssblk_check_params();
-
        return 0;
+
+out_root:
+       root_device_unregister(dcssblk_root_dev);
+out_pdev:
+       platform_device_unregister(dcssblk_pdev);
+out_pdrv:
+       platform_driver_unregister(&dcssblk_pdrv);
+       return rc;
 }
 
 module_init(dcssblk_init);
index 0ae0c83ef87903e9121b76e14ae372dd2e40b8d1..2e9e1ecd6d82b2d1f03181d4237d04ff37dedab6 100644 (file)
 #include <linux/hdreg.h>  /* HDIO_GETGEO */
 #include <linux/sysdev.h>
 #include <linux/bio.h>
+#include <linux/suspend.h>
+#include <linux/platform_device.h>
 #include <asm/uaccess.h>
+#include <asm/checksum.h>
 
 #define XPRAM_NAME     "xpram"
 #define XPRAM_DEVS     1       /* one partition */
@@ -48,6 +51,7 @@
 typedef struct {
        unsigned int    size;           /* size of xpram segment in pages */
        unsigned int    offset;         /* start page of xpram segment */
+       unsigned int    csum;           /* partition checksum for suspend */
 } xpram_device_t;
 
 static xpram_device_t xpram_devices[XPRAM_MAX_DEVS];
@@ -138,7 +142,7 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index)
 /*
  * Check if xpram is available.
  */
-static int __init xpram_present(void)
+static int xpram_present(void)
 {
        unsigned long mem_page;
        int rc;
@@ -154,7 +158,7 @@ static int __init xpram_present(void)
 /*
  * Return index of the last available xpram page.
  */
-static unsigned long __init xpram_highest_page_index(void)
+static unsigned long xpram_highest_page_index(void)
 {
        unsigned int page_index, add_bit;
        unsigned long mem_page;
@@ -382,6 +386,106 @@ out:
        return rc;
 }
 
+/*
+ * Save checksums for all partitions.
+ */
+static int xpram_save_checksums(void)
+{
+       unsigned long mem_page;
+       int rc, i;
+
+       rc = 0;
+       mem_page = (unsigned long) __get_free_page(GFP_KERNEL);
+       if (!mem_page)
+               return -ENOMEM;
+       for (i = 0; i < xpram_devs; i++) {
+               rc = xpram_page_in(mem_page, xpram_devices[i].offset);
+               if (rc)
+                       goto fail;
+               xpram_devices[i].csum = csum_partial((const void *) mem_page,
+                                                    PAGE_SIZE, 0);
+       }
+fail:
+       free_page(mem_page);
+       return rc ? -ENXIO : 0;
+}
+
+/*
+ * Verify checksums for all partitions.
+ */
+static int xpram_validate_checksums(void)
+{
+       unsigned long mem_page;
+       unsigned int csum;
+       int rc, i;
+
+       rc = 0;
+       mem_page = (unsigned long) __get_free_page(GFP_KERNEL);
+       if (!mem_page)
+               return -ENOMEM;
+       for (i = 0; i < xpram_devs; i++) {
+               rc = xpram_page_in(mem_page, xpram_devices[i].offset);
+               if (rc)
+                       goto fail;
+               csum = csum_partial((const void *) mem_page, PAGE_SIZE, 0);
+               if (xpram_devices[i].csum != csum) {
+                       rc = -EINVAL;
+                       goto fail;
+               }
+       }
+fail:
+       free_page(mem_page);
+       return rc ? -ENXIO : 0;
+}
+
+/*
+ * Resume failed: Print error message and call panic.
+ */
+static void xpram_resume_error(const char *message)
+{
+       pr_err("Resume error: %s\n", message);
+       panic("xpram resume error\n");
+}
+
+/*
+ * Check if xpram setup changed between suspend and resume.
+ */
+static int xpram_restore(struct device *dev)
+{
+       if (!xpram_pages)
+               return 0;
+       if (xpram_present() != 0)
+               xpram_resume_error("xpram disappeared");
+       if (xpram_pages != xpram_highest_page_index() + 1)
+               xpram_resume_error("Size of xpram changed");
+       if (xpram_validate_checksums())
+               xpram_resume_error("Data of xpram changed");
+       return 0;
+}
+
+/*
+ * Save necessary state in suspend.
+ */
+static int xpram_freeze(struct device *dev)
+{
+       return xpram_save_checksums();
+}
+
+static struct dev_pm_ops xpram_pm_ops = {
+       .freeze         = xpram_freeze,
+       .restore        = xpram_restore,
+};
+
+static struct platform_driver xpram_pdrv = {
+       .driver = {
+               .name   = XPRAM_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &xpram_pm_ops,
+       },
+};
+
+static struct platform_device *xpram_pdev;
+
 /*
  * Finally, the init/exit functions.
  */
@@ -394,6 +498,8 @@ static void __exit xpram_exit(void)
                put_disk(xpram_disks[i]);
        }
        unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
+       platform_device_unregister(xpram_pdev);
+       platform_driver_unregister(&xpram_pdrv);
 }
 
 static int __init xpram_init(void)
@@ -411,7 +517,24 @@ static int __init xpram_init(void)
        rc = xpram_setup_sizes(xpram_pages);
        if (rc)
                return rc;
-       return xpram_setup_blkdev();
+       rc = platform_driver_register(&xpram_pdrv);
+       if (rc)
+               return rc;
+       xpram_pdev = platform_device_register_simple(XPRAM_NAME, -1, NULL, 0);
+       if (IS_ERR(xpram_pdev)) {
+               rc = PTR_ERR(xpram_pdev);
+               goto fail_platform_driver_unregister;
+       }
+       rc = xpram_setup_blkdev();
+       if (rc)
+               goto fail_platform_device_unregister;
+       return 0;
+
+fail_platform_device_unregister:
+       platform_device_unregister(xpram_pdev);
+fail_platform_driver_unregister:
+       platform_driver_unregister(&xpram_pdrv);
+       return rc;
 }
 
 module_init(xpram_init);
index 9ab06e0dad408abdc2b5f66b33b559ec8ec23000..04dc734805c61418353e2b68802a6621121c3317 100644 (file)
@@ -1,14 +1,12 @@
 /*
- *  drivers/s390/char/con3215.c
- *    3215 line mode terminal driver.
+ * 3215 line mode terminal driver.
  *
- *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Copyright IBM Corp. 1999, 2009
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
- *  Updated:
- *   Aug-2000: Added tab support
- *            Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu)
+ * Updated:
+ *  Aug-2000: Added tab support
+ *           Dan Morrison, IBM Corporation <dmorriso@cse.buffalo.edu>
  */
 
 #include <linux/module.h>
@@ -56,6 +54,7 @@
 #define RAW3215_CLOSING            32        /* set while in close process */
 #define RAW3215_TIMER_RUNS  64       /* set if the output delay timer is on */
 #define RAW3215_FLUSHING    128              /* set to flush buffer (no delay) */
+#define RAW3215_FROZEN     256       /* set if 3215 is frozen for suspend */
 
 #define TAB_STOP_SIZE      8         /* tab stop size */
 
@@ -111,8 +110,8 @@ static struct tty_driver *tty3215_driver;
 /*
  * Get a request structure from the free list
  */
-static inline struct raw3215_req *
-raw3215_alloc_req(void) {
+static inline struct raw3215_req *raw3215_alloc_req(void)
+{
        struct raw3215_req *req;
        unsigned long flags;
 
@@ -126,8 +125,8 @@ raw3215_alloc_req(void) {
 /*
  * Put a request structure back to the free list
  */
-static inline void
-raw3215_free_req(struct raw3215_req *req) {
+static inline void raw3215_free_req(struct raw3215_req *req)
+{
        unsigned long flags;
 
        if (req->type == RAW3215_FREE)
@@ -145,8 +144,7 @@ raw3215_free_req(struct raw3215_req *req) {
  * because a 3215 terminal won't accept a new read before the old one is
  * completed.
  */
-static void
-raw3215_mk_read_req(struct raw3215_info *raw)
+static void raw3215_mk_read_req(struct raw3215_info *raw)
 {
        struct raw3215_req *req;
        struct ccw1 *ccw;
@@ -174,8 +172,7 @@ raw3215_mk_read_req(struct raw3215_info *raw)
  * buffer to the 3215 device. If a queued write exists it is replaced by
  * the new, probably lengthened request.
  */
-static void
-raw3215_mk_write_req(struct raw3215_info *raw)
+static void raw3215_mk_write_req(struct raw3215_info *raw)
 {
        struct raw3215_req *req;
        struct ccw1 *ccw;
@@ -251,8 +248,7 @@ raw3215_mk_write_req(struct raw3215_info *raw)
 /*
  * Start a read or a write request
  */
-static void
-raw3215_start_io(struct raw3215_info *raw)
+static void raw3215_start_io(struct raw3215_info *raw)
 {
        struct raw3215_req *req;
        int res;
@@ -290,8 +286,7 @@ raw3215_start_io(struct raw3215_info *raw)
 /*
  * Function to start a delayed output after RAW3215_TIMEOUT seconds
  */
-static void
-raw3215_timeout(unsigned long __data)
+static void raw3215_timeout(unsigned long __data)
 {
        struct raw3215_info *raw = (struct raw3215_info *) __data;
        unsigned long flags;
@@ -300,8 +295,10 @@ raw3215_timeout(unsigned long __data)
        if (raw->flags & RAW3215_TIMER_RUNS) {
                del_timer(&raw->timer);
                raw->flags &= ~RAW3215_TIMER_RUNS;
-               raw3215_mk_write_req(raw);
-               raw3215_start_io(raw);
+               if (!(raw->flags & RAW3215_FROZEN)) {
+                       raw3215_mk_write_req(raw);
+                       raw3215_start_io(raw);
+               }
        }
        spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 }
@@ -312,10 +309,9 @@ raw3215_timeout(unsigned long __data)
  * amount of data is bigger than RAW3215_MIN_WRITE. If a write is not
  * done immediately a timer is started with a delay of RAW3215_TIMEOUT.
  */
-static inline void
-raw3215_try_io(struct raw3215_info *raw)
+static inline void raw3215_try_io(struct raw3215_info *raw)
 {
-       if (!(raw->flags & RAW3215_ACTIVE))
+       if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN))
                return;
        if (raw->queued_read != NULL)
                raw3215_start_io(raw);
@@ -359,8 +355,8 @@ static void raw3215_next_io(struct raw3215_info *raw)
 /*
  * Interrupt routine, called from common io layer
  */
-static void
-raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
+static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
+                       struct irb *irb)
 {
        struct raw3215_info *raw;
        struct raw3215_req *req;
@@ -368,7 +364,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        int cstat, dstat;
        int count;
 
-       raw = cdev->dev.driver_data;
+       raw = dev_get_drvdata(&cdev->dev);
        req = (struct raw3215_req *) intparm;
        cstat = irb->scsw.cmd.cstat;
        dstat = irb->scsw.cmd.dstat;
@@ -458,15 +454,41 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        return;
 }
 
+/*
+ * Drop the oldest line from the output buffer.
+ */
+static void raw3215_drop_line(struct raw3215_info *raw)
+{
+       int ix;
+       char ch;
+
+       BUG_ON(raw->written != 0);
+       ix = (raw->head - raw->count) & (RAW3215_BUFFER_SIZE - 1);
+       while (raw->count > 0) {
+               ch = raw->buffer[ix];
+               ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1);
+               raw->count--;
+               if (ch == 0x15)
+                       break;
+       }
+       raw->head = ix;
+}
+
 /*
  * Wait until length bytes are available int the output buffer.
  * Has to be called with the s390irq lock held. Can be called
  * disabled.
  */
-static void
-raw3215_make_room(struct raw3215_info *raw, unsigned int length)
+static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
 {
        while (RAW3215_BUFFER_SIZE - raw->count < length) {
+               /* While console is frozen for suspend we have no other
+                * choice but to drop message from the buffer to make
+                * room for even more messages. */
+               if (raw->flags & RAW3215_FROZEN) {
+                       raw3215_drop_line(raw);
+                       continue;
+               }
                /* there might be a request pending */
                raw->flags |= RAW3215_FLUSHING;
                raw3215_mk_write_req(raw);
@@ -488,8 +510,8 @@ raw3215_make_room(struct raw3215_info *raw, unsigned int length)
 /*
  * String write routine for 3215 devices
  */
-static void
-raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length)
+static void raw3215_write(struct raw3215_info *raw, const char *str,
+                         unsigned int length)
 {
        unsigned long flags;
        int c, count;
@@ -529,8 +551,7 @@ raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length)
 /*
  * Put character routine for 3215 devices
  */
-static void
-raw3215_putchar(struct raw3215_info *raw, unsigned char ch)
+static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch)
 {
        unsigned long flags;
        unsigned int length, i;
@@ -566,8 +587,7 @@ raw3215_putchar(struct raw3215_info *raw, unsigned char ch)
  * Flush routine, it simply sets the flush flag and tries to start
  * pending IO.
  */
-static void
-raw3215_flush_buffer(struct raw3215_info *raw)
+static void raw3215_flush_buffer(struct raw3215_info *raw)
 {
        unsigned long flags;
 
@@ -583,8 +603,7 @@ raw3215_flush_buffer(struct raw3215_info *raw)
 /*
  * Fire up a 3215 device.
  */
-static int
-raw3215_startup(struct raw3215_info *raw)
+static int raw3215_startup(struct raw3215_info *raw)
 {
        unsigned long flags;
 
@@ -602,8 +621,7 @@ raw3215_startup(struct raw3215_info *raw)
 /*
  * Shutdown a 3215 device.
  */
-static void
-raw3215_shutdown(struct raw3215_info *raw)
+static void raw3215_shutdown(struct raw3215_info *raw)
 {
        DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
@@ -628,14 +646,13 @@ raw3215_shutdown(struct raw3215_info *raw)
        spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 }
 
-static int
-raw3215_probe (struct ccw_device *cdev)
+static int raw3215_probe (struct ccw_device *cdev)
 {
        struct raw3215_info *raw;
        int line;
 
        /* Console is special. */
-       if (raw3215[0] && (cdev->dev.driver_data == raw3215[0]))
+       if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
                return 0;
        raw = kmalloc(sizeof(struct raw3215_info) +
                      RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
@@ -669,44 +686,41 @@ raw3215_probe (struct ccw_device *cdev)
        }
        init_waitqueue_head(&raw->empty_wait);
 
-       cdev->dev.driver_data = raw;
+       dev_set_drvdata(&cdev->dev, raw);
        cdev->handler = raw3215_irq;
 
        return 0;
 }
 
-static void
-raw3215_remove (struct ccw_device *cdev)
+static void raw3215_remove (struct ccw_device *cdev)
 {
        struct raw3215_info *raw;
 
        ccw_device_set_offline(cdev);
-       raw = cdev->dev.driver_data;
+       raw = dev_get_drvdata(&cdev->dev);
        if (raw) {
-               cdev->dev.driver_data = NULL;
+               dev_set_drvdata(&cdev->dev, NULL);
                kfree(raw->buffer);
                kfree(raw);
        }
 }
 
-static int
-raw3215_set_online (struct ccw_device *cdev)
+static int raw3215_set_online (struct ccw_device *cdev)
 {
        struct raw3215_info *raw;
 
-       raw = cdev->dev.driver_data;
+       raw = dev_get_drvdata(&cdev->dev);
        if (!raw)
                return -ENODEV;
 
        return raw3215_startup(raw);
 }
 
-static int
-raw3215_set_offline (struct ccw_device *cdev)
+static int raw3215_set_offline (struct ccw_device *cdev)
 {
        struct raw3215_info *raw;
 
-       raw = cdev->dev.driver_data;
+       raw = dev_get_drvdata(&cdev->dev);
        if (!raw)
                return -ENODEV;
 
@@ -715,6 +729,36 @@ raw3215_set_offline (struct ccw_device *cdev)
        return 0;
 }
 
+static int raw3215_pm_stop(struct ccw_device *cdev)
+{
+       struct raw3215_info *raw;
+       unsigned long flags;
+
+       /* Empty the output buffer, then prevent new I/O. */
+       raw = cdev->dev.driver_data;
+       spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
+       raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
+       raw->flags |= RAW3215_FROZEN;
+       spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
+       return 0;
+}
+
+static int raw3215_pm_start(struct ccw_device *cdev)
+{
+       struct raw3215_info *raw;
+       unsigned long flags;
+
+       /* Allow I/O again and flush output buffer. */
+       raw = cdev->dev.driver_data;
+       spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
+       raw->flags &= ~RAW3215_FROZEN;
+       raw->flags |= RAW3215_FLUSHING;
+       raw3215_try_io(raw);
+       raw->flags &= ~RAW3215_FLUSHING;
+       spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
+       return 0;
+}
+
 static struct ccw_device_id raw3215_id[] = {
        { CCW_DEVICE(0x3215, 0) },
        { /* end of list */ },
@@ -728,14 +772,17 @@ static struct ccw_driver raw3215_ccw_driver = {
        .remove         = &raw3215_remove,
        .set_online     = &raw3215_set_online,
        .set_offline    = &raw3215_set_offline,
+       .freeze         = &raw3215_pm_stop,
+       .thaw           = &raw3215_pm_start,
+       .restore        = &raw3215_pm_start,
 };
 
 #ifdef CONFIG_TN3215_CONSOLE
 /*
  * Write a string to the 3215 console
  */
-static void
-con3215_write(struct console *co, const char *str, unsigned int count)
+static void con3215_write(struct console *co, const char *str,
+                         unsigned int count)
 {
        struct raw3215_info *raw;
        int i;
@@ -768,13 +815,17 @@ static struct tty_driver *con3215_device(struct console *c, int *index)
  * panic() calls con3215_flush through a panic_notifier
  * before the system enters a disabled, endless loop.
  */
-static void
-con3215_flush(void)
+static void con3215_flush(void)
 {
        struct raw3215_info *raw;
        unsigned long flags;
 
        raw = raw3215[0];  /* console 3215 is the first one */
+       if (raw->flags & RAW3215_FROZEN)
+               /* The console is still frozen for suspend. */
+               if (ccw_device_force_console())
+                       /* Forcing didn't work, no panic message .. */
+                       return;
        spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
        raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
        spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -811,8 +862,7 @@ static struct console con3215 = {
  * 3215 console initialization code called from console_init().
  * NOTE: This is called before kmalloc is available.
  */
-static int __init
-con3215_init(void)
+static int __init con3215_init(void)
 {
        struct ccw_device *cdev;
        struct raw3215_info *raw;
@@ -848,7 +898,7 @@ con3215_init(void)
        raw->buffer = (char *) alloc_bootmem_low(RAW3215_BUFFER_SIZE);
        raw->inbuf = (char *) alloc_bootmem_low(RAW3215_INBUF_SIZE);
        raw->cdev = cdev;
-       cdev->dev.driver_data = raw;
+       dev_set_drvdata(&cdev->dev, raw);
        cdev->handler = raw3215_irq;
 
        raw->flags |= RAW3215_FIXED;
@@ -875,8 +925,7 @@ console_initcall(con3215_init);
  *
  * This routine is called whenever a 3215 tty is opened.
  */
-static int
-tty3215_open(struct tty_struct *tty, struct file * filp)
+static int tty3215_open(struct tty_struct *tty, struct file * filp)
 {
        struct raw3215_info *raw;
        int retval, line;
@@ -909,8 +958,7 @@ tty3215_open(struct tty_struct *tty, struct file * filp)
  * This routine is called when the 3215 tty is closed. We wait
  * for the remaining request to be completed. Then we clean up.
  */
-static void
-tty3215_close(struct tty_struct *tty, struct file * filp)
+static void tty3215_close(struct tty_struct *tty, struct file * filp)
 {
        struct raw3215_info *raw;
 
@@ -927,8 +975,7 @@ tty3215_close(struct tty_struct *tty, struct file * filp)
 /*
  * Returns the amount of free space in the output buffer.
  */
-static int
-tty3215_write_room(struct tty_struct *tty)
+static int tty3215_write_room(struct tty_struct *tty)
 {
        struct raw3215_info *raw;
 
@@ -944,9 +991,8 @@ tty3215_write_room(struct tty_struct *tty)
 /*
  * String write routine for 3215 ttys
  */
-static int
-tty3215_write(struct tty_struct * tty,
-             const unsigned char *buf, int count)
+static int tty3215_write(struct tty_struct * tty,
+                        const unsigned char *buf, int count)
 {
        struct raw3215_info *raw;
 
@@ -960,8 +1006,7 @@ tty3215_write(struct tty_struct * tty,
 /*
  * Put character routine for 3215 ttys
  */
-static int
-tty3215_put_char(struct tty_struct *tty, unsigned char ch)
+static int tty3215_put_char(struct tty_struct *tty, unsigned char ch)
 {
        struct raw3215_info *raw;
 
@@ -972,16 +1017,14 @@ tty3215_put_char(struct tty_struct *tty, unsigned char ch)
        return 1;
 }
 
-static void
-tty3215_flush_chars(struct tty_struct *tty)
+static void tty3215_flush_chars(struct tty_struct *tty)
 {
 }
 
 /*
  * Returns the number of characters in the output buffer
  */
-static int
-tty3215_chars_in_buffer(struct tty_struct *tty)
+static int tty3215_chars_in_buffer(struct tty_struct *tty)
 {
        struct raw3215_info *raw;
 
@@ -989,8 +1032,7 @@ tty3215_chars_in_buffer(struct tty_struct *tty)
        return raw->count;
 }
 
-static void
-tty3215_flush_buffer(struct tty_struct *tty)
+static void tty3215_flush_buffer(struct tty_struct *tty)
 {
        struct raw3215_info *raw;
 
@@ -1002,9 +1044,8 @@ tty3215_flush_buffer(struct tty_struct *tty)
 /*
  * Currently we don't have any io controls for 3215 ttys
  */
-static int
-tty3215_ioctl(struct tty_struct *tty, struct file * file,
-             unsigned int cmd, unsigned long arg)
+static int tty3215_ioctl(struct tty_struct *tty, struct file * file,
+                        unsigned int cmd, unsigned long arg)
 {
        if (tty->flags & (1 << TTY_IO_ERROR))
                return -EIO;
@@ -1019,8 +1060,7 @@ tty3215_ioctl(struct tty_struct *tty, struct file * file,
 /*
  * Disable reading from a 3215 tty
  */
-static void
-tty3215_throttle(struct tty_struct * tty)
+static void tty3215_throttle(struct tty_struct * tty)
 {
        struct raw3215_info *raw;
 
@@ -1031,8 +1071,7 @@ tty3215_throttle(struct tty_struct * tty)
 /*
  * Enable reading from a 3215 tty
  */
-static void
-tty3215_unthrottle(struct tty_struct * tty)
+static void tty3215_unthrottle(struct tty_struct * tty)
 {
        struct raw3215_info *raw;
        unsigned long flags;
@@ -1049,8 +1088,7 @@ tty3215_unthrottle(struct tty_struct * tty)
 /*
  * Disable writing to a 3215 tty
  */
-static void
-tty3215_stop(struct tty_struct *tty)
+static void tty3215_stop(struct tty_struct *tty)
 {
        struct raw3215_info *raw;
 
@@ -1061,8 +1099,7 @@ tty3215_stop(struct tty_struct *tty)
 /*
  * Enable writing to a 3215 tty
  */
-static void
-tty3215_start(struct tty_struct *tty)
+static void tty3215_start(struct tty_struct *tty)
 {
        struct raw3215_info *raw;
        unsigned long flags;
@@ -1096,8 +1133,7 @@ static const struct tty_operations tty3215_ops = {
  * 3215 tty registration code called from tty_init().
  * Most kernel services (incl. kmalloc) are available at this poimt.
  */
-static int __init
-tty3215_init(void)
+static int __init tty3215_init(void)
 {
        struct tty_driver *driver;
        int ret;
@@ -1142,8 +1178,7 @@ tty3215_init(void)
        return 0;
 }
 
-static void __exit
-tty3215_exit(void)
+static void __exit tty3215_exit(void)
 {
        tty_unregister_driver(tty3215_driver);
        put_tty_driver(tty3215_driver);
index ed5396dae58eef0edc2eb6f451419737c0b5dfd7..44d02e371c04b89f1d089ecc1b0e3f2881610919 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/con3270.c
- *    IBM/3270 Driver - console view.
+ * IBM/3270 Driver - console view.
  *
- *  Author(s):
- *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
- *    Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
- *     -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s):
+ *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
+ *   Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *     Copyright IBM Corp. 2003, 2009
  */
 
 #include <linux/bootmem.h>
@@ -530,6 +529,7 @@ con3270_flush(void)
        cp = condev;
        if (!cp->view.dev)
                return;
+       raw3270_pm_unfreeze(&cp->view);
        spin_lock_irqsave(&cp->view.lock, flags);
        con3270_wait_write(cp);
        cp->nr_up = 0;
index 40759c33477d1d38bca2400f034affbf24e3efcc..097d3846a828df50ccd45cc4a063a430695d5959 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/fs3270.c
- *    IBM/3270 Driver - fullscreen driver.
+ * IBM/3270 Driver - fullscreen driver.
  *
- *  Author(s):
- *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
- *    Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com>
- *     -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s):
+ *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
+ *   Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *     Copyright IBM Corp. 2003, 2009
  */
 
 #include <linux/bootmem.h>
@@ -399,6 +398,11 @@ fs3270_free_view(struct raw3270_view *view)
 static void
 fs3270_release(struct raw3270_view *view)
 {
+       struct fs3270 *fp;
+
+       fp = (struct fs3270 *) view;
+       if (fp->fs_pid)
+               kill_pid(fp->fs_pid, SIGHUP, 1);
 }
 
 /* View to a 3270 device. Can be console, tty or fullscreen. */
index 97e63cf469443ab594e231a288b856c0cc5d9562..75a8831eebbc78dbf7b5bdd60903c2d9e1226355 100644 (file)
@@ -1,10 +1,9 @@
 /*
- * drivers/s390/char/monreader.c
- *
  * Character device driver for reading z/VM *MONITOR service records.
  *
- *   Copyright IBM Corp. 2004, 2008
- *   Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
+ * Copyright IBM Corp. 2004, 2009
+ *
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #define KMSG_COMPONENT "monreader"
@@ -22,6 +21,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/poll.h>
+#include <linux/device.h>
 #include <net/iucv/iucv.h>
 #include <asm/uaccess.h>
 #include <asm/ebcdic.h>
@@ -78,6 +78,7 @@ static u8 user_data_sever[16] = {
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 };
 
+static struct device *monreader_device;
 
 /******************************************************************************
  *                             helper functions                               *
@@ -319,11 +320,12 @@ static int mon_open(struct inode *inode, struct file *filp)
                goto out_path;
        }
        filp->private_data = monpriv;
+       monreader_device->driver_data = monpriv;
        unlock_kernel();
        return nonseekable_open(inode, filp);
 
 out_path:
-       kfree(monpriv->path);
+       iucv_path_free(monpriv->path);
 out_priv:
        mon_free_mem(monpriv);
 out_use:
@@ -341,10 +343,13 @@ static int mon_close(struct inode *inode, struct file *filp)
        /*
         * Close IUCV connection and unregister
         */
-       rc = iucv_path_sever(monpriv->path, user_data_sever);
-       if (rc)
-               pr_warning("Disconnecting the z/VM *MONITOR system service "
-                          "failed with rc=%i\n", rc);
+       if (monpriv->path) {
+               rc = iucv_path_sever(monpriv->path, user_data_sever);
+               if (rc)
+                       pr_warning("Disconnecting the z/VM *MONITOR system "
+                                  "service failed with rc=%i\n", rc);
+               iucv_path_free(monpriv->path);
+       }
 
        atomic_set(&monpriv->iucv_severed, 0);
        atomic_set(&monpriv->iucv_connected, 0);
@@ -452,6 +457,94 @@ static struct miscdevice mon_dev = {
        .minor      = MISC_DYNAMIC_MINOR,
 };
 
+
+/******************************************************************************
+ *                             suspend / resume                              *
+ *****************************************************************************/
+static int monreader_freeze(struct device *dev)
+{
+       struct mon_private *monpriv = dev->driver_data;
+       int rc;
+
+       if (!monpriv)
+               return 0;
+       if (monpriv->path) {
+               rc = iucv_path_sever(monpriv->path, user_data_sever);
+               if (rc)
+                       pr_warning("Disconnecting the z/VM *MONITOR system "
+                                  "service failed with rc=%i\n", rc);
+               iucv_path_free(monpriv->path);
+       }
+       atomic_set(&monpriv->iucv_severed, 0);
+       atomic_set(&monpriv->iucv_connected, 0);
+       atomic_set(&monpriv->read_ready, 0);
+       atomic_set(&monpriv->msglim_count, 0);
+       monpriv->write_index  = 0;
+       monpriv->read_index   = 0;
+       monpriv->path = NULL;
+       return 0;
+}
+
+static int monreader_thaw(struct device *dev)
+{
+       struct mon_private *monpriv = dev->driver_data;
+       int rc;
+
+       if (!monpriv)
+               return 0;
+       rc = -ENOMEM;
+       monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL);
+       if (!monpriv->path)
+               goto out;
+       rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
+                              MON_SERVICE, NULL, user_data_connect, monpriv);
+       if (rc) {
+               pr_err("Connecting to the z/VM *MONITOR system service "
+                      "failed with rc=%i\n", rc);
+               goto out_path;
+       }
+       wait_event(mon_conn_wait_queue,
+                  atomic_read(&monpriv->iucv_connected) ||
+                  atomic_read(&monpriv->iucv_severed));
+       if (atomic_read(&monpriv->iucv_severed))
+               goto out_path;
+       return 0;
+out_path:
+       rc = -EIO;
+       iucv_path_free(monpriv->path);
+       monpriv->path = NULL;
+out:
+       atomic_set(&monpriv->iucv_severed, 1);
+       return rc;
+}
+
+static int monreader_restore(struct device *dev)
+{
+       int rc;
+
+       segment_unload(mon_dcss_name);
+       rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
+                         &mon_dcss_start, &mon_dcss_end);
+       if (rc < 0) {
+               segment_warning(rc, mon_dcss_name);
+               panic("fatal monreader resume error: no monitor dcss\n");
+       }
+       return monreader_thaw(dev);
+}
+
+static struct dev_pm_ops monreader_pm_ops = {
+       .freeze  = monreader_freeze,
+       .thaw    = monreader_thaw,
+       .restore = monreader_restore,
+};
+
+static struct device_driver monreader_driver = {
+       .name = "monreader",
+       .bus  = &iucv_bus,
+       .pm   = &monreader_pm_ops,
+};
+
+
 /******************************************************************************
  *                              module init/exit                              *
  *****************************************************************************/
@@ -475,16 +568,33 @@ static int __init mon_init(void)
                return rc;
        }
 
+       rc = driver_register(&monreader_driver);
+       if (rc)
+               goto out_iucv;
+       monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL);
+       if (!monreader_device)
+               goto out_driver;
+       dev_set_name(monreader_device, "monreader-dev");
+       monreader_device->bus = &iucv_bus;
+       monreader_device->parent = iucv_root;
+       monreader_device->driver = &monreader_driver;
+       monreader_device->release = (void (*)(struct device *))kfree;
+       rc = device_register(monreader_device);
+       if (rc) {
+               kfree(monreader_device);
+               goto out_driver;
+       }
+
        rc = segment_type(mon_dcss_name);
        if (rc < 0) {
                segment_warning(rc, mon_dcss_name);
-               goto out_iucv;
+               goto out_device;
        }
        if (rc != SEG_TYPE_SC) {
                pr_err("The specified *MONITOR DCSS %s does not have the "
                       "required type SC\n", mon_dcss_name);
                rc = -EINVAL;
-               goto out_iucv;
+               goto out_device;
        }
 
        rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
@@ -492,7 +602,7 @@ static int __init mon_init(void)
        if (rc < 0) {
                segment_warning(rc, mon_dcss_name);
                rc = -EINVAL;
-               goto out_iucv;
+               goto out_device;
        }
        dcss_mkname(mon_dcss_name, &user_data_connect[8]);
 
@@ -503,6 +613,10 @@ static int __init mon_init(void)
 
 out:
        segment_unload(mon_dcss_name);
+out_device:
+       device_unregister(monreader_device);
+out_driver:
+       driver_unregister(&monreader_driver);
 out_iucv:
        iucv_unregister(&monreader_iucv_handler, 1);
        return rc;
@@ -512,6 +626,8 @@ static void __exit mon_exit(void)
 {
        segment_unload(mon_dcss_name);
        WARN_ON(misc_deregister(&mon_dev) != 0);
+       device_unregister(monreader_device);
+       driver_unregister(&monreader_driver);
        iucv_unregister(&monreader_iucv_handler, 1);
        return;
 }
index c7d7483bab9ae010fef8e225d3138242aa9a00c7..66fb8eba93f43bfe16d03784dbc21eac52b78f78 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * drivers/s390/char/monwriter.c
- *
  * Character device driver for writing z/VM *MONITOR service records.
  *
- * Copyright (C) IBM Corp. 2006
+ * Copyright IBM Corp. 2006, 2009
  *
  * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com>
  */
@@ -22,6 +20,7 @@
 #include <linux/ctype.h>
 #include <linux/poll.h>
 #include <linux/mutex.h>
+#include <linux/platform_device.h>
 #include <asm/uaccess.h>
 #include <asm/ebcdic.h>
 #include <asm/io.h>
@@ -40,7 +39,10 @@ struct mon_buf {
        char *data;
 };
 
+static LIST_HEAD(mon_priv_list);
+
 struct mon_private {
+       struct list_head priv_list;
        struct list_head list;
        struct monwrite_hdr hdr;
        size_t hdr_to_read;
@@ -188,6 +190,7 @@ static int monwrite_open(struct inode *inode, struct file *filp)
        monpriv->hdr_to_read = sizeof(monpriv->hdr);
        mutex_init(&monpriv->thread_mutex);
        filp->private_data = monpriv;
+       list_add_tail(&monpriv->priv_list, &mon_priv_list);
        unlock_kernel();
        return nonseekable_open(inode, filp);
 }
@@ -206,6 +209,7 @@ static int monwrite_close(struct inode *inode, struct file *filp)
                kfree(entry->data);
                kfree(entry);
        }
+       list_del(&monpriv->priv_list);
        kfree(monpriv);
        return 0;
 }
@@ -280,21 +284,103 @@ static struct miscdevice mon_dev = {
        .minor  = MISC_DYNAMIC_MINOR,
 };
 
+/*
+ * suspend/resume
+ */
+
+static int monwriter_freeze(struct device *dev)
+{
+       struct mon_private *monpriv;
+       struct mon_buf *monbuf;
+
+       list_for_each_entry(monpriv, &mon_priv_list, priv_list) {
+               list_for_each_entry(monbuf, &monpriv->list, list) {
+                       if (monbuf->hdr.mon_function != MONWRITE_GEN_EVENT)
+                               monwrite_diag(&monbuf->hdr, monbuf->data,
+                                             APPLDATA_STOP_REC);
+               }
+       }
+       return 0;
+}
+
+static int monwriter_restore(struct device *dev)
+{
+       struct mon_private *monpriv;
+       struct mon_buf *monbuf;
+
+       list_for_each_entry(monpriv, &mon_priv_list, priv_list) {
+               list_for_each_entry(monbuf, &monpriv->list, list) {
+                       if (monbuf->hdr.mon_function == MONWRITE_START_INTERVAL)
+                               monwrite_diag(&monbuf->hdr, monbuf->data,
+                                             APPLDATA_START_INTERVAL_REC);
+                       if (monbuf->hdr.mon_function == MONWRITE_START_CONFIG)
+                               monwrite_diag(&monbuf->hdr, monbuf->data,
+                                             APPLDATA_START_CONFIG_REC);
+               }
+       }
+       return 0;
+}
+
+static int monwriter_thaw(struct device *dev)
+{
+       return monwriter_restore(dev);
+}
+
+static struct dev_pm_ops monwriter_pm_ops = {
+       .freeze         = monwriter_freeze,
+       .thaw           = monwriter_thaw,
+       .restore        = monwriter_restore,
+};
+
+static struct platform_driver monwriter_pdrv = {
+       .driver = {
+               .name   = "monwriter",
+               .owner  = THIS_MODULE,
+               .pm     = &monwriter_pm_ops,
+       },
+};
+
+static struct platform_device *monwriter_pdev;
+
 /*
  * module init/exit
  */
 
 static int __init mon_init(void)
 {
-       if (MACHINE_IS_VM)
-               return misc_register(&mon_dev);
-       else
+       int rc;
+
+       if (!MACHINE_IS_VM)
                return -ENODEV;
+
+       rc = platform_driver_register(&monwriter_pdrv);
+       if (rc)
+               return rc;
+
+       monwriter_pdev = platform_device_register_simple("monwriter", -1, NULL,
+                                                       0);
+       if (IS_ERR(monwriter_pdev)) {
+               rc = PTR_ERR(monwriter_pdev);
+               goto out_driver;
+       }
+
+       rc = misc_register(&mon_dev);
+       if (rc)
+               goto out_device;
+       return 0;
+
+out_device:
+       platform_device_unregister(monwriter_pdev);
+out_driver:
+       platform_driver_unregister(&monwriter_pdrv);
+       return rc;
 }
 
 static void __exit mon_exit(void)
 {
        WARN_ON(misc_deregister(&mon_dev) != 0);
+       platform_device_unregister(monwriter_pdev);
+       platform_driver_unregister(&monwriter_pdrv);
 }
 
 module_init(mon_init);
index 0b15cf107ec97d9162506d1acc23d678416692a3..acab7b2dfe8ab2a23174487dda6658a1c7d2ac5d 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/raw3270.c
- *    IBM/3270 Driver - core functions.
+ * IBM/3270 Driver - core functions.
  *
- *  Author(s):
- *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
- *    Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
- *     -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s):
+ *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
+ *   Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *     Copyright IBM Corp. 2003, 2009
  */
 
 #include <linux/bootmem.h>
@@ -61,6 +60,7 @@ struct raw3270 {
 #define RAW3270_FLAGS_ATTN     2       /* Device sent an ATTN interrupt */
 #define RAW3270_FLAGS_READY    4       /* Device is useable by views */
 #define RAW3270_FLAGS_CONSOLE  8       /* Device is the console. */
+#define RAW3270_FLAGS_FROZEN   16      /* set if 3270 is frozen for suspend */
 
 /* Semaphore to protect global data of raw3270 (devices, views, etc). */
 static DEFINE_MUTEX(raw3270_mutex);
@@ -306,7 +306,8 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
 
        spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
        rp = view->dev;
-       if (!rp || rp->view != view)
+       if (!rp || rp->view != view ||
+           test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
                rc = -EACCES;
        else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
                rc = -ENODEV;
@@ -323,7 +324,8 @@ raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
        int rc;
 
        rp = view->dev;
-       if (!rp || rp->view != view)
+       if (!rp || rp->view != view ||
+           test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
                rc = -EACCES;
        else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
                rc = -ENODEV;
@@ -355,7 +357,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        struct raw3270_request *rq;
        int rc;
 
-       rp = (struct raw3270 *) cdev->dev.driver_data;
+       rp = dev_get_drvdata(&cdev->dev);
        if (!rp)
                return;
        rq = (struct raw3270_request *) intparm;
@@ -764,7 +766,8 @@ raw3270_reset(struct raw3270_view *view)
        int rc;
 
        rp = view->dev;
-       if (!rp || rp->view != view)
+       if (!rp || rp->view != view ||
+           test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
                rc = -EACCES;
        else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
                rc = -ENODEV;
@@ -828,7 +831,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
        if (rp->minor == -1)
                return -EUSERS;
        rp->cdev = cdev;
-       cdev->dev.driver_data = rp;
+       dev_set_drvdata(&cdev->dev, rp);
        cdev->handler = raw3270_irq;
        return 0;
 }
@@ -922,6 +925,8 @@ raw3270_activate_view(struct raw3270_view *view)
                rc = 0;
        else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
                rc = -ENODEV;
+       else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
+               rc = -EACCES;
        else {
                oldview = NULL;
                if (rp->view) {
@@ -969,7 +974,8 @@ raw3270_deactivate_view(struct raw3270_view *view)
                list_del_init(&view->list);
                list_add_tail(&view->list, &rp->view_list);
                /* Try to activate another view. */
-               if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
+               if (test_bit(RAW3270_FLAGS_READY, &rp->flags) &&
+                   !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
                        list_for_each_entry(view, &rp->view_list, list) {
                                rp->view = view;
                                if (view->fn->activate(view) == 0)
@@ -1068,7 +1074,8 @@ raw3270_del_view(struct raw3270_view *view)
                rp->view = NULL;
        }
        list_del_init(&view->list);
-       if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
+       if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags) &&
+           !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
                /* Try to activate another view. */
                list_for_each_entry(nv, &rp->view_list, list) {
                        if (nv->fn->activate(nv) == 0) {
@@ -1105,7 +1112,7 @@ raw3270_delete_device(struct raw3270 *rp)
        /* Disconnect from ccw_device. */
        cdev = rp->cdev;
        rp->cdev = NULL;
-       cdev->dev.driver_data = NULL;
+       dev_set_drvdata(&cdev->dev, NULL);
        cdev->handler = NULL;
 
        /* Put ccw_device structure. */
@@ -1129,7 +1136,7 @@ static ssize_t
 raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%i\n",
-                       ((struct raw3270 *) dev->driver_data)->model);
+                       ((struct raw3270 *) dev_get_drvdata(dev))->model);
 }
 static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL);
 
@@ -1137,7 +1144,7 @@ static ssize_t
 raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%i\n",
-                       ((struct raw3270 *) dev->driver_data)->rows);
+                       ((struct raw3270 *) dev_get_drvdata(dev))->rows);
 }
 static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL);
 
@@ -1145,7 +1152,7 @@ static ssize_t
 raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%i\n",
-                       ((struct raw3270 *) dev->driver_data)->cols);
+                       ((struct raw3270 *) dev_get_drvdata(dev))->cols);
 }
 static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL);
 
@@ -1282,7 +1289,7 @@ raw3270_remove (struct ccw_device *cdev)
        struct raw3270_view *v;
        struct raw3270_notifier *np;
 
-       rp = cdev->dev.driver_data;
+       rp = dev_get_drvdata(&cdev->dev);
        /*
         * _remove is the opposite of _probe; it's probe that
         * should set up rp.  raw3270_remove gets entered for
@@ -1330,13 +1337,65 @@ raw3270_set_offline (struct ccw_device *cdev)
 {
        struct raw3270 *rp;
 
-       rp = cdev->dev.driver_data;
+       rp = dev_get_drvdata(&cdev->dev);
        if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags))
                return -EBUSY;
        raw3270_remove(cdev);
        return 0;
 }
 
+static int raw3270_pm_stop(struct ccw_device *cdev)
+{
+       struct raw3270 *rp;
+       struct raw3270_view *view;
+       unsigned long flags;
+
+       rp = cdev->dev.driver_data;
+       if (!rp)
+               return 0;
+       spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
+       if (rp->view)
+               rp->view->fn->deactivate(rp->view);
+       if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) {
+               /*
+                * Release tty and fullscreen for all non-console
+                * devices.
+                */
+               list_for_each_entry(view, &rp->view_list, list) {
+                       if (view->fn->release)
+                               view->fn->release(view);
+               }
+       }
+       set_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
+       spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
+       return 0;
+}
+
+static int raw3270_pm_start(struct ccw_device *cdev)
+{
+       struct raw3270 *rp;
+       unsigned long flags;
+
+       rp = cdev->dev.driver_data;
+       if (!rp)
+               return 0;
+       spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
+       clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
+       if (rp->view)
+               rp->view->fn->activate(rp->view);
+       spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
+       return 0;
+}
+
+void raw3270_pm_unfreeze(struct raw3270_view *view)
+{
+       struct raw3270 *rp;
+
+       rp = view->dev;
+       if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
+               ccw_device_force_console();
+}
+
 static struct ccw_device_id raw3270_id[] = {
        { CCW_DEVICE(0x3270, 0) },
        { CCW_DEVICE(0x3271, 0) },
@@ -1360,6 +1419,9 @@ static struct ccw_driver raw3270_ccw_driver = {
        .remove         = &raw3270_remove,
        .set_online     = &raw3270_set_online,
        .set_offline    = &raw3270_set_offline,
+       .freeze         = &raw3270_pm_stop,
+       .thaw           = &raw3270_pm_start,
+       .restore        = &raw3270_pm_start,
 };
 
 static int
index 90beaa80a78229d94368e3e170274158bf2a9f55..ed34eb2199cc3ea4165f095c5c2533866df34d26 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/raw3270.h
- *    IBM/3270 Driver
+ * IBM/3270 Driver
  *
- *  Author(s):
- *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
- *    Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
- *     -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s):
+ *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
+ *   Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *     Copyright IBM Corp. 2003, 2009
  */
 
 #include <asm/idals.h>
@@ -195,6 +194,7 @@ void raw3270_wait_cons_dev(struct raw3270 *);
 /* Notifier for device addition/removal */
 int raw3270_register_notifier(void (*notifier)(int, int));
 void raw3270_unregister_notifier(void (*notifier)(int, int));
+void raw3270_pm_unfreeze(struct raw3270_view *);
 
 /*
  * Little memory allocator for string objects. 
index 4377e93a43d7f97b7087ed5164967743337fc8a5..a983f50867881643f06ad0b2364fc5b9cbf2bb04 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/sclp.c
- *     core function to access sclp interface
+ * core function to access sclp interface
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Copyright IBM Corp. 1999, 2009
+ *
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *           Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #include <linux/module.h>
@@ -16,6 +15,9 @@
 #include <linux/reboot.h>
 #include <linux/jiffies.h>
 #include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
 #include <asm/types.h>
 #include <asm/s390_ext.h>
 
@@ -47,6 +49,16 @@ static struct sclp_req sclp_init_req;
 static char sclp_read_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
+/* Suspend request */
+static DECLARE_COMPLETION(sclp_request_queue_flushed);
+
+static void sclp_suspend_req_cb(struct sclp_req *req, void *data)
+{
+       complete(&sclp_request_queue_flushed);
+}
+
+static struct sclp_req sclp_suspend_req;
+
 /* Timer for request retries. */
 static struct timer_list sclp_request_timer;
 
@@ -84,6 +96,12 @@ static volatile enum sclp_mask_state_t {
        sclp_mask_state_initializing
 } sclp_mask_state = sclp_mask_state_idle;
 
+/* Internal state: is the driver suspended? */
+static enum sclp_suspend_state_t {
+       sclp_suspend_state_running,
+       sclp_suspend_state_suspended,
+} sclp_suspend_state = sclp_suspend_state_running;
+
 /* Maximum retry counts */
 #define SCLP_INIT_RETRY                3
 #define SCLP_MASK_RETRY                3
@@ -211,6 +229,8 @@ sclp_process_queue(void)
        del_timer(&sclp_request_timer);
        while (!list_empty(&sclp_req_queue)) {
                req = list_entry(sclp_req_queue.next, struct sclp_req, list);
+               if (!req->sccb)
+                       goto do_post;
                rc = __sclp_start_request(req);
                if (rc == 0)
                        break;
@@ -222,6 +242,7 @@ sclp_process_queue(void)
                                                 sclp_request_timeout, 0);
                        break;
                }
+do_post:
                /* Post-processing for aborted request */
                list_del(&req->list);
                if (req->callback) {
@@ -233,6 +254,19 @@ sclp_process_queue(void)
        spin_unlock_irqrestore(&sclp_lock, flags);
 }
 
+static int __sclp_can_add_request(struct sclp_req *req)
+{
+       if (req == &sclp_suspend_req || req == &sclp_init_req)
+               return 1;
+       if (sclp_suspend_state != sclp_suspend_state_running)
+               return 0;
+       if (sclp_init_state != sclp_init_state_initialized)
+               return 0;
+       if (sclp_activation_state != sclp_activation_state_active)
+               return 0;
+       return 1;
+}
+
 /* Queue a new request. Return zero on success, non-zero otherwise. */
 int
 sclp_add_request(struct sclp_req *req)
@@ -241,9 +275,7 @@ sclp_add_request(struct sclp_req *req)
        int rc;
 
        spin_lock_irqsave(&sclp_lock, flags);
-       if ((sclp_init_state != sclp_init_state_initialized ||
-            sclp_activation_state != sclp_activation_state_active) &&
-           req != &sclp_init_req) {
+       if (!__sclp_can_add_request(req)) {
                spin_unlock_irqrestore(&sclp_lock, flags);
                return -EIO;
        }
@@ -254,10 +286,16 @@ sclp_add_request(struct sclp_req *req)
        /* Start if request is first in list */
        if (sclp_running_state == sclp_running_state_idle &&
            req->list.prev == &sclp_req_queue) {
+               if (!req->sccb) {
+                       list_del(&req->list);
+                       rc = -ENODATA;
+                       goto out;
+               }
                rc = __sclp_start_request(req);
                if (rc)
                        list_del(&req->list);
        }
+out:
        spin_unlock_irqrestore(&sclp_lock, flags);
        return rc;
 }
@@ -560,6 +598,7 @@ sclp_register(struct sclp_register *reg)
        /* Trigger initial state change callback */
        reg->sclp_receive_mask = 0;
        reg->sclp_send_mask = 0;
+       reg->pm_event_posted = 0;
        list_add(&reg->list, &sclp_reg_list);
        spin_unlock_irqrestore(&sclp_lock, flags);
        rc = sclp_init_mask(1);
@@ -880,20 +919,134 @@ static struct notifier_block sclp_reboot_notifier = {
        .notifier_call = sclp_reboot_event
 };
 
+/*
+ * Suspend/resume SCLP notifier implementation
+ */
+
+static void sclp_pm_event(enum sclp_pm_event sclp_pm_event, int rollback)
+{
+       struct sclp_register *reg;
+       unsigned long flags;
+
+       if (!rollback) {
+               spin_lock_irqsave(&sclp_lock, flags);
+               list_for_each_entry(reg, &sclp_reg_list, list)
+                       reg->pm_event_posted = 0;
+               spin_unlock_irqrestore(&sclp_lock, flags);
+       }
+       do {
+               spin_lock_irqsave(&sclp_lock, flags);
+               list_for_each_entry(reg, &sclp_reg_list, list) {
+                       if (rollback && reg->pm_event_posted)
+                               goto found;
+                       if (!rollback && !reg->pm_event_posted)
+                               goto found;
+               }
+               spin_unlock_irqrestore(&sclp_lock, flags);
+               return;
+found:
+               spin_unlock_irqrestore(&sclp_lock, flags);
+               if (reg->pm_event_fn)
+                       reg->pm_event_fn(reg, sclp_pm_event);
+               reg->pm_event_posted = rollback ? 0 : 1;
+       } while (1);
+}
+
+/*
+ * Susend/resume callbacks for platform device
+ */
+
+static int sclp_freeze(struct device *dev)
+{
+       unsigned long flags;
+       int rc;
+
+       sclp_pm_event(SCLP_PM_EVENT_FREEZE, 0);
+
+       spin_lock_irqsave(&sclp_lock, flags);
+       sclp_suspend_state = sclp_suspend_state_suspended;
+       spin_unlock_irqrestore(&sclp_lock, flags);
+
+       /* Init supend data */
+       memset(&sclp_suspend_req, 0, sizeof(sclp_suspend_req));
+       sclp_suspend_req.callback = sclp_suspend_req_cb;
+       sclp_suspend_req.status = SCLP_REQ_FILLED;
+       init_completion(&sclp_request_queue_flushed);
+
+       rc = sclp_add_request(&sclp_suspend_req);
+       if (rc == 0)
+               wait_for_completion(&sclp_request_queue_flushed);
+       else if (rc != -ENODATA)
+               goto fail_thaw;
+
+       rc = sclp_deactivate();
+       if (rc)
+               goto fail_thaw;
+       return 0;
+
+fail_thaw:
+       spin_lock_irqsave(&sclp_lock, flags);
+       sclp_suspend_state = sclp_suspend_state_running;
+       spin_unlock_irqrestore(&sclp_lock, flags);
+       sclp_pm_event(SCLP_PM_EVENT_THAW, 1);
+       return rc;
+}
+
+static int sclp_undo_suspend(enum sclp_pm_event event)
+{
+       unsigned long flags;
+       int rc;
+
+       rc = sclp_reactivate();
+       if (rc)
+               return rc;
+
+       spin_lock_irqsave(&sclp_lock, flags);
+       sclp_suspend_state = sclp_suspend_state_running;
+       spin_unlock_irqrestore(&sclp_lock, flags);
+
+       sclp_pm_event(event, 0);
+       return 0;
+}
+
+static int sclp_thaw(struct device *dev)
+{
+       return sclp_undo_suspend(SCLP_PM_EVENT_THAW);
+}
+
+static int sclp_restore(struct device *dev)
+{
+       return sclp_undo_suspend(SCLP_PM_EVENT_RESTORE);
+}
+
+static struct dev_pm_ops sclp_pm_ops = {
+       .freeze         = sclp_freeze,
+       .thaw           = sclp_thaw,
+       .restore        = sclp_restore,
+};
+
+static struct platform_driver sclp_pdrv = {
+       .driver = {
+               .name   = "sclp",
+               .owner  = THIS_MODULE,
+               .pm     = &sclp_pm_ops,
+       },
+};
+
+static struct platform_device *sclp_pdev;
+
 /* Initialize SCLP driver. Return zero if driver is operational, non-zero
  * otherwise. */
 static int
 sclp_init(void)
 {
        unsigned long flags;
-       int rc;
+       int rc = 0;
 
        spin_lock_irqsave(&sclp_lock, flags);
        /* Check for previous or running initialization */
-       if (sclp_init_state != sclp_init_state_uninitialized) {
-               spin_unlock_irqrestore(&sclp_lock, flags);
-               return 0;
-       }
+       if (sclp_init_state != sclp_init_state_uninitialized)
+               goto fail_unlock;
        sclp_init_state = sclp_init_state_initializing;
        /* Set up variables */
        INIT_LIST_HEAD(&sclp_req_queue);
@@ -904,27 +1057,17 @@ sclp_init(void)
        spin_unlock_irqrestore(&sclp_lock, flags);
        rc = sclp_check_interface();
        spin_lock_irqsave(&sclp_lock, flags);
-       if (rc) {
-               sclp_init_state = sclp_init_state_uninitialized;
-               spin_unlock_irqrestore(&sclp_lock, flags);
-               return rc;
-       }
+       if (rc)
+               goto fail_init_state_uninitialized;
        /* Register reboot handler */
        rc = register_reboot_notifier(&sclp_reboot_notifier);
-       if (rc) {
-               sclp_init_state = sclp_init_state_uninitialized;
-               spin_unlock_irqrestore(&sclp_lock, flags);
-               return rc;
-       }
+       if (rc)
+               goto fail_init_state_uninitialized;
        /* Register interrupt handler */
        rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler,
                                               &ext_int_info_hwc);
-       if (rc) {
-               unregister_reboot_notifier(&sclp_reboot_notifier);
-               sclp_init_state = sclp_init_state_uninitialized;
-               spin_unlock_irqrestore(&sclp_lock, flags);
-               return rc;
-       }
+       if (rc)
+               goto fail_unregister_reboot_notifier;
        sclp_init_state = sclp_init_state_initialized;
        spin_unlock_irqrestore(&sclp_lock, flags);
        /* Enable service-signal external interruption - needs to happen with
@@ -932,11 +1075,56 @@ sclp_init(void)
        ctl_set_bit(0, 9);
        sclp_init_mask(1);
        return 0;
+
+fail_unregister_reboot_notifier:
+       unregister_reboot_notifier(&sclp_reboot_notifier);
+fail_init_state_uninitialized:
+       sclp_init_state = sclp_init_state_uninitialized;
+fail_unlock:
+       spin_unlock_irqrestore(&sclp_lock, flags);
+       return rc;
 }
 
+/*
+ * SCLP panic notifier: If we are suspended, we thaw SCLP in order to be able
+ * to print the panic message.
+ */
+static int sclp_panic_notify(struct notifier_block *self,
+                            unsigned long event, void *data)
+{
+       if (sclp_suspend_state == sclp_suspend_state_suspended)
+               sclp_undo_suspend(SCLP_PM_EVENT_THAW);
+       return NOTIFY_OK;
+}
+
+static struct notifier_block sclp_on_panic_nb = {
+       .notifier_call = sclp_panic_notify,
+       .priority = SCLP_PANIC_PRIO,
+};
+
 static __init int sclp_initcall(void)
 {
+       int rc;
+
+       rc = platform_driver_register(&sclp_pdrv);
+       if (rc)
+               return rc;
+       sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0);
+       rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0;
+       if (rc)
+               goto fail_platform_driver_unregister;
+       rc = atomic_notifier_chain_register(&panic_notifier_list,
+                                           &sclp_on_panic_nb);
+       if (rc)
+               goto fail_platform_device_unregister;
+
        return sclp_init();
+
+fail_platform_device_unregister:
+       platform_device_unregister(sclp_pdev);
+fail_platform_driver_unregister:
+       platform_driver_unregister(&sclp_pdrv);
+       return rc;
 }
 
 arch_initcall(sclp_initcall);
index bac80e856f97978d1c9354e7df7830fc2fa76691..60e7cb07095b6fa2c6e0b2908a6886c2cfc5c1c6 100644 (file)
@@ -1,10 +1,8 @@
 /*
- *  drivers/s390/char/sclp.h
+ * Copyright IBM Corp. 1999, 2009
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *           Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #ifndef __SCLP_H__
@@ -17,7 +15,7 @@
 
 /* maximum number of pages concerning our own memory management */
 #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3)
-#define MAX_CONSOLE_PAGES      4
+#define MAX_CONSOLE_PAGES      6
 
 #define EVTYP_OPCMD            0x01
 #define EVTYP_MSG              0x02
@@ -68,6 +66,15 @@ typedef unsigned int sclp_cmdw_t;
 
 #define GDS_KEY_SELFDEFTEXTMSG 0x31
 
+enum sclp_pm_event {
+       SCLP_PM_EVENT_FREEZE,
+       SCLP_PM_EVENT_THAW,
+       SCLP_PM_EVENT_RESTORE,
+};
+
+#define SCLP_PANIC_PRIO                1
+#define SCLP_PANIC_PRIO_CLIENT 0
+
 typedef u32 sccb_mask_t;       /* ATTENTION: assumes 32bit mask !!! */
 
 struct sccb_header {
@@ -134,6 +141,10 @@ struct sclp_register {
        void (*state_change_fn)(struct sclp_register *);
        /* called for events in cp_receive_mask/sclp_receive_mask */
        void (*receiver_fn)(struct evbuf_header *);
+       /* called for power management events */
+       void (*pm_event_fn)(struct sclp_register *, enum sclp_pm_event);
+       /* pm event posted flag */
+       int pm_event_posted;
 };
 
 /* externals from sclp.c */
index 77ab6e34a100b758bc3047888e78f1962a90146d..5cc11c636d38ad8e4fb640ef38afdbbb635095ee 100644 (file)
@@ -1,9 +1,8 @@
 /*
- *  drivers/s390/char/sclp_cmd.c
+ * Copyright IBM Corp. 2007, 2009
  *
- *    Copyright IBM Corp. 2007
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
- *              Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *           Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  */
 
 #define KMSG_COMPONENT "sclp_cmd"
 #include <linux/completion.h>
 #include <linux/init.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/mmzone.h>
 #include <linux/memory.h>
+#include <linux/platform_device.h>
 #include <asm/chpid.h>
 #include <asm/sclp.h>
 #include <asm/setup.h>
@@ -292,6 +293,7 @@ static DEFINE_MUTEX(sclp_mem_mutex);
 static LIST_HEAD(sclp_mem_list);
 static u8 sclp_max_storage_id;
 static unsigned long sclp_storage_ids[256 / BITS_PER_LONG];
+static int sclp_mem_state_changed;
 
 struct memory_increment {
        struct list_head list;
@@ -450,6 +452,8 @@ static int sclp_mem_notifier(struct notifier_block *nb,
                rc = -EINVAL;
                break;
        }
+       if (!rc)
+               sclp_mem_state_changed = 1;
        mutex_unlock(&sclp_mem_mutex);
        return rc ? NOTIFY_BAD : NOTIFY_OK;
 }
@@ -525,6 +529,14 @@ static void __init insert_increment(u16 rn, int standby, int assigned)
        list_add(&new_incr->list, prev);
 }
 
+static int sclp_mem_freeze(struct device *dev)
+{
+       if (!sclp_mem_state_changed)
+               return 0;
+       pr_err("Memory hotplug state changed, suspend refused.\n");
+       return -EPERM;
+}
+
 struct read_storage_sccb {
        struct sccb_header header;
        u16 max_id;
@@ -534,8 +546,20 @@ struct read_storage_sccb {
        u32 entries[0];
 } __packed;
 
+static struct dev_pm_ops sclp_mem_pm_ops = {
+       .freeze         = sclp_mem_freeze,
+};
+
+static struct platform_driver sclp_mem_pdrv = {
+       .driver = {
+               .name   = "sclp_mem",
+               .pm     = &sclp_mem_pm_ops,
+       },
+};
+
 static int __init sclp_detect_standby_memory(void)
 {
+       struct platform_device *sclp_pdev;
        struct read_storage_sccb *sccb;
        int i, id, assigned, rc;
 
@@ -588,7 +612,17 @@ static int __init sclp_detect_standby_memory(void)
        rc = register_memory_notifier(&sclp_mem_nb);
        if (rc)
                goto out;
+       rc = platform_driver_register(&sclp_mem_pdrv);
+       if (rc)
+               goto out;
+       sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0);
+       rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0;
+       if (rc)
+               goto out_driver;
        sclp_add_standby_memory();
+       goto out;
+out_driver:
+       platform_driver_unregister(&sclp_mem_pdrv);
 out:
        free_page((unsigned long) sccb);
        return rc;
index 9a25c4bd14210ded21fffa666b53f653febced08..336811a77672c751f9a8ab3f74281dd52f068f38 100644 (file)
@@ -1,11 +1,9 @@
 /*
- *  drivers/s390/char/sclp_con.c
- *    SCLP line mode console driver
+ * SCLP line mode console driver
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Copyright IBM Corp. 1999, 2009
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *           Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #include <linux/kmod.h>
@@ -32,13 +30,14 @@ static spinlock_t sclp_con_lock;
 static struct list_head sclp_con_pages;
 /* List of full struct sclp_buffer structures ready for output */
 static struct list_head sclp_con_outqueue;
-/* Counter how many buffers are emitted (max 1) and how many */
-/* are on the output queue. */
-static int sclp_con_buffer_count;
 /* Pointer to current console buffer */
 static struct sclp_buffer *sclp_conbuf;
 /* Timer for delayed output of console messages */
 static struct timer_list sclp_con_timer;
+/* Suspend mode flag */
+static int sclp_con_suspended;
+/* Flag that output queue is currently running */
+static int sclp_con_queue_running;
 
 /* Output format for console messages */
 static unsigned short sclp_con_columns;
@@ -53,42 +52,71 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
        do {
                page = sclp_unmake_buffer(buffer);
                spin_lock_irqsave(&sclp_con_lock, flags);
+
                /* Remove buffer from outqueue */
                list_del(&buffer->list);
-               sclp_con_buffer_count--;
                list_add_tail((struct list_head *) page, &sclp_con_pages);
+
                /* Check if there is a pending buffer on the out queue. */
                buffer = NULL;
                if (!list_empty(&sclp_con_outqueue))
-                       buffer = list_entry(sclp_con_outqueue.next,
-                                           struct sclp_buffer, list);
+                       buffer = list_first_entry(&sclp_con_outqueue,
+                                                 struct sclp_buffer, list);
+               if (!buffer || sclp_con_suspended) {
+                       sclp_con_queue_running = 0;
+                       spin_unlock_irqrestore(&sclp_con_lock, flags);
+                       break;
+               }
                spin_unlock_irqrestore(&sclp_con_lock, flags);
-       } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
+       } while (sclp_emit_buffer(buffer, sclp_conbuf_callback));
 }
 
-static void
-sclp_conbuf_emit(void)
+/*
+ * Finalize and emit first pending buffer.
+ */
+static void sclp_conbuf_emit(void)
 {
        struct sclp_buffer* buffer;
        unsigned long flags;
-       int count;
        int rc;
 
        spin_lock_irqsave(&sclp_con_lock, flags);
-       buffer = sclp_conbuf;
+       if (sclp_conbuf)
+               list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue);
        sclp_conbuf = NULL;
-       if (buffer == NULL) {
-               spin_unlock_irqrestore(&sclp_con_lock, flags);
-               return;
-       }
-       list_add_tail(&buffer->list, &sclp_con_outqueue);
-       count = sclp_con_buffer_count++;
+       if (sclp_con_queue_running || sclp_con_suspended)
+               goto out_unlock;
+       if (list_empty(&sclp_con_outqueue))
+               goto out_unlock;
+       buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer,
+                                 list);
+       sclp_con_queue_running = 1;
        spin_unlock_irqrestore(&sclp_con_lock, flags);
-       if (count)
-               return;
+
        rc = sclp_emit_buffer(buffer, sclp_conbuf_callback);
        if (rc)
                sclp_conbuf_callback(buffer, rc);
+       return;
+out_unlock:
+       spin_unlock_irqrestore(&sclp_con_lock, flags);
+}
+
+/*
+ * Wait until out queue is empty
+ */
+static void sclp_console_sync_queue(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sclp_con_lock, flags);
+       if (timer_pending(&sclp_con_timer))
+               del_timer_sync(&sclp_con_timer);
+       while (sclp_con_queue_running) {
+               spin_unlock_irqrestore(&sclp_con_lock, flags);
+               sclp_sync_wait();
+               spin_lock_irqsave(&sclp_con_lock, flags);
+       }
+       spin_unlock_irqrestore(&sclp_con_lock, flags);
 }
 
 /*
@@ -123,6 +151,8 @@ sclp_console_write(struct console *console, const char *message,
                /* make sure we have a console output buffer */
                if (sclp_conbuf == NULL) {
                        while (list_empty(&sclp_con_pages)) {
+                               if (sclp_con_suspended)
+                                       goto out;
                                spin_unlock_irqrestore(&sclp_con_lock, flags);
                                sclp_sync_wait();
                                spin_lock_irqsave(&sclp_con_lock, flags);
@@ -157,6 +187,7 @@ sclp_console_write(struct console *console, const char *message,
                sclp_con_timer.expires = jiffies + HZ/10;
                add_timer(&sclp_con_timer);
        }
+out:
        spin_unlock_irqrestore(&sclp_con_lock, flags);
 }
 
@@ -168,30 +199,43 @@ sclp_console_device(struct console *c, int *index)
 }
 
 /*
- * This routine is called from panic when the kernel
- * is going to give up. We have to make sure that all buffers
- * will be flushed to the SCLP.
+ * Make sure that all buffers will be flushed to the SCLP.
  */
 static void
 sclp_console_flush(void)
+{
+       sclp_conbuf_emit();
+       sclp_console_sync_queue();
+}
+
+/*
+ * Resume console: If there are cached messages, emit them.
+ */
+static void sclp_console_resume(void)
 {
        unsigned long flags;
 
+       spin_lock_irqsave(&sclp_con_lock, flags);
+       sclp_con_suspended = 0;
+       spin_unlock_irqrestore(&sclp_con_lock, flags);
        sclp_conbuf_emit();
+}
+
+/*
+ * Suspend console: Set suspend flag and flush console
+ */
+static void sclp_console_suspend(void)
+{
+       unsigned long flags;
+
        spin_lock_irqsave(&sclp_con_lock, flags);
-       if (timer_pending(&sclp_con_timer))
-               del_timer(&sclp_con_timer);
-       while (sclp_con_buffer_count > 0) {
-               spin_unlock_irqrestore(&sclp_con_lock, flags);
-               sclp_sync_wait();
-               spin_lock_irqsave(&sclp_con_lock, flags);
-       }
+       sclp_con_suspended = 1;
        spin_unlock_irqrestore(&sclp_con_lock, flags);
+       sclp_console_flush();
 }
 
-static int
-sclp_console_notify(struct notifier_block *self,
-                         unsigned long event, void *data)
+static int sclp_console_notify(struct notifier_block *self,
+                              unsigned long event, void *data)
 {
        sclp_console_flush();
        return NOTIFY_OK;
@@ -199,7 +243,7 @@ sclp_console_notify(struct notifier_block *self,
 
 static struct notifier_block on_panic_nb = {
        .notifier_call = sclp_console_notify,
-       .priority = 1,
+       .priority = SCLP_PANIC_PRIO_CLIENT,
 };
 
 static struct notifier_block on_reboot_nb = {
@@ -220,6 +264,22 @@ static struct console sclp_console =
        .index = 0 /* ttyS0 */
 };
 
+/*
+ * This function is called for SCLP suspend and resume events.
+ */
+void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event)
+{
+       switch (sclp_pm_event) {
+       case SCLP_PM_EVENT_FREEZE:
+               sclp_console_suspend();
+               break;
+       case SCLP_PM_EVENT_RESTORE:
+       case SCLP_PM_EVENT_THAW:
+               sclp_console_resume();
+               break;
+       }
+}
+
 /*
  * called by console_init() in drivers/char/tty_io.c at boot-time.
  */
@@ -243,7 +303,6 @@ sclp_console_init(void)
        }
        INIT_LIST_HEAD(&sclp_con_outqueue);
        spin_lock_init(&sclp_con_lock);
-       sclp_con_buffer_count = 0;
        sclp_conbuf = NULL;
        init_timer(&sclp_con_timer);
 
index 710af42603f80f7866b2d3be13e7ebaff14ce166..4be63be7344564a113e29a0051c79ac430b372a6 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/sclp_rw.c
- *     driver: reading from and writing to system console on S/390 via SCLP
+ * driver: reading from and writing to system console on S/390 via SCLP
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Copyright IBM Corp. 1999, 2009
+ *
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *           Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #include <linux/kmod.h>
  */
 #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
 
+static void sclp_rw_pm_event(struct sclp_register *reg,
+                            enum sclp_pm_event sclp_pm_event)
+{
+       sclp_console_pm_event(sclp_pm_event);
+}
+
 /* Event type structure for write message and write priority message */
 static struct sclp_register sclp_rw_event = {
-       .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK
+       .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK,
+       .pm_event_fn = sclp_rw_pm_event,
 };
 
 /*
index 6aa7a6948bc91a29a6047b7d6f808a064cd0fcc4..85f491ea929c0da0df28ee54676949354f51b7b0 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/sclp_rw.h
- *    interface to the SCLP-read/write driver
+ * interface to the SCLP-read/write driver
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Copyright IBM Corporation 1999, 2009
+ *
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *           Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #ifndef __SCLP_RW_H__
@@ -93,4 +92,5 @@ void sclp_set_columns(struct sclp_buffer *, unsigned short);
 void sclp_set_htab(struct sclp_buffer *, unsigned short);
 int sclp_chars_in_buffer(struct sclp_buffer *);
 
+void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event);
 #endif /* __SCLP_RW_H__ */
index a839aa531d7c0f011cbe6e135ce3bac897333d7e..5518e24946aa7735c618699e6bf4e2762fcb3fa8 100644 (file)
@@ -1,10 +1,9 @@
 /*
- *  drivers/s390/char/sclp_vt220.c
- *    SCLP VT220 terminal driver.
+ * SCLP VT220 terminal driver.
  *
- *  S390 version
- *    Copyright IBM Corp. 2003,2008
- *    Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+ * Copyright IBM Corp. 2003, 2009
+ *
+ * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
  */
 
 #include <linux/module.h>
@@ -69,8 +68,11 @@ static struct list_head sclp_vt220_empty;
 /* List of pending requests */
 static struct list_head sclp_vt220_outqueue;
 
-/* Number of requests in outqueue */
-static int sclp_vt220_outqueue_count;
+/* Suspend mode flag */
+static int sclp_vt220_suspended;
+
+/* Flag that output queue is currently running */
+static int sclp_vt220_queue_running;
 
 /* Timer used for delaying write requests to merge subsequent messages into
  * a single buffer */
@@ -92,6 +94,8 @@ static int __initdata sclp_vt220_init_count;
 static int sclp_vt220_flush_later;
 
 static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf);
+static void sclp_vt220_pm_event_fn(struct sclp_register *reg,
+                                  enum sclp_pm_event sclp_pm_event);
 static int __sclp_vt220_emit(struct sclp_vt220_request *request);
 static void sclp_vt220_emit_current(void);
 
@@ -100,7 +104,8 @@ static struct sclp_register sclp_vt220_register = {
        .send_mask              = EVTYP_VT220MSG_MASK,
        .receive_mask           = EVTYP_VT220MSG_MASK,
        .state_change_fn        = NULL,
-       .receiver_fn            = sclp_vt220_receiver_fn
+       .receiver_fn            = sclp_vt220_receiver_fn,
+       .pm_event_fn            = sclp_vt220_pm_event_fn,
 };
 
 
@@ -120,15 +125,19 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
                spin_lock_irqsave(&sclp_vt220_lock, flags);
                /* Move request from outqueue to empty queue */
                list_del(&request->list);
-               sclp_vt220_outqueue_count--;
                list_add_tail((struct list_head *) page, &sclp_vt220_empty);
                /* Check if there is a pending buffer on the out queue. */
                request = NULL;
                if (!list_empty(&sclp_vt220_outqueue))
                        request = list_entry(sclp_vt220_outqueue.next,
                                             struct sclp_vt220_request, list);
+               if (!request || sclp_vt220_suspended) {
+                       sclp_vt220_queue_running = 0;
+                       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+                       break;
+               }
                spin_unlock_irqrestore(&sclp_vt220_lock, flags);
-       } while (request && __sclp_vt220_emit(request));
+       } while (__sclp_vt220_emit(request));
        if (request == NULL && sclp_vt220_flush_later)
                sclp_vt220_emit_current();
        /* Check if the tty needs a wake up call */
@@ -212,26 +221,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request)
 }
 
 /*
- * Queue and emit given request.
- */
-static void
-sclp_vt220_emit(struct sclp_vt220_request *request)
-{
-       unsigned long flags;
-       int count;
-
-       spin_lock_irqsave(&sclp_vt220_lock, flags);
-       list_add_tail(&request->list, &sclp_vt220_outqueue);
-       count = sclp_vt220_outqueue_count++;
-       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
-       /* Emit only the first buffer immediately - callback takes care of
-        * the rest */
-       if (count == 0 && __sclp_vt220_emit(request))
-               sclp_vt220_process_queue(request);
-}
-
-/*
- * Queue and emit current request. Return zero on success, non-zero otherwise.
+ * Queue and emit current request.
  */
 static void
 sclp_vt220_emit_current(void)
@@ -241,22 +231,33 @@ sclp_vt220_emit_current(void)
        struct sclp_vt220_sccb *sccb;
 
        spin_lock_irqsave(&sclp_vt220_lock, flags);
-       request = NULL;
-       if (sclp_vt220_current_request != NULL) {
+       if (sclp_vt220_current_request) {
                sccb = (struct sclp_vt220_sccb *) 
                                sclp_vt220_current_request->sclp_req.sccb;
                /* Only emit buffers with content */
                if (sccb->header.length != sizeof(struct sclp_vt220_sccb)) {
-                       request = sclp_vt220_current_request;
+                       list_add_tail(&sclp_vt220_current_request->list,
+                                     &sclp_vt220_outqueue);
                        sclp_vt220_current_request = NULL;
                        if (timer_pending(&sclp_vt220_timer))
                                del_timer(&sclp_vt220_timer);
                }
                sclp_vt220_flush_later = 0;
        }
+       if (sclp_vt220_queue_running || sclp_vt220_suspended)
+               goto out_unlock;
+       if (list_empty(&sclp_vt220_outqueue))
+               goto out_unlock;
+       request = list_first_entry(&sclp_vt220_outqueue,
+                                  struct sclp_vt220_request, list);
+       sclp_vt220_queue_running = 1;
+       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+
+       if (__sclp_vt220_emit(request))
+               sclp_vt220_process_queue(request);
+       return;
+out_unlock:
        spin_unlock_irqrestore(&sclp_vt220_lock, flags);
-       if (request != NULL)
-               sclp_vt220_emit(request);
 }
 
 #define SCLP_NORMAL_WRITE      0x00
@@ -396,7 +397,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
                if (sclp_vt220_current_request == NULL) {
                        while (list_empty(&sclp_vt220_empty)) {
                                spin_unlock_irqrestore(&sclp_vt220_lock, flags);
-                               if (may_fail)
+                               if (may_fail || sclp_vt220_suspended)
                                        goto out;
                                else
                                        sclp_sync_wait();
@@ -531,7 +532,7 @@ sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch)
 static void
 sclp_vt220_flush_chars(struct tty_struct *tty)
 {
-       if (sclp_vt220_outqueue_count == 0)
+       if (!sclp_vt220_queue_running)
                sclp_vt220_emit_current();
        else
                sclp_vt220_flush_later = 1;
@@ -635,7 +636,6 @@ static int __init __sclp_vt220_init(int num_pages)
        init_timer(&sclp_vt220_timer);
        sclp_vt220_current_request = NULL;
        sclp_vt220_buffered_chars = 0;
-       sclp_vt220_outqueue_count = 0;
        sclp_vt220_tty = NULL;
        sclp_vt220_flush_later = 0;
 
@@ -736,7 +736,7 @@ static void __sclp_vt220_flush_buffer(void)
        spin_lock_irqsave(&sclp_vt220_lock, flags);
        if (timer_pending(&sclp_vt220_timer))
                del_timer(&sclp_vt220_timer);
-       while (sclp_vt220_outqueue_count > 0) {
+       while (sclp_vt220_queue_running) {
                spin_unlock_irqrestore(&sclp_vt220_lock, flags);
                sclp_sync_wait();
                spin_lock_irqsave(&sclp_vt220_lock, flags);
@@ -744,6 +744,46 @@ static void __sclp_vt220_flush_buffer(void)
        spin_unlock_irqrestore(&sclp_vt220_lock, flags);
 }
 
+/*
+ * Resume console: If there are cached messages, emit them.
+ */
+static void sclp_vt220_resume(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sclp_vt220_lock, flags);
+       sclp_vt220_suspended = 0;
+       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+       sclp_vt220_emit_current();
+}
+
+/*
+ * Suspend console: Set suspend flag and flush console
+ */
+static void sclp_vt220_suspend(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sclp_vt220_lock, flags);
+       sclp_vt220_suspended = 1;
+       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+       __sclp_vt220_flush_buffer();
+}
+
+static void sclp_vt220_pm_event_fn(struct sclp_register *reg,
+                                  enum sclp_pm_event sclp_pm_event)
+{
+       switch (sclp_pm_event) {
+       case SCLP_PM_EVENT_FREEZE:
+               sclp_vt220_suspend();
+               break;
+       case SCLP_PM_EVENT_RESTORE:
+       case SCLP_PM_EVENT_THAW:
+               sclp_vt220_resume();
+               break;
+       }
+}
+
 static int
 sclp_vt220_notify(struct notifier_block *self,
                          unsigned long event, void *data)
index 5469e099597e6083e4b80dc2ae01407b258b3a08..a263337747012de55f87375292403fb149fd5cec 100644 (file)
@@ -3,7 +3,7 @@
  *    tape device driver for 3480/3490E/3590 tapes.
  *
  *  S390 and zSeries version
- *    Copyright IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001, 2009
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *              Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -286,6 +286,7 @@ extern void tape_state_set(struct tape_device *, enum tape_state);
 
 extern int tape_generic_online(struct tape_device *, struct tape_discipline *);
 extern int tape_generic_offline(struct ccw_device *);
+extern int tape_generic_pm_suspend(struct ccw_device *);
 
 /* Externals from tape_devmap.c */
 extern int tape_generic_probe(struct ccw_device *);
index 2d00a383a475ca50fbc93a6b0fee0cc1df018c59..5a519fac37b7187505499ff33e95103da31a9e9a 100644 (file)
@@ -2,7 +2,7 @@
  *  drivers/s390/char/tape_34xx.c
  *    tape device discipline for 3480/3490 tapes.
  *
- *    Copyright (C) IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001, 2009
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *              Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -1289,7 +1289,7 @@ static int
 tape_34xx_online(struct ccw_device *cdev)
 {
        return tape_generic_online(
-               cdev->dev.driver_data,
+               dev_get_drvdata(&cdev->dev),
                &tape_discipline_34xx
        );
 }
@@ -1302,6 +1302,7 @@ static struct ccw_driver tape_34xx_driver = {
        .remove = tape_generic_remove,
        .set_online = tape_34xx_online,
        .set_offline = tape_generic_offline,
+       .freeze = tape_generic_pm_suspend,
 };
 
 static int
index c453b2f3e9f4c6c46cf73a9be1397c9f10873c7c..418f72dd39b4d4836457edd8e87a9b6b25808566 100644 (file)
@@ -2,7 +2,7 @@
  *  drivers/s390/char/tape_3590.c
  *    tape device discipline for 3590 tapes.
  *
- *    Copyright IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001, 2009
  *    Author(s): Stefan Bader <shbader@de.ibm.com>
  *              Michael Holzheu <holzheu@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -1703,7 +1703,7 @@ static struct ccw_device_id tape_3590_ids[] = {
 static int
 tape_3590_online(struct ccw_device *cdev)
 {
-       return tape_generic_online(cdev->dev.driver_data,
+       return tape_generic_online(dev_get_drvdata(&cdev->dev),
                                   &tape_discipline_3590);
 }
 
@@ -1715,6 +1715,7 @@ static struct ccw_driver tape_3590_driver = {
        .remove = tape_generic_remove,
        .set_offline = tape_generic_offline,
        .set_online = tape_3590_online,
+       .freeze = tape_generic_pm_suspend,
 };
 
 /*
index 8a109f3b69c6480d3f3dbd1463a173ed9989f66d..595aa04cfd019699e09cd03b99e9774c7f99a100 100644 (file)
@@ -3,7 +3,7 @@
  *    basic function of the tape device driver
  *
  *  S390 and zSeries version
- *    Copyright IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001, 2009
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *              Michael Holzheu <holzheu@de.ibm.com>
  *              Tuan Ngo-Anh <ngoanh@de.ibm.com>
@@ -92,7 +92,7 @@ tape_medium_state_show(struct device *dev, struct device_attribute *attr, char *
 {
        struct tape_device *tdev;
 
-       tdev = (struct tape_device *) dev->driver_data;
+       tdev = dev_get_drvdata(dev);
        return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->medium_state);
 }
 
@@ -104,7 +104,7 @@ tape_first_minor_show(struct device *dev, struct device_attribute *attr, char *b
 {
        struct tape_device *tdev;
 
-       tdev = (struct tape_device *) dev->driver_data;
+       tdev = dev_get_drvdata(dev);
        return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->first_minor);
 }
 
@@ -116,7 +116,7 @@ tape_state_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct tape_device *tdev;
 
-       tdev = (struct tape_device *) dev->driver_data;
+       tdev = dev_get_drvdata(dev);
        return scnprintf(buf, PAGE_SIZE, "%s\n", (tdev->first_minor < 0) ?
                "OFFLINE" : tape_state_verbose[tdev->tape_state]);
 }
@@ -130,7 +130,7 @@ tape_operation_show(struct device *dev, struct device_attribute *attr, char *buf
        struct tape_device *tdev;
        ssize_t rc;
 
-       tdev = (struct tape_device *) dev->driver_data;
+       tdev = dev_get_drvdata(dev);
        if (tdev->first_minor < 0)
                return scnprintf(buf, PAGE_SIZE, "N/A\n");
 
@@ -156,7 +156,7 @@ tape_blocksize_show(struct device *dev, struct device_attribute *attr, char *buf
 {
        struct tape_device *tdev;
 
-       tdev = (struct tape_device *) dev->driver_data;
+       tdev = dev_get_drvdata(dev);
 
        return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->char_data.block_size);
 }
@@ -379,6 +379,55 @@ tape_cleanup_device(struct tape_device *device)
        tape_med_state_set(device, MS_UNKNOWN);
 }
 
+/*
+ * Suspend device.
+ *
+ * Called by the common I/O layer if the drive should be suspended on user
+ * request. We refuse to suspend if the device is loaded or in use for the
+ * following reason:
+ * While the Linux guest is suspended, it might be logged off which causes
+ * devices to be detached. Tape devices are automatically rewound and unloaded
+ * during DETACH processing (unless the tape device was attached with the
+ * NOASSIGN or MULTIUSER option). After rewind/unload, there is no way to
+ * resume the original state of the tape device, since we would need to
+ * manually re-load the cartridge which was active at suspend time.
+ */
+int tape_generic_pm_suspend(struct ccw_device *cdev)
+{
+       struct tape_device *device;
+
+       device = cdev->dev.driver_data;
+       if (!device) {
+               return -ENODEV;
+       }
+
+       DBF_LH(3, "(%08x): tape_generic_pm_suspend(%p)\n",
+               device->cdev_id, device);
+
+       if (device->medium_state != MS_UNLOADED) {
+               pr_err("A cartridge is loaded in tape device %s, "
+                      "refusing to suspend\n", dev_name(&cdev->dev));
+               return -EBUSY;
+       }
+
+       spin_lock_irq(get_ccwdev_lock(device->cdev));
+       switch (device->tape_state) {
+               case TS_INIT:
+               case TS_NOT_OPER:
+               case TS_UNUSED:
+                       spin_unlock_irq(get_ccwdev_lock(device->cdev));
+                       break;
+               default:
+                       pr_err("Tape device %s is busy, refusing to "
+                              "suspend\n", dev_name(&cdev->dev));
+                       spin_unlock_irq(get_ccwdev_lock(device->cdev));
+                       return -EBUSY;
+       }
+
+       DBF_LH(3, "(%08x): Drive suspended.\n", device->cdev_id);
+       return 0;
+}
+
 /*
  * Set device offline.
  *
@@ -391,7 +440,7 @@ tape_generic_offline(struct ccw_device *cdev)
 {
        struct tape_device *device;
 
-       device = cdev->dev.driver_data;
+       device = dev_get_drvdata(&cdev->dev);
        if (!device) {
                return -ENODEV;
        }
@@ -534,7 +583,7 @@ tape_generic_probe(struct ccw_device *cdev)
                tape_put_device(device);
                return ret;
        }
-       cdev->dev.driver_data = device;
+       dev_set_drvdata(&cdev->dev, device);
        cdev->handler = __tape_do_irq;
        device->cdev = cdev;
        ccw_device_get_id(cdev, &dev_id);
@@ -573,7 +622,7 @@ tape_generic_remove(struct ccw_device *cdev)
 {
        struct tape_device *    device;
 
-       device = cdev->dev.driver_data;
+       device = dev_get_drvdata(&cdev->dev);
        if (!device) {
                return;
        }
@@ -613,9 +662,9 @@ tape_generic_remove(struct ccw_device *cdev)
                        tape_cleanup_device(device);
        }
 
-       if (cdev->dev.driver_data != NULL) {
+       if (!dev_get_drvdata(&cdev->dev)) {
                sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group);
-               cdev->dev.driver_data = tape_put_device(cdev->dev.driver_data);
+               dev_set_drvdata(&cdev->dev, tape_put_device(dev_get_drvdata(&cdev->dev)));
        }
 }
 
@@ -1011,7 +1060,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        struct tape_request *request;
        int rc;
 
-       device = (struct tape_device *) cdev->dev.driver_data;
+       device = dev_get_drvdata(&cdev->dev);
        if (device == NULL) {
                return;
        }
@@ -1273,6 +1322,7 @@ EXPORT_SYMBOL(tape_generic_remove);
 EXPORT_SYMBOL(tape_generic_probe);
 EXPORT_SYMBOL(tape_generic_online);
 EXPORT_SYMBOL(tape_generic_offline);
+EXPORT_SYMBOL(tape_generic_pm_suspend);
 EXPORT_SYMBOL(tape_put_device);
 EXPORT_SYMBOL(tape_get_device_reference);
 EXPORT_SYMBOL(tape_state_verbose);
index d8a2289fcb699c8f501d510340b90bf43051a03f..411cfa3c77196261c126b79356563505b8bb901e 100644 (file)
@@ -3,7 +3,7 @@
  *     character device driver for reading z/VM system service records
  *
  *
- *     Copyright 2004 IBM Corporation
+ *     Copyright IBM Corp. 2004, 2009
  *     character device driver for reading z/VM system service records,
  *     Version 1.0
  *     Author(s): Xenia Tkatschow <xenia@us.ibm.com>
@@ -504,7 +504,7 @@ static ssize_t vmlogrdr_autopurge_store(struct device * dev,
                                        struct device_attribute *attr,
                                        const char * buf, size_t count)
 {
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
        ssize_t ret = count;
 
        switch (buf[0]) {
@@ -525,7 +525,7 @@ static ssize_t vmlogrdr_autopurge_show(struct device *dev,
                                       struct device_attribute *attr,
                                       char *buf)
 {
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
        return sprintf(buf, "%u\n", priv->autopurge);
 }
 
@@ -541,7 +541,7 @@ static ssize_t vmlogrdr_purge_store(struct device * dev,
 
        char cp_command[80];
        char cp_response[80];
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
 
        if (buf[0] != '1')
                return -EINVAL;
@@ -578,7 +578,7 @@ static ssize_t vmlogrdr_autorecording_store(struct device *dev,
                                            struct device_attribute *attr,
                                            const char *buf, size_t count)
 {
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
        ssize_t ret = count;
 
        switch (buf[0]) {
@@ -599,7 +599,7 @@ static ssize_t vmlogrdr_autorecording_show(struct device *dev,
                                           struct device_attribute *attr,
                                           char *buf)
 {
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
        return sprintf(buf, "%u\n", priv->autorecording);
 }
 
@@ -612,7 +612,7 @@ static ssize_t vmlogrdr_recording_store(struct device * dev,
                                        struct device_attribute *attr,
                                        const char * buf, size_t count)
 {
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
        ssize_t ret;
 
        switch (buf[0]) {
@@ -660,6 +660,29 @@ static struct attribute *vmlogrdr_attrs[] = {
        NULL,
 };
 
+static int vmlogrdr_pm_prepare(struct device *dev)
+{
+       int rc;
+       struct vmlogrdr_priv_t *priv = dev->driver_data;
+
+       rc = 0;
+       if (priv) {
+               spin_lock_bh(&priv->priv_lock);
+               if (priv->dev_in_use)
+                       rc = -EBUSY;
+               spin_unlock_bh(&priv->priv_lock);
+       }
+       if (rc)
+               pr_err("vmlogrdr: device %s is busy. Refuse to suspend.\n",
+                      dev_name(dev));
+       return rc;
+}
+
+
+static struct dev_pm_ops vmlogrdr_pm_ops = {
+       .prepare = vmlogrdr_pm_prepare,
+};
+
 static struct attribute_group vmlogrdr_attr_group = {
        .attrs = vmlogrdr_attrs,
 };
@@ -668,6 +691,7 @@ static struct class *vmlogrdr_class;
 static struct device_driver vmlogrdr_driver = {
        .name = "vmlogrdr",
        .bus  = &iucv_bus,
+       .pm = &vmlogrdr_pm_ops,
 };
 
 
@@ -729,6 +753,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
                dev->bus = &iucv_bus;
                dev->parent = iucv_root;
                dev->driver = &vmlogrdr_driver;
+               dev->driver_data = priv;
                /*
                 * The release function could be called after the
                 * module has been unloaded. It's _only_ task is to
index 5dcef81fc9d927a0bf5672a0f979e564dac32953..7d9e67cb64714494043bf62449632a27780fa0be 100644 (file)
@@ -2,7 +2,7 @@
  * Linux driver for System z and s390 unit record devices
  * (z/VM virtual punch, reader, printer)
  *
- * Copyright IBM Corp. 2001, 2007
+ * Copyright IBM Corp. 2001, 2009
  * Authors: Malcolm Beattie <beattiem@uk.ibm.com>
  *         Michael Holzheu <holzheu@de.ibm.com>
  *         Frank Munzert <munzert@de.ibm.com>
@@ -60,6 +60,7 @@ static int ur_probe(struct ccw_device *cdev);
 static void ur_remove(struct ccw_device *cdev);
 static int ur_set_online(struct ccw_device *cdev);
 static int ur_set_offline(struct ccw_device *cdev);
+static int ur_pm_suspend(struct ccw_device *cdev);
 
 static struct ccw_driver ur_driver = {
        .name           = "vmur",
@@ -69,6 +70,7 @@ static struct ccw_driver ur_driver = {
        .remove         = ur_remove,
        .set_online     = ur_set_online,
        .set_offline    = ur_set_offline,
+       .freeze         = ur_pm_suspend,
 };
 
 static DEFINE_MUTEX(vmur_mutex);
@@ -78,11 +80,11 @@ static DEFINE_MUTEX(vmur_mutex);
  *
  * Each ur device (urd) contains a reference to its corresponding ccw device
  * (cdev) using the urd->cdev pointer. Each ccw device has a reference to the
- * ur device using the cdev->dev.driver_data pointer.
+ * ur device using dev_get_drvdata(&cdev->dev) pointer.
  *
  * urd references:
  * - ur_probe gets a urd reference, ur_remove drops the reference
- *   (cdev->dev.driver_data)
+ *   dev_get_drvdata(&cdev->dev)
  * - ur_open gets a urd reference, ur_relase drops the reference
  *   (urf->urd)
  *
@@ -90,7 +92,7 @@ static DEFINE_MUTEX(vmur_mutex);
  * - urdev_alloc get a cdev reference (urd->cdev)
  * - urdev_free drops the cdev reference (urd->cdev)
  *
- * Setting and clearing of cdev->dev.driver_data is protected by the ccwdev lock
+ * Setting and clearing of dev_get_drvdata(&cdev->dev) is protected by the ccwdev lock
  */
 static struct urdev *urdev_alloc(struct ccw_device *cdev)
 {
@@ -129,7 +131,7 @@ static struct urdev *urdev_get_from_cdev(struct ccw_device *cdev)
        unsigned long flags;
 
        spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-       urd = cdev->dev.driver_data;
+       urd = dev_get_drvdata(&cdev->dev);
        if (urd)
                urdev_get(urd);
        spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
@@ -157,6 +159,28 @@ static void urdev_put(struct urdev *urd)
                urdev_free(urd);
 }
 
+/*
+ * State and contents of ur devices can be changed by class D users issuing
+ * CP commands such as PURGE or TRANSFER, while the Linux guest is suspended.
+ * Also the Linux guest might be logged off, which causes all active spool
+ * files to be closed.
+ * So we cannot guarantee that spool files are still the same when the Linux
+ * guest is resumed. In order to avoid unpredictable results at resume time
+ * we simply refuse to suspend if a ur device node is open.
+ */
+static int ur_pm_suspend(struct ccw_device *cdev)
+{
+       struct urdev *urd = cdev->dev.driver_data;
+
+       TRACE("ur_pm_suspend: cdev=%p\n", cdev);
+       if (urd->open_flag) {
+               pr_err("Unit record device %s is busy, %s refusing to "
+                      "suspend.\n", dev_name(&cdev->dev), ur_banner);
+               return -EBUSY;
+       }
+       return 0;
+}
+
 /*
  * Low-level functions to do I/O to a ur device.
  *     alloc_chan_prog
@@ -286,7 +310,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
                TRACE("ur_int_handler: unsolicited interrupt\n");
                return;
        }
-       urd = cdev->dev.driver_data;
+       urd = dev_get_drvdata(&cdev->dev);
        BUG_ON(!urd);
        /* On special conditions irb is an error pointer */
        if (IS_ERR(irb))
@@ -832,7 +856,7 @@ static int ur_probe(struct ccw_device *cdev)
                goto fail_remove_attr;
        }
        spin_lock_irq(get_ccwdev_lock(cdev));
-       cdev->dev.driver_data = urd;
+       dev_set_drvdata(&cdev->dev, urd);
        spin_unlock_irq(get_ccwdev_lock(cdev));
 
        mutex_unlock(&vmur_mutex);
@@ -972,8 +996,8 @@ static void ur_remove(struct ccw_device *cdev)
        ur_remove_attributes(&cdev->dev);
 
        spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-       urdev_put(cdev->dev.driver_data);
-       cdev->dev.driver_data = NULL;
+       urdev_put(dev_get_drvdata(&cdev->dev));
+       dev_set_drvdata(&cdev->dev, NULL);
        spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
 
        mutex_unlock(&vmur_mutex);
index 21a2a829bf4eb5baf20cfdfd9e71489c5987b77a..cb7854c10c0479585d1879f9c0a3fe8a90a713a1 100644 (file)
@@ -1,17 +1,23 @@
 /*
  * Watchdog implementation based on z/VM Watchdog Timer API
  *
+ * Copyright IBM Corp. 2004,2009
+ *
  * The user space watchdog daemon can use this driver as
  * /dev/vmwatchdog to have z/VM execute the specified CP
  * command when the timeout expires. The default command is
  * "IPL", which which cause an immediate reboot.
  */
+#define KMSG_COMPONENT "vmwatchdog"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/suspend.h>
 #include <linux/watchdog.h>
 #include <linux/smp_lock.h>
 
@@ -43,6 +49,9 @@ static unsigned int vmwdt_interval = 60;
 static unsigned long vmwdt_is_open;
 static int vmwdt_expect_close;
 
+#define VMWDT_OPEN     0       /* devnode is open or suspend in progress */
+#define VMWDT_RUNNING  1       /* The watchdog is armed */
+
 enum vmwdt_func {
        /* function codes */
        wdt_init   = 0,
@@ -92,6 +101,7 @@ static int vmwdt_keepalive(void)
        EBC_TOUPPER(ebc_cmd, MAX_CMDLEN);
 
        func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init;
+       set_bit(VMWDT_RUNNING, &vmwdt_is_open);
        ret = __diag288(func, vmwdt_interval, ebc_cmd, len);
        WARN_ON(ret != 0);
        kfree(ebc_cmd);
@@ -102,6 +112,7 @@ static int vmwdt_disable(void)
 {
        int ret = __diag288(wdt_cancel, 0, "", 0);
        WARN_ON(ret != 0);
+       clear_bit(VMWDT_RUNNING, &vmwdt_is_open);
        return ret;
 }
 
@@ -123,13 +134,13 @@ static int vmwdt_open(struct inode *i, struct file *f)
 {
        int ret;
        lock_kernel();
-       if (test_and_set_bit(0, &vmwdt_is_open)) {
+       if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) {
                unlock_kernel();
                return -EBUSY;
        }
        ret = vmwdt_keepalive();
        if (ret)
-               clear_bit(0, &vmwdt_is_open);
+               clear_bit(VMWDT_OPEN, &vmwdt_is_open);
        unlock_kernel();
        return ret ? ret : nonseekable_open(i, f);
 }
@@ -139,7 +150,7 @@ static int vmwdt_close(struct inode *i, struct file *f)
        if (vmwdt_expect_close == 42)
                vmwdt_disable();
        vmwdt_expect_close = 0;
-       clear_bit(0, &vmwdt_is_open);
+       clear_bit(VMWDT_OPEN, &vmwdt_is_open);
        return 0;
 }
 
@@ -223,6 +234,57 @@ static ssize_t vmwdt_write(struct file *f, const char __user *buf,
        return count;
 }
 
+static int vmwdt_resume(void)
+{
+       clear_bit(VMWDT_OPEN, &vmwdt_is_open);
+       return NOTIFY_DONE;
+}
+
+/*
+ * It makes no sense to go into suspend while the watchdog is running.
+ * Depending on the memory size, the watchdog might trigger, while we
+ * are still saving the memory.
+ * We reuse the open flag to ensure that suspend and watchdog open are
+ * exclusive operations
+ */
+static int vmwdt_suspend(void)
+{
+       if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) {
+               pr_err("The watchdog is in use. "
+                       "This prevents hibernation or suspend.\n");
+               return NOTIFY_BAD;
+       }
+       if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) {
+               clear_bit(VMWDT_OPEN, &vmwdt_is_open);
+               pr_err("The watchdog is running. "
+                       "This prevents hibernation or suspend.\n");
+               return NOTIFY_BAD;
+       }
+       return NOTIFY_DONE;
+}
+
+/*
+ * This function is called for suspend and resume.
+ */
+static int vmwdt_power_event(struct notifier_block *this, unsigned long event,
+                            void *ptr)
+{
+       switch (event) {
+       case PM_POST_HIBERNATION:
+       case PM_POST_SUSPEND:
+               return vmwdt_resume();
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+               return vmwdt_suspend();
+       default:
+               return NOTIFY_DONE;
+       }
+}
+
+static struct notifier_block vmwdt_power_notifier = {
+       .notifier_call = vmwdt_power_event,
+};
+
 static const struct file_operations vmwdt_fops = {
        .open    = &vmwdt_open,
        .release = &vmwdt_close,
@@ -244,12 +306,21 @@ static int __init vmwdt_init(void)
        ret = vmwdt_probe();
        if (ret)
                return ret;
-       return misc_register(&vmwdt_dev);
+       ret = register_pm_notifier(&vmwdt_power_notifier);
+       if (ret)
+               return ret;
+       ret = misc_register(&vmwdt_dev);
+       if (ret) {
+               unregister_pm_notifier(&vmwdt_power_notifier);
+               return ret;
+       }
+       return 0;
 }
 module_init(vmwdt_init);
 
 static void __exit vmwdt_exit(void)
 {
-       WARN_ON(misc_deregister(&vmwdt_dev) != 0);
+       unregister_pm_notifier(&vmwdt_power_notifier);
+       misc_deregister(&vmwdt_dev);
 }
 module_exit(vmwdt_exit);
index 22ce765d537e9f0bccbca4c769131c07b3c03574..a5a62f1f7747c66107c71ea62be654473765541f 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/cio/ccwgroup.c
  *  bus driver for ccwgroup
  *
- *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
- *                       IBM Corporation
- *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
- *               Cornelia Huck (cornelia.huck@de.ibm.com)
+ *  Copyright IBM Corp. 2002, 2009
+ *
+ *  Author(s): Arnd Bergmann (arndb@de.ibm.com)
+ *            Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -501,6 +500,74 @@ static void ccwgroup_shutdown(struct device *dev)
                gdrv->shutdown(gdev);
 }
 
+static int ccwgroup_pm_prepare(struct device *dev)
+{
+       struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+       struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver);
+
+       /* Fail while device is being set online/offline. */
+       if (atomic_read(&gdev->onoff))
+               return -EAGAIN;
+
+       if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE)
+               return 0;
+
+       return gdrv->prepare ? gdrv->prepare(gdev) : 0;
+}
+
+static void ccwgroup_pm_complete(struct device *dev)
+{
+       struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+       struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver);
+
+       if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE)
+               return;
+
+       if (gdrv->complete)
+               gdrv->complete(gdev);
+}
+
+static int ccwgroup_pm_freeze(struct device *dev)
+{
+       struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+       struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver);
+
+       if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE)
+               return 0;
+
+       return gdrv->freeze ? gdrv->freeze(gdev) : 0;
+}
+
+static int ccwgroup_pm_thaw(struct device *dev)
+{
+       struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+       struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver);
+
+       if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE)
+               return 0;
+
+       return gdrv->thaw ? gdrv->thaw(gdev) : 0;
+}
+
+static int ccwgroup_pm_restore(struct device *dev)
+{
+       struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+       struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver);
+
+       if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE)
+               return 0;
+
+       return gdrv->restore ? gdrv->restore(gdev) : 0;
+}
+
+static struct dev_pm_ops ccwgroup_pm_ops = {
+       .prepare = ccwgroup_pm_prepare,
+       .complete = ccwgroup_pm_complete,
+       .freeze = ccwgroup_pm_freeze,
+       .thaw = ccwgroup_pm_thaw,
+       .restore = ccwgroup_pm_restore,
+};
+
 static struct bus_type ccwgroup_bus_type = {
        .name   = "ccwgroup",
        .match  = ccwgroup_bus_match,
@@ -508,6 +575,7 @@ static struct bus_type ccwgroup_bus_type = {
        .probe  = ccwgroup_probe,
        .remove = ccwgroup_remove,
        .shutdown = ccwgroup_shutdown,
+       .pm = &ccwgroup_pm_ops,
 };
 
 
index 883f16f96f2286ffaa8b617cef0227b239b61799..1ecd3e567648f0cf97dec1b0d63060450aae2037 100644 (file)
@@ -549,8 +549,7 @@ cleanup:
        return ret;
 }
 
-static int
-__chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
+int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
 {
        struct {
                struct chsc_header request;
index ba59bceace987968823330fb74abf048286b96e1..425e8f89a6c504c48e41feac82780695bfb911ca 100644 (file)
@@ -90,6 +90,7 @@ extern void chsc_free_sei_area(void);
 extern int chsc_enable_facility(int);
 struct channel_subsystem;
 extern int chsc_secm(struct channel_subsystem *, int);
+int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page);
 
 int chsc_chp_vary(struct chp_id chpid, int on);
 int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
index 93eca1731b81a56bb7d934a8c5e62119e8178eb9..cc5144b6f9d9c590f56bdb9112774130f23f97ed 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Driver for s390 chsc subchannels
  *
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008, 2009
+ *
  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
  *
  */
@@ -112,6 +113,31 @@ static void chsc_subchannel_shutdown(struct subchannel *sch)
        cio_disable_subchannel(sch);
 }
 
+static int chsc_subchannel_prepare(struct subchannel *sch)
+{
+       int cc;
+       struct schib schib;
+       /*
+        * Don't allow suspend while the subchannel is not idle
+        * since we don't have a way to clear the subchannel and
+        * cannot disable it with a request running.
+        */
+       cc = stsch(sch->schid, &schib);
+       if (!cc && scsw_stctl(&schib.scsw))
+               return -EAGAIN;
+       return 0;
+}
+
+static int chsc_subchannel_freeze(struct subchannel *sch)
+{
+       return cio_disable_subchannel(sch);
+}
+
+static int chsc_subchannel_restore(struct subchannel *sch)
+{
+       return cio_enable_subchannel(sch, (u32)(unsigned long)sch);
+}
+
 static struct css_device_id chsc_subchannel_ids[] = {
        { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, },
        { /* end of list */ },
@@ -125,6 +151,10 @@ static struct css_driver chsc_subchannel_driver = {
        .probe = chsc_subchannel_probe,
        .remove = chsc_subchannel_remove,
        .shutdown = chsc_subchannel_shutdown,
+       .prepare = chsc_subchannel_prepare,
+       .freeze = chsc_subchannel_freeze,
+       .thaw = chsc_subchannel_restore,
+       .restore = chsc_subchannel_restore,
        .name = "chsc_subchannel",
 };
 
index dc98b2c638628bf8a3174db78c53ec5823506a1e..30f516111307718234d579af922f51f01418bb49 100644 (file)
@@ -1204,6 +1204,11 @@ static ssize_t cmb_enable_store(struct device *dev,
 
 DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);
 
+int ccw_set_cmf(struct ccw_device *cdev, int enable)
+{
+       return cmbops->set(cdev, enable ? 2 : 0);
+}
+
 /**
  * enable_cmf() - switch on the channel measurement for a specific device
  *  @cdev:     The ccw device to be enabled
index 0085d89017924c13d0b1ab0686cd3bb7571ba190..85d43c6bcb66a3521de03370d74c399c87440de8 100644 (file)
@@ -1,10 +1,10 @@
 /*
- *  drivers/s390/cio/css.c
- *  driver for channel subsystem
+ * driver for channel subsystem
  *
- *    Copyright IBM Corp. 2002,2008
- *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
- *              Cornelia Huck (cornelia.huck@de.ibm.com)
+ * Copyright IBM Corp. 2002, 2009
+ *
+ * Author(s): Arnd Bergmann (arndb@de.ibm.com)
+ *           Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 
 #define KMSG_COMPONENT "cio"
@@ -17,6 +17,7 @@
 #include <linux/errno.h>
 #include <linux/list.h>
 #include <linux/reboot.h>
+#include <linux/suspend.h>
 #include <asm/isc.h>
 #include <asm/crw.h>
 
@@ -779,6 +780,79 @@ static struct notifier_block css_reboot_notifier = {
        .notifier_call = css_reboot_event,
 };
 
+/*
+ * Since the css devices are neither on a bus nor have a class
+ * nor have a special device type, we cannot stop/restart channel
+ * path measurements via the normal suspend/resume callbacks, but have
+ * to use notifiers.
+ */
+static int css_power_event(struct notifier_block *this, unsigned long event,
+                          void *ptr)
+{
+       void *secm_area;
+       int ret, i;
+
+       switch (event) {
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+               ret = NOTIFY_DONE;
+               for (i = 0; i <= __MAX_CSSID; i++) {
+                       struct channel_subsystem *css;
+
+                       css = channel_subsystems[i];
+                       mutex_lock(&css->mutex);
+                       if (!css->cm_enabled) {
+                               mutex_unlock(&css->mutex);
+                               continue;
+                       }
+                       secm_area = (void *)get_zeroed_page(GFP_KERNEL |
+                                                           GFP_DMA);
+                       if (secm_area) {
+                               if (__chsc_do_secm(css, 0, secm_area))
+                                       ret = NOTIFY_BAD;
+                               free_page((unsigned long)secm_area);
+                       } else
+                               ret = NOTIFY_BAD;
+
+                       mutex_unlock(&css->mutex);
+               }
+               break;
+       case PM_POST_HIBERNATION:
+       case PM_POST_SUSPEND:
+               ret = NOTIFY_DONE;
+               for (i = 0; i <= __MAX_CSSID; i++) {
+                       struct channel_subsystem *css;
+
+                       css = channel_subsystems[i];
+                       mutex_lock(&css->mutex);
+                       if (!css->cm_enabled) {
+                               mutex_unlock(&css->mutex);
+                               continue;
+                       }
+                       secm_area = (void *)get_zeroed_page(GFP_KERNEL |
+                                                           GFP_DMA);
+                       if (secm_area) {
+                               if (__chsc_do_secm(css, 1, secm_area))
+                                       ret = NOTIFY_BAD;
+                               free_page((unsigned long)secm_area);
+                       } else
+                               ret = NOTIFY_BAD;
+
+                       mutex_unlock(&css->mutex);
+               }
+               /* search for subchannels, which appeared during hibernation */
+               css_schedule_reprobe();
+               break;
+       default:
+               ret = NOTIFY_DONE;
+       }
+       return ret;
+
+}
+static struct notifier_block css_power_notifier = {
+       .notifier_call = css_power_event,
+};
+
 /*
  * Now that the driver core is running, we can setup our channel subsystem.
  * The struct subchannel's are created during probing (except for the
@@ -852,6 +926,11 @@ init_channel_subsystem (void)
        ret = register_reboot_notifier(&css_reboot_notifier);
        if (ret)
                goto out_unregister;
+       ret = register_pm_notifier(&css_power_notifier);
+       if (ret) {
+               unregister_reboot_notifier(&css_reboot_notifier);
+               goto out_unregister;
+       }
        css_init_done = 1;
 
        /* Enable default isc for I/O subchannels. */
@@ -953,6 +1032,73 @@ static int css_uevent(struct device *dev, struct kobj_uevent_env *env)
        return ret;
 }
 
+static int css_pm_prepare(struct device *dev)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       struct css_driver *drv;
+
+       if (mutex_is_locked(&sch->reg_mutex))
+               return -EAGAIN;
+       if (!sch->dev.driver)
+               return 0;
+       drv = to_cssdriver(sch->dev.driver);
+       /* Notify drivers that they may not register children. */
+       return drv->prepare ? drv->prepare(sch) : 0;
+}
+
+static void css_pm_complete(struct device *dev)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       struct css_driver *drv;
+
+       if (!sch->dev.driver)
+               return;
+       drv = to_cssdriver(sch->dev.driver);
+       if (drv->complete)
+               drv->complete(sch);
+}
+
+static int css_pm_freeze(struct device *dev)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       struct css_driver *drv;
+
+       if (!sch->dev.driver)
+               return 0;
+       drv = to_cssdriver(sch->dev.driver);
+       return drv->freeze ? drv->freeze(sch) : 0;
+}
+
+static int css_pm_thaw(struct device *dev)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       struct css_driver *drv;
+
+       if (!sch->dev.driver)
+               return 0;
+       drv = to_cssdriver(sch->dev.driver);
+       return drv->thaw ? drv->thaw(sch) : 0;
+}
+
+static int css_pm_restore(struct device *dev)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       struct css_driver *drv;
+
+       if (!sch->dev.driver)
+               return 0;
+       drv = to_cssdriver(sch->dev.driver);
+       return drv->restore ? drv->restore(sch) : 0;
+}
+
+static struct dev_pm_ops css_pm_ops = {
+       .prepare = css_pm_prepare,
+       .complete = css_pm_complete,
+       .freeze = css_pm_freeze,
+       .thaw = css_pm_thaw,
+       .restore = css_pm_restore,
+};
+
 struct bus_type css_bus_type = {
        .name     = "css",
        .match    = css_bus_match,
@@ -960,6 +1106,7 @@ struct bus_type css_bus_type = {
        .remove   = css_remove,
        .shutdown = css_shutdown,
        .uevent   = css_uevent,
+       .pm = &css_pm_ops,
 };
 
 /**
index 57ebf120f825b00f68ee934e9e9a26324beedd09..9763eeec74587d3a106dc5eae49eacd40505f899 100644 (file)
@@ -70,6 +70,11 @@ struct chp_link;
  * @probe: function called on probe
  * @remove: function called on remove
  * @shutdown: called at device shutdown
+ * @prepare: prepare for pm state transition
+ * @complete: undo work done in @prepare
+ * @freeze: callback for freezing during hibernation snapshotting
+ * @thaw: undo work done in @freeze
+ * @restore: callback for restoring after hibernation
  * @name: name of the device driver
  */
 struct css_driver {
@@ -82,6 +87,11 @@ struct css_driver {
        int (*probe)(struct subchannel *);
        int (*remove)(struct subchannel *);
        void (*shutdown)(struct subchannel *);
+       int (*prepare) (struct subchannel *);
+       void (*complete) (struct subchannel *);
+       int (*freeze)(struct subchannel *);
+       int (*thaw) (struct subchannel *);
+       int (*restore)(struct subchannel *);
        const char *name;
 };
 
index 35441fa16be1de86dcb72dd02d8e319da458edde..3c57c1a18bb8772db79a73159a98244ae4c89972 100644 (file)
@@ -138,6 +138,19 @@ static struct css_device_id io_subchannel_ids[] = {
 };
 MODULE_DEVICE_TABLE(css, io_subchannel_ids);
 
+static int io_subchannel_prepare(struct subchannel *sch)
+{
+       struct ccw_device *cdev;
+       /*
+        * Don't allow suspend while a ccw device registration
+        * is still outstanding.
+        */
+       cdev = sch_get_cdev(sch);
+       if (cdev && !device_is_registered(&cdev->dev))
+               return -EAGAIN;
+       return 0;
+}
+
 static struct css_driver io_subchannel_driver = {
        .owner = THIS_MODULE,
        .subchannel_type = io_subchannel_ids,
@@ -148,6 +161,7 @@ static struct css_driver io_subchannel_driver = {
        .probe = io_subchannel_probe,
        .remove = io_subchannel_remove,
        .shutdown = io_subchannel_shutdown,
+       .prepare = io_subchannel_prepare,
 };
 
 struct workqueue_struct *ccw_device_work;
@@ -1775,6 +1789,15 @@ ccw_device_probe_console(void)
        return &console_cdev;
 }
 
+static int ccw_device_pm_restore(struct device *dev);
+
+int ccw_device_force_console(void)
+{
+       if (!console_cdev_in_use)
+               return -ENODEV;
+       return ccw_device_pm_restore(&console_cdev.dev);
+}
+EXPORT_SYMBOL_GPL(ccw_device_force_console);
 
 const char *cio_get_console_cdev_name(struct subchannel *sch)
 {
@@ -1895,6 +1918,242 @@ static void ccw_device_shutdown(struct device *dev)
        disable_cmf(cdev);
 }
 
+static int ccw_device_pm_prepare(struct device *dev)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+
+       if (work_pending(&cdev->private->kick_work))
+               return -EAGAIN;
+       /* Fail while device is being set online/offline. */
+       if (atomic_read(&cdev->private->onoff))
+               return -EAGAIN;
+
+       if (cdev->online && cdev->drv && cdev->drv->prepare)
+               return cdev->drv->prepare(cdev);
+
+       return 0;
+}
+
+static void ccw_device_pm_complete(struct device *dev)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+
+       if (cdev->online && cdev->drv && cdev->drv->complete)
+               cdev->drv->complete(cdev);
+}
+
+static int ccw_device_pm_freeze(struct device *dev)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       int ret, cm_enabled;
+
+       /* Fail suspend while device is in transistional state. */
+       if (!dev_fsm_final_state(cdev))
+               return -EAGAIN;
+       if (!cdev->online)
+               return 0;
+       if (cdev->drv && cdev->drv->freeze) {
+               ret = cdev->drv->freeze(cdev);
+               if (ret)
+                       return ret;
+       }
+
+       spin_lock_irq(sch->lock);
+       cm_enabled = cdev->private->cmb != NULL;
+       spin_unlock_irq(sch->lock);
+       if (cm_enabled) {
+               /* Don't have the css write on memory. */
+               ret = ccw_set_cmf(cdev, 0);
+               if (ret)
+                       return ret;
+       }
+       /* From here on, disallow device driver I/O. */
+       spin_lock_irq(sch->lock);
+       ret = cio_disable_subchannel(sch);
+       spin_unlock_irq(sch->lock);
+
+       return ret;
+}
+
+static int ccw_device_pm_thaw(struct device *dev)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       int ret, cm_enabled;
+
+       if (!cdev->online)
+               return 0;
+
+       spin_lock_irq(sch->lock);
+       /* Allow device driver I/O again. */
+       ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
+       cm_enabled = cdev->private->cmb != NULL;
+       spin_unlock_irq(sch->lock);
+       if (ret)
+               return ret;
+
+       if (cm_enabled) {
+               ret = ccw_set_cmf(cdev, 1);
+               if (ret)
+                       return ret;
+       }
+
+       if (cdev->drv && cdev->drv->thaw)
+               ret = cdev->drv->thaw(cdev);
+
+       return ret;
+}
+
+static void __ccw_device_pm_restore(struct ccw_device *cdev)
+{
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       int ret;
+
+       if (cio_is_console(sch->schid))
+               goto out;
+       /*
+        * While we were sleeping, devices may have gone or become
+        * available again. Kick re-detection.
+        */
+       spin_lock_irq(sch->lock);
+       cdev->private->flags.resuming = 1;
+       ret = ccw_device_recognition(cdev);
+       spin_unlock_irq(sch->lock);
+       if (ret) {
+               CIO_MSG_EVENT(0, "Couldn't start recognition for device "
+                             "%s (ret=%d)\n", dev_name(&cdev->dev), ret);
+               spin_lock_irq(sch->lock);
+               cdev->private->state = DEV_STATE_DISCONNECTED;
+               spin_unlock_irq(sch->lock);
+               /* notify driver after the resume cb */
+               goto out;
+       }
+       wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) ||
+                  cdev->private->state == DEV_STATE_DISCONNECTED);
+
+out:
+       cdev->private->flags.resuming = 0;
+}
+
+static int resume_handle_boxed(struct ccw_device *cdev)
+{
+       cdev->private->state = DEV_STATE_BOXED;
+       if (ccw_device_notify(cdev, CIO_BOXED))
+               return 0;
+       ccw_device_schedule_sch_unregister(cdev);
+       return -ENODEV;
+}
+
+static int resume_handle_disc(struct ccw_device *cdev)
+{
+       cdev->private->state = DEV_STATE_DISCONNECTED;
+       if (ccw_device_notify(cdev, CIO_GONE))
+               return 0;
+       ccw_device_schedule_sch_unregister(cdev);
+       return -ENODEV;
+}
+
+static int ccw_device_pm_restore(struct device *dev)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       int ret = 0, cm_enabled;
+
+       __ccw_device_pm_restore(cdev);
+       spin_lock_irq(sch->lock);
+       if (cio_is_console(sch->schid)) {
+               cio_enable_subchannel(sch, (u32)(addr_t)sch);
+               spin_unlock_irq(sch->lock);
+               goto out_restore;
+       }
+       cdev->private->flags.donotify = 0;
+       /* check recognition results */
+       switch (cdev->private->state) {
+       case DEV_STATE_OFFLINE:
+               break;
+       case DEV_STATE_BOXED:
+               ret = resume_handle_boxed(cdev);
+               spin_unlock_irq(sch->lock);
+               if (ret)
+                       goto out;
+               goto out_restore;
+       case DEV_STATE_DISCONNECTED:
+               goto out_disc_unlock;
+       default:
+               goto out_unreg_unlock;
+       }
+       /* check if the device id has changed */
+       if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
+               CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from "
+                             "%04x to %04x)\n", dev_name(&sch->dev),
+                             cdev->private->dev_id.devno,
+                             sch->schib.pmcw.dev);
+               goto out_unreg_unlock;
+       }
+       /* check if the device type has changed */
+       if (!ccw_device_test_sense_data(cdev)) {
+               ccw_device_update_sense_data(cdev);
+               PREPARE_WORK(&cdev->private->kick_work,
+                            ccw_device_do_unbind_bind);
+               queue_work(ccw_device_work, &cdev->private->kick_work);
+               ret = -ENODEV;
+               goto out_unlock;
+       }
+       if (!cdev->online) {
+               ret = 0;
+               goto out_unlock;
+       }
+       ret = ccw_device_online(cdev);
+       if (ret)
+               goto out_disc_unlock;
+
+       cm_enabled = cdev->private->cmb != NULL;
+       spin_unlock_irq(sch->lock);
+
+       wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
+       if (cdev->private->state != DEV_STATE_ONLINE) {
+               spin_lock_irq(sch->lock);
+               goto out_disc_unlock;
+       }
+       if (cm_enabled) {
+               ret = ccw_set_cmf(cdev, 1);
+               if (ret) {
+                       CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed "
+                                     "(rc=%d)\n", dev_name(&cdev->dev), ret);
+                       ret = 0;
+               }
+       }
+
+out_restore:
+       if (cdev->online && cdev->drv && cdev->drv->restore)
+               ret = cdev->drv->restore(cdev);
+out:
+       return ret;
+
+out_disc_unlock:
+       ret = resume_handle_disc(cdev);
+       spin_unlock_irq(sch->lock);
+       if (ret)
+               return ret;
+       goto out_restore;
+
+out_unreg_unlock:
+       ccw_device_schedule_sch_unregister(cdev);
+       ret = -ENODEV;
+out_unlock:
+       spin_unlock_irq(sch->lock);
+       return ret;
+}
+
+static struct dev_pm_ops ccw_pm_ops = {
+       .prepare = ccw_device_pm_prepare,
+       .complete = ccw_device_pm_complete,
+       .freeze = ccw_device_pm_freeze,
+       .thaw = ccw_device_pm_thaw,
+       .restore = ccw_device_pm_restore,
+};
+
 struct bus_type ccw_bus_type = {
        .name   = "ccw",
        .match  = ccw_bus_match,
@@ -1902,6 +2161,7 @@ struct bus_type ccw_bus_type = {
        .probe  = ccw_device_probe,
        .remove = ccw_device_remove,
        .shutdown = ccw_device_shutdown,
+       .pm = &ccw_pm_ops,
 };
 
 /**
index f1cbbd94ad4e76fbaaba927b1988ede2107d515c..e3975107a5787fa314b0ec16feb7c1d313b2d1b1 100644 (file)
@@ -87,6 +87,8 @@ int ccw_device_is_orphan(struct ccw_device *);
 int ccw_device_recognition(struct ccw_device *);
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
+void ccw_device_update_sense_data(struct ccw_device *);
+int ccw_device_test_sense_data(struct ccw_device *);
 void ccw_device_schedule_sch_unregister(struct ccw_device *);
 int ccw_purge_blacklisted(void);
 
@@ -133,5 +135,6 @@ extern struct bus_type ccw_bus_type;
 void retry_set_schib(struct ccw_device *cdev);
 void cmf_retry_copy_block(struct ccw_device *);
 int cmf_reenable(struct ccw_device *);
+int ccw_set_cmf(struct ccw_device *cdev, int enable);
 extern struct device_attribute dev_attr_cmb_enable;
 #endif
index e46049261561986174c8448714e811ef6344a092..3db88c52d2879e9dc4cac73dd40e4967f5719e5a 100644 (file)
@@ -177,29 +177,21 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
        panic("Can't stop i/o on subchannel.\n");
 }
 
-static int
-ccw_device_handle_oper(struct ccw_device *cdev)
+void ccw_device_update_sense_data(struct ccw_device *cdev)
 {
-       struct subchannel *sch;
+       memset(&cdev->id, 0, sizeof(cdev->id));
+       cdev->id.cu_type   = cdev->private->senseid.cu_type;
+       cdev->id.cu_model  = cdev->private->senseid.cu_model;
+       cdev->id.dev_type  = cdev->private->senseid.dev_type;
+       cdev->id.dev_model = cdev->private->senseid.dev_model;
+}
 
-       sch = to_subchannel(cdev->dev.parent);
-       cdev->private->flags.recog_done = 1;
-       /*
-        * Check if cu type and device type still match. If
-        * not, it is certainly another device and we have to
-        * de- and re-register.
-        */
-       if (cdev->id.cu_type != cdev->private->senseid.cu_type ||
-           cdev->id.cu_model != cdev->private->senseid.cu_model ||
-           cdev->id.dev_type != cdev->private->senseid.dev_type ||
-           cdev->id.dev_model != cdev->private->senseid.dev_model) {
-               PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_do_unbind_bind);
-               queue_work(ccw_device_work, &cdev->private->kick_work);
-               return 0;
-       }
-       cdev->private->flags.donotify = 1;
-       return 1;
+int ccw_device_test_sense_data(struct ccw_device *cdev)
+{
+       return cdev->id.cu_type == cdev->private->senseid.cu_type &&
+               cdev->id.cu_model == cdev->private->senseid.cu_model &&
+               cdev->id.dev_type == cdev->private->senseid.dev_type &&
+               cdev->id.dev_model == cdev->private->senseid.dev_model;
 }
 
 /*
@@ -233,7 +225,7 @@ static void
 ccw_device_recog_done(struct ccw_device *cdev, int state)
 {
        struct subchannel *sch;
-       int notify, old_lpm, same_dev;
+       int old_lpm;
 
        sch = to_subchannel(cdev->dev.parent);
 
@@ -263,8 +255,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                wake_up(&cdev->private->wait_q);
                return;
        }
-       notify = 0;
-       same_dev = 0; /* Keep the compiler quiet... */
+       if (cdev->private->flags.resuming) {
+               cdev->private->state = state;
+               cdev->private->flags.recog_done = 1;
+               wake_up(&cdev->private->wait_q);
+               return;
+       }
        switch (state) {
        case DEV_STATE_NOT_OPER:
                CIO_MSG_EVENT(2, "SenseID : unknown device %04x on "
@@ -273,34 +269,31 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                              sch->schid.ssid, sch->schid.sch_no);
                break;
        case DEV_STATE_OFFLINE:
-               if (cdev->online) {
-                       same_dev = ccw_device_handle_oper(cdev);
-                       notify = 1;
+               if (!cdev->online) {
+                       ccw_device_update_sense_data(cdev);
+                       /* Issue device info message. */
+                       CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: "
+                                     "CU  Type/Mod = %04X/%02X, Dev Type/Mod "
+                                     "= %04X/%02X\n",
+                                     cdev->private->dev_id.ssid,
+                                     cdev->private->dev_id.devno,
+                                     cdev->id.cu_type, cdev->id.cu_model,
+                                     cdev->id.dev_type, cdev->id.dev_model);
+                       break;
                }
-               /* fill out sense information */
-               memset(&cdev->id, 0, sizeof(cdev->id));
-               cdev->id.cu_type   = cdev->private->senseid.cu_type;
-               cdev->id.cu_model  = cdev->private->senseid.cu_model;
-               cdev->id.dev_type  = cdev->private->senseid.dev_type;
-               cdev->id.dev_model = cdev->private->senseid.dev_model;
-               if (notify) {
-                       cdev->private->state = DEV_STATE_OFFLINE;
-                       if (same_dev) {
-                               /* Get device online again. */
-                               ccw_device_online(cdev);
-                               wake_up(&cdev->private->wait_q);
-                       }
-                       return;
+               cdev->private->state = DEV_STATE_OFFLINE;
+               cdev->private->flags.recog_done = 1;
+               if (ccw_device_test_sense_data(cdev)) {
+                       cdev->private->flags.donotify = 1;
+                       ccw_device_online(cdev);
+                       wake_up(&cdev->private->wait_q);
+               } else {
+                       ccw_device_update_sense_data(cdev);
+                       PREPARE_WORK(&cdev->private->kick_work,
+                                    ccw_device_do_unbind_bind);
+                       queue_work(ccw_device_work, &cdev->private->kick_work);
                }
-               /* Issue device info message. */
-               CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: "
-                             "CU  Type/Mod = %04X/%02X, Dev Type/Mod = "
-                             "%04X/%02X\n",
-                             cdev->private->dev_id.ssid,
-                             cdev->private->dev_id.devno,
-                             cdev->id.cu_type, cdev->id.cu_model,
-                             cdev->id.dev_type, cdev->id.dev_model);
-               break;
+               return;
        case DEV_STATE_BOXED:
                CIO_MSG_EVENT(0, "SenseID : boxed device %04x on "
                              " subchannel 0.%x.%04x\n",
@@ -502,9 +495,6 @@ ccw_device_recognition(struct ccw_device *cdev)
        struct subchannel *sch;
        int ret;
 
-       if ((cdev->private->state != DEV_STATE_NOT_OPER) &&
-           (cdev->private->state != DEV_STATE_BOXED))
-               return -EINVAL;
        sch = to_subchannel(cdev->dev.parent);
        ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
        if (ret != 0)
index bf0a24af39a0542be842f5705cc49ec58da63b2f..2d0efee8a290c54ff9564a156ae05cb8c952a7bd 100644 (file)
@@ -1,10 +1,8 @@
 /*
- *  drivers/s390/cio/device_ops.c
+ * Copyright IBM Corp. 2002, 2009
  *
- *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
- *                      IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
- *               Cornelia Huck (cornelia.huck@de.ibm.com)
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *           Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -116,12 +114,15 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
 
        if (!cdev || !cdev->dev.parent)
                return -ENODEV;
+       sch = to_subchannel(cdev->dev.parent);
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE &&
            cdev->private->state != DEV_STATE_W4SENSE)
                return -EINVAL;
-       sch = to_subchannel(cdev->dev.parent);
+
        ret = cio_clear(sch);
        if (ret == 0)
                cdev->private->intparm = intparm;
@@ -162,6 +163,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
        if (!cdev || !cdev->dev.parent)
                return -ENODEV;
        sch = to_subchannel(cdev->dev.parent);
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
        if (cdev->private->state == DEV_STATE_VERIFY ||
@@ -337,12 +340,15 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
 
        if (!cdev || !cdev->dev.parent)
                return -ENODEV;
+       sch = to_subchannel(cdev->dev.parent);
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE &&
            cdev->private->state != DEV_STATE_W4SENSE)
                return -EINVAL;
-       sch = to_subchannel(cdev->dev.parent);
+
        ret = cio_halt(sch);
        if (ret == 0)
                cdev->private->intparm = intparm;
@@ -369,6 +375,8 @@ int ccw_device_resume(struct ccw_device *cdev)
        if (!cdev || !cdev->dev.parent)
                return -ENODEV;
        sch = to_subchannel(cdev->dev.parent);
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE ||
@@ -580,6 +588,8 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
        int rc;
 
        sch = to_subchannel(cdev->dev.parent);
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state != DEV_STATE_ONLINE)
                return -EIO;
        /* Adjust requested path mask to excluded varied off paths. */
@@ -669,6 +679,8 @@ int ccw_device_tm_intrg(struct ccw_device *cdev)
 {
        struct subchannel *sch = to_subchannel(cdev->dev.parent);
 
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state != DEV_STATE_ONLINE)
                return -EIO;
        if (!scsw_is_tm(&sch->schib.scsw) ||
index c4f3e7c9a85482996dbd41b4249651d108be2e4f..0b8f381bd20e888f8ad7ad1c46f9da229337fab6 100644 (file)
@@ -107,6 +107,7 @@ struct ccw_device_private {
                unsigned int recog_done:1;  /* dev. recog. complete */
                unsigned int fake_irb:1;    /* deliver faked irb */
                unsigned int intretry:1;    /* retry internal operation */
+               unsigned int resuming:1;    /* recognition while resume */
        } __attribute__((packed)) flags;
        unsigned long intparm;  /* user interruption parameter */
        struct qdio_irq *qdio_data;
index 7b6f46ddf3c304146b5b7e0afd34233f34b01b42..f370f8d460a721674f5537d79c8e528d23bb4b5e 100644 (file)
@@ -3,12 +3,12 @@
  *    ESCON CLAW network driver
  *
  *  Linux for zSeries version
- *    Copyright (C) 2002,2005 IBM Corporation
+ *    Copyright IBM Corp. 2002, 2009
  *  Author(s) Original code written by:
- *              Kazuo Iimura (iimura@jp.ibm.com)
+ *             Kazuo Iimura <iimura@jp.ibm.com>
  *           Rewritten by
- *              Andy Richter (richtera@us.ibm.com)
- *              Marc Price (mwprice@us.ibm.com)
+ *             Andy Richter <richtera@us.ibm.com>
+ *             Marc Price <mwprice@us.ibm.com>
  *
  *    sysfs parms:
  *   group x.x.rrrr,x.x.wwww
@@ -253,6 +253,11 @@ static void claw_free_wrt_buf(struct net_device *dev);
 /* Functions for unpack reads   */
 static void unpack_read(struct net_device *dev);
 
+static int claw_pm_prepare(struct ccwgroup_device *gdev)
+{
+       return -EPERM;
+}
+
 /* ccwgroup table  */
 
 static struct ccwgroup_driver claw_group_driver = {
@@ -264,6 +269,7 @@ static struct ccwgroup_driver claw_group_driver = {
         .remove      = claw_remove_device,
         .set_online  = claw_new_device,
         .set_offline = claw_shutdown_device,
+       .prepare     = claw_pm_prepare,
 };
 
 /*
@@ -284,7 +290,7 @@ claw_probe(struct ccwgroup_device *cgdev)
        if (!get_device(&cgdev->dev))
                return -ENODEV;
        privptr = kzalloc(sizeof(struct claw_privbk), GFP_KERNEL);
-       cgdev->dev.driver_data = privptr;
+       dev_set_drvdata(&cgdev->dev, privptr);
        if (privptr == NULL) {
                probe_error(cgdev);
                put_device(&cgdev->dev);
@@ -591,14 +597,14 @@ claw_irq_handler(struct ccw_device *cdev,
 
        CLAW_DBF_TEXT(4, trace, "clawirq");
         /* Bypass all 'unsolicited interrupts' */
-       if (!cdev->dev.driver_data) {
+       privptr = dev_get_drvdata(&cdev->dev);
+       if (!privptr) {
                dev_warn(&cdev->dev, "An uninitialized CLAW device received an"
                        " IRQ, c-%02x d-%02x\n",
                        irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
                CLAW_DBF_TEXT(2, trace, "badirq");
                 return;
         }
-       privptr = (struct claw_privbk *)cdev->dev.driver_data;
 
        /* Try to extract channel from driver data. */
        if (privptr->channel[READ].cdev == cdev)
@@ -1980,9 +1986,9 @@ probe_error( struct ccwgroup_device *cgdev)
        struct claw_privbk *privptr;
 
        CLAW_DBF_TEXT(4, trace, "proberr");
-       privptr = (struct claw_privbk *) cgdev->dev.driver_data;
+       privptr = dev_get_drvdata(&cgdev->dev);
        if (privptr != NULL) {
-               cgdev->dev.driver_data = NULL;
+               dev_set_drvdata(&cgdev->dev, NULL);
                kfree(privptr->p_env);
                kfree(privptr->p_mtc_envelope);
                kfree(privptr);
@@ -2911,9 +2917,9 @@ claw_new_device(struct ccwgroup_device *cgdev)
        dev_info(&cgdev->dev, "add for %s\n",
                 dev_name(&cgdev->cdev[READ]->dev));
        CLAW_DBF_TEXT(2, setup, "new_dev");
-       privptr = cgdev->dev.driver_data;
-       cgdev->cdev[READ]->dev.driver_data = privptr;
-       cgdev->cdev[WRITE]->dev.driver_data = privptr;
+       privptr = dev_get_drvdata(&cgdev->dev);
+       dev_set_drvdata(&cgdev->cdev[READ]->dev, privptr);
+       dev_set_drvdata(&cgdev->cdev[WRITE]->dev, privptr);
        if (!privptr)
                return -ENODEV;
        p_env = privptr->p_env;
@@ -2950,9 +2956,9 @@ claw_new_device(struct ccwgroup_device *cgdev)
                goto out;
        }
        dev->ml_priv = privptr;
-       cgdev->dev.driver_data = privptr;
-        cgdev->cdev[READ]->dev.driver_data = privptr;
-        cgdev->cdev[WRITE]->dev.driver_data = privptr;
+       dev_set_drvdata(&cgdev->dev, privptr);
+       dev_set_drvdata(&cgdev->cdev[READ]->dev, privptr);
+       dev_set_drvdata(&cgdev->cdev[WRITE]->dev, privptr);
        /* sysfs magic */
         SET_NETDEV_DEV(dev, &cgdev->dev);
        if (register_netdev(dev) != 0) {
@@ -3018,7 +3024,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev)
        int     ret;
 
        CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev));
-       priv = cgdev->dev.driver_data;
+       priv = dev_get_drvdata(&cgdev->dev);
        if (!priv)
                return -ENODEV;
        ndev = priv->channel[READ].ndev;
@@ -3048,7 +3054,7 @@ claw_remove_device(struct ccwgroup_device *cgdev)
 
        BUG_ON(!cgdev);
        CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev));
-       priv = cgdev->dev.driver_data;
+       priv = dev_get_drvdata(&cgdev->dev);
        BUG_ON(!priv);
        dev_info(&cgdev->dev, " will be removed.\n");
        if (cgdev->state == CCWGROUP_ONLINE)
@@ -3063,9 +3069,9 @@ claw_remove_device(struct ccwgroup_device *cgdev)
        kfree(priv->channel[1].irb);
        priv->channel[1].irb=NULL;
        kfree(priv);
-       cgdev->dev.driver_data=NULL;
-       cgdev->cdev[READ]->dev.driver_data = NULL;
-       cgdev->cdev[WRITE]->dev.driver_data = NULL;
+       dev_set_drvdata(&cgdev->dev, NULL);
+       dev_set_drvdata(&cgdev->cdev[READ]->dev, NULL);
+       dev_set_drvdata(&cgdev->cdev[WRITE]->dev, NULL);
        put_device(&cgdev->dev);
 
        return;
@@ -3081,7 +3087,7 @@ claw_hname_show(struct device *dev, struct device_attribute *attr, char *buf)
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3095,7 +3101,7 @@ claw_hname_write(struct device *dev, struct device_attribute *attr,
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3119,7 +3125,7 @@ claw_adname_show(struct device *dev, struct device_attribute *attr, char *buf)
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3133,7 +3139,7 @@ claw_adname_write(struct device *dev, struct device_attribute *attr,
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3157,7 +3163,7 @@ claw_apname_show(struct device *dev, struct device_attribute *attr, char *buf)
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3172,7 +3178,7 @@ claw_apname_write(struct device *dev, struct device_attribute *attr,
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3206,7 +3212,7 @@ claw_wbuff_show(struct device *dev, struct device_attribute *attr, char *buf)
        struct claw_privbk *priv;
        struct claw_env * p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3221,7 +3227,7 @@ claw_wbuff_write(struct device *dev, struct device_attribute *attr,
        struct claw_env *  p_env;
        int nnn,max;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3248,7 +3254,7 @@ claw_rbuff_show(struct device *dev, struct device_attribute *attr, char *buf)
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3263,7 +3269,7 @@ claw_rbuff_write(struct device *dev, struct device_attribute *attr,
        struct claw_env *p_env;
        int nnn,max;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
index 54c4649a493bd27399f107032926662a79370d15..222e4739443715902dd5e5ce38b1f5a924b4e3cb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * drivers/s390/net/ctcm_main.c
  *
- * Copyright IBM Corp. 2001, 2007
+ * Copyright IBM Corp. 2001, 2009
  * Author(s):
  *     Original CTC driver(s):
  *             Fritz Elfert (felfert@millenux.com)
@@ -1688,6 +1688,38 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev)
        put_device(&cgdev->dev);
 }
 
+static int ctcm_pm_suspend(struct ccwgroup_device *gdev)
+{
+       struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev);
+
+       if (gdev->state == CCWGROUP_OFFLINE)
+               return 0;
+       netif_device_detach(priv->channel[READ]->netdev);
+       ctcm_close(priv->channel[READ]->netdev);
+       ccw_device_set_offline(gdev->cdev[1]);
+       ccw_device_set_offline(gdev->cdev[0]);
+       return 0;
+}
+
+static int ctcm_pm_resume(struct ccwgroup_device *gdev)
+{
+       struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev);
+       int rc;
+
+       if (gdev->state == CCWGROUP_OFFLINE)
+               return 0;
+       rc = ccw_device_set_online(gdev->cdev[1]);
+       if (rc)
+               goto err_out;
+       rc = ccw_device_set_online(gdev->cdev[0]);
+       if (rc)
+               goto err_out;
+       ctcm_open(priv->channel[READ]->netdev);
+err_out:
+       netif_device_attach(priv->channel[READ]->netdev);
+       return rc;
+}
+
 static struct ccwgroup_driver ctcm_group_driver = {
        .owner       = THIS_MODULE,
        .name        = CTC_DRIVER_NAME,
@@ -1697,6 +1729,9 @@ static struct ccwgroup_driver ctcm_group_driver = {
        .remove      = ctcm_remove_device,
        .set_online  = ctcm_new_device,
        .set_offline = ctcm_shutdown_device,
+       .freeze      = ctcm_pm_suspend,
+       .thaw        = ctcm_pm_resume,
+       .restore     = ctcm_pm_resume,
 };
 
 
index a45bc24eb5f91627c03eabc94575a71ed0a6053f..8c675905448b74c33983c7e5038e4b8688a15ce0 100644 (file)
@@ -1,15 +1,12 @@
 /*
- *  linux/drivers/s390/net/lcs.c
- *
  *  Linux for S/390 Lan Channel Station Network Driver
  *
- *  Copyright (C)  1999-2001 IBM Deutschland Entwicklung GmbH,
- *                          IBM Corporation
- *    Author(s): Original Code written by
- *                       DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- *              Rewritten by
- *                       Frank Pavlic (fpavlic@de.ibm.com) and
- *                       Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *  Copyright IBM Corp. 1999, 2009
+ *  Author(s): Original Code written by
+ *                     DJ Barrow <djbarrow@de.ibm.com,barrow_dj@yahoo.com>
+ *            Rewritten by
+ *                     Frank Pavlic <fpavlic@de.ibm.com> and
+ *                     Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -1939,7 +1936,7 @@ lcs_portno_show (struct device *dev, struct device_attribute *attr, char *buf)
 {
         struct lcs_card *card;
 
-       card = (struct lcs_card *)dev->driver_data;
+       card = dev_get_drvdata(dev);
 
         if (!card)
                 return 0;
@@ -1956,7 +1953,7 @@ lcs_portno_store (struct device *dev, struct device_attribute *attr, const char
         struct lcs_card *card;
         int value;
 
-       card = (struct lcs_card *)dev->driver_data;
+       card = dev_get_drvdata(dev);
 
         if (!card)
                 return 0;
@@ -1990,7 +1987,7 @@ lcs_timeout_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct lcs_card *card;
 
-       card = (struct lcs_card *)dev->driver_data;
+       card = dev_get_drvdata(dev);
 
        return card ? sprintf(buf, "%u\n", card->lancmd_timeout) : 0;
 }
@@ -2001,7 +1998,7 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char
         struct lcs_card *card;
         int value;
 
-       card = (struct lcs_card *)dev->driver_data;
+       card = dev_get_drvdata(dev);
 
         if (!card)
                 return 0;
@@ -2020,7 +2017,7 @@ static ssize_t
 lcs_dev_recover_store(struct device *dev, struct device_attribute *attr,
                      const char *buf, size_t count)
 {
-       struct lcs_card *card = dev->driver_data;
+       struct lcs_card *card = dev_get_drvdata(dev);
        char *tmp;
        int i;
 
@@ -2073,7 +2070,7 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev)
                put_device(&ccwgdev->dev);
                return ret;
         }
-       ccwgdev->dev.driver_data = card;
+       dev_set_drvdata(&ccwgdev->dev, card);
        ccwgdev->cdev[0]->handler = lcs_irq;
        ccwgdev->cdev[1]->handler = lcs_irq;
        card->gdev = ccwgdev;
@@ -2090,7 +2087,7 @@ lcs_register_netdev(struct ccwgroup_device *ccwgdev)
        struct lcs_card *card;
 
        LCS_DBF_TEXT(2, setup, "regnetdv");
-       card = (struct lcs_card *)ccwgdev->dev.driver_data;
+       card = dev_get_drvdata(&ccwgdev->dev);
        if (card->dev->reg_state != NETREG_UNINITIALIZED)
                return 0;
        SET_NETDEV_DEV(card->dev, &ccwgdev->dev);
@@ -2123,7 +2120,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
        enum lcs_dev_states recover_state;
        int rc;
 
-       card = (struct lcs_card *)ccwgdev->dev.driver_data;
+       card = dev_get_drvdata(&ccwgdev->dev);
        if (!card)
                return -ENODEV;
 
@@ -2229,7 +2226,7 @@ __lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode)
        int ret;
 
        LCS_DBF_TEXT(3, setup, "shtdndev");
-       card = (struct lcs_card *)ccwgdev->dev.driver_data;
+       card = dev_get_drvdata(&ccwgdev->dev);
        if (!card)
                return -ENODEV;
        if (recovery_mode == 0) {
@@ -2296,7 +2293,7 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev)
 {
        struct lcs_card *card;
 
-       card = (struct lcs_card *)ccwgdev->dev.driver_data;
+       card = dev_get_drvdata(&ccwgdev->dev);
        if (!card)
                return;
 
@@ -2313,6 +2310,60 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev)
        put_device(&ccwgdev->dev);
 }
 
+static int lcs_pm_suspend(struct lcs_card *card)
+{
+       if (card->dev)
+               netif_device_detach(card->dev);
+       lcs_set_allowed_threads(card, 0);
+       lcs_wait_for_threads(card, 0xffffffff);
+       if (card->state != DEV_STATE_DOWN)
+               __lcs_shutdown_device(card->gdev, 1);
+       return 0;
+}
+
+static int lcs_pm_resume(struct lcs_card *card)
+{
+       int rc = 0;
+
+       if (card->state == DEV_STATE_RECOVER)
+               rc = lcs_new_device(card->gdev);
+       if (card->dev)
+               netif_device_attach(card->dev);
+       if (rc) {
+               dev_warn(&card->gdev->dev, "The lcs device driver "
+                       "failed to recover the device\n");
+       }
+       return rc;
+}
+
+static int lcs_prepare(struct ccwgroup_device *gdev)
+{
+       return 0;
+}
+
+static void lcs_complete(struct ccwgroup_device *gdev)
+{
+       return;
+}
+
+static int lcs_freeze(struct ccwgroup_device *gdev)
+{
+       struct lcs_card *card = dev_get_drvdata(&gdev->dev);
+       return lcs_pm_suspend(card);
+}
+
+static int lcs_thaw(struct ccwgroup_device *gdev)
+{
+       struct lcs_card *card = dev_get_drvdata(&gdev->dev);
+       return lcs_pm_resume(card);
+}
+
+static int lcs_restore(struct ccwgroup_device *gdev)
+{
+       struct lcs_card *card = dev_get_drvdata(&gdev->dev);
+       return lcs_pm_resume(card);
+}
+
 /**
  * LCS ccwgroup driver registration
  */
@@ -2325,6 +2376,11 @@ static struct ccwgroup_driver lcs_group_driver = {
        .remove      = lcs_remove_device,
        .set_online  = lcs_new_device,
        .set_offline = lcs_shutdown_device,
+       .prepare     = lcs_prepare,
+       .complete    = lcs_complete,
+       .freeze      = lcs_freeze,
+       .thaw        = lcs_thaw,
+       .restore     = lcs_restore,
 };
 
 /**
index d58fea52557dd4338afffcdf06fb93f4d88ae710..6d668642af270e27b6b376ce99c2b3276cbc63a8 100644 (file)
@@ -34,8 +34,8 @@ static inline int lcs_dbf_passes(debug_info_t *dbf_grp, int level)
  *     sysfs related stuff
  */
 #define CARD_FROM_DEV(cdev) \
-       (struct lcs_card *) \
-       ((struct ccwgroup_device *)cdev->dev.driver_data)->dev.driver_data;
+       (struct lcs_card *) dev_get_drvdata( \
+               &((struct ccwgroup_device *)dev_get_drvdata(&cdev->dev))->dev);
 /**
  * CCW commands used in this driver
  */
index aec9e5d3cf4b72ef7830435fccf8c3c708df31b5..52574ce797b24f92e91edf49c20174d08fca28ed 100644 (file)
@@ -1,11 +1,15 @@
 /*
  * IUCV network driver
  *
- * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
+ * Copyright IBM Corp. 2001, 2009
  *
- * Sysfs integration and all bugs therein by Cornelia Huck
- * (cornelia.huck@de.ibm.com)
+ * Author(s):
+ *     Original netiucv driver:
+ *             Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
+ *     Sysfs integration and all bugs therein:
+ *             Cornelia Huck (cornelia.huck@de.ibm.com)
+ *     PM functions:
+ *             Ursula Braun (ursula.braun@de.ibm.com)
  *
  * Documentation used:
  *  the source of the original IUCV driver by:
@@ -149,10 +153,27 @@ PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
 
 #define PRINTK_HEADER " iucv: "       /* for debugging */
 
+/* dummy device to make sure netiucv_pm functions are called */
+static struct device *netiucv_dev;
+
+static int netiucv_pm_prepare(struct device *);
+static void netiucv_pm_complete(struct device *);
+static int netiucv_pm_freeze(struct device *);
+static int netiucv_pm_restore_thaw(struct device *);
+
+static struct dev_pm_ops netiucv_pm_ops = {
+       .prepare = netiucv_pm_prepare,
+       .complete = netiucv_pm_complete,
+       .freeze = netiucv_pm_freeze,
+       .thaw = netiucv_pm_restore_thaw,
+       .restore = netiucv_pm_restore_thaw,
+};
+
 static struct device_driver netiucv_driver = {
        .owner = THIS_MODULE,
        .name = "netiucv",
        .bus  = &iucv_bus,
+       .pm = &netiucv_pm_ops,
 };
 
 static int netiucv_callback_connreq(struct iucv_path *,
@@ -233,6 +254,7 @@ struct netiucv_priv {
        fsm_instance            *fsm;
         struct iucv_connection  *conn;
        struct device           *dev;
+       int                      pm_state;
 };
 
 /**
@@ -1265,6 +1287,72 @@ static int netiucv_close(struct net_device *dev)
        return 0;
 }
 
+static int netiucv_pm_prepare(struct device *dev)
+{
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       return 0;
+}
+
+static void netiucv_pm_complete(struct device *dev)
+{
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       return;
+}
+
+/**
+ * netiucv_pm_freeze() - Freeze PM callback
+ * @dev:       netiucv device
+ *
+ * close open netiucv interfaces
+ */
+static int netiucv_pm_freeze(struct device *dev)
+{
+       struct netiucv_priv *priv = dev->driver_data;
+       struct net_device *ndev = NULL;
+       int rc = 0;
+
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       if (priv && priv->conn)
+               ndev = priv->conn->netdev;
+       if (!ndev)
+               goto out;
+       netif_device_detach(ndev);
+       priv->pm_state = fsm_getstate(priv->fsm);
+       rc = netiucv_close(ndev);
+out:
+       return rc;
+}
+
+/**
+ * netiucv_pm_restore_thaw() - Thaw and restore PM callback
+ * @dev:       netiucv device
+ *
+ * re-open netiucv interfaces closed during freeze
+ */
+static int netiucv_pm_restore_thaw(struct device *dev)
+{
+       struct netiucv_priv *priv = dev->driver_data;
+       struct net_device *ndev = NULL;
+       int rc = 0;
+
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       if (priv && priv->conn)
+               ndev = priv->conn->netdev;
+       if (!ndev)
+               goto out;
+       switch (priv->pm_state) {
+       case DEV_STATE_RUNNING:
+       case DEV_STATE_STARTWAIT:
+               rc = netiucv_open(ndev);
+               break;
+       default:
+               break;
+       }
+       netif_device_attach(ndev);
+out:
+       return rc;
+}
+
 /**
  * Start transmission of a packet.
  * Called from generic network device layer.
@@ -1364,7 +1452,7 @@ static int netiucv_change_mtu(struct net_device * dev, int new_mtu)
 static ssize_t user_show(struct device *dev, struct device_attribute *attr,
                         char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid));
@@ -1373,7 +1461,7 @@ static ssize_t user_show(struct device *dev, struct device_attribute *attr,
 static ssize_t user_write(struct device *dev, struct device_attribute *attr,
                          const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->conn->netdev;
        char    *p;
        char    *tmp;
@@ -1430,7 +1518,8 @@ static DEVICE_ATTR(user, 0644, user_show, user_write);
 
 static ssize_t buffer_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
-{      struct netiucv_priv *priv = dev->driver_data;
+{
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%d\n", priv->conn->max_buffsize);
@@ -1439,7 +1528,7 @@ static ssize_t buffer_show (struct device *dev, struct device_attribute *attr,
 static ssize_t buffer_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->conn->netdev;
        char         *e;
        int          bs1;
@@ -1487,7 +1576,7 @@ static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
 static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%s\n", fsm_getstate_str(priv->fsm));
@@ -1498,7 +1587,7 @@ static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL);
 static ssize_t conn_fsm_show (struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%s\n", fsm_getstate_str(priv->conn->fsm));
@@ -1509,7 +1598,7 @@ static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL);
 static ssize_t maxmulti_show (struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti);
@@ -1519,7 +1608,7 @@ static ssize_t maxmulti_write (struct device *dev,
                               struct device_attribute *attr,
                               const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.maxmulti = 0;
@@ -1531,7 +1620,7 @@ static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write);
 static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue);
@@ -1540,7 +1629,7 @@ static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr,
 static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.maxcqueue = 0;
@@ -1552,7 +1641,7 @@ static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write);
 static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.doios_single);
@@ -1561,7 +1650,7 @@ static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr,
 static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.doios_single = 0;
@@ -1573,7 +1662,7 @@ static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write);
 static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi);
@@ -1582,7 +1671,7 @@ static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr,
 static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        priv->conn->prof.doios_multi = 0;
@@ -1594,7 +1683,7 @@ static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write);
 static ssize_t txlen_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.txlen);
@@ -1603,7 +1692,7 @@ static ssize_t txlen_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txlen_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.txlen = 0;
@@ -1615,7 +1704,7 @@ static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write);
 static ssize_t txtime_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.tx_time);
@@ -1624,7 +1713,7 @@ static ssize_t txtime_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txtime_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.tx_time = 0;
@@ -1636,7 +1725,7 @@ static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write);
 static ssize_t txpend_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending);
@@ -1645,7 +1734,7 @@ static ssize_t txpend_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txpend_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.tx_pending = 0;
@@ -1657,7 +1746,7 @@ static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write);
 static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending);
@@ -1666,7 +1755,7 @@ static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.tx_max_pending = 0;
@@ -1731,7 +1820,6 @@ static int netiucv_register_device(struct net_device *ndev)
        struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
        int ret;
 
-
        IUCV_DBF_TEXT(trace, 3, __func__);
 
        if (dev) {
@@ -1758,7 +1846,7 @@ static int netiucv_register_device(struct net_device *ndev)
        if (ret)
                goto out_unreg;
        priv->dev = dev;
-       dev->driver_data = priv;
+       dev_set_drvdata(dev, priv);
        return 0;
 
 out_unreg:
@@ -2100,6 +2188,7 @@ static void __exit netiucv_exit(void)
                netiucv_unregister_device(dev);
        }
 
+       device_unregister(netiucv_dev);
        driver_unregister(&netiucv_driver);
        iucv_unregister(&netiucv_handler, 1);
        iucv_unregister_dbf_views();
@@ -2125,10 +2214,25 @@ static int __init netiucv_init(void)
                IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc);
                goto out_iucv;
        }
-
+       /* establish dummy device */
+       netiucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+       if (!netiucv_dev) {
+               rc = -ENOMEM;
+               goto out_driver;
+       }
+       dev_set_name(netiucv_dev, "netiucv");
+       netiucv_dev->bus = &iucv_bus;
+       netiucv_dev->parent = iucv_root;
+       netiucv_dev->release = (void (*)(struct device *))kfree;
+       netiucv_dev->driver = &netiucv_driver;
+       rc = device_register(netiucv_dev);
+       if (rc)
+               goto out_driver;
        netiucv_banner();
        return rc;
 
+out_driver:
+       driver_unregister(&netiucv_driver);
 out_iucv:
        iucv_unregister(&netiucv_handler, 1);
 out_dbf:
index 74c49d9a8dba2b76932b5f143bb8e66fb9458068..d53621c4acbbaca813ddd49e630cbf16582cd58e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/net/qeth_core_main.c
  *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007, 2009
  *    Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
  *              Frank Pavlic <fpavlic@de.ibm.com>,
  *              Thomas Spatzier <tspat@de.ibm.com>,
@@ -4195,6 +4195,50 @@ static void qeth_core_shutdown(struct ccwgroup_device *gdev)
                card->discipline.ccwgdriver->shutdown(gdev);
 }
 
+static int qeth_core_prepare(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->prepare)
+               return card->discipline.ccwgdriver->prepare(gdev);
+       return 0;
+}
+
+static void qeth_core_complete(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->complete)
+               card->discipline.ccwgdriver->complete(gdev);
+}
+
+static int qeth_core_freeze(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->freeze)
+               return card->discipline.ccwgdriver->freeze(gdev);
+       return 0;
+}
+
+static int qeth_core_thaw(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->thaw)
+               return card->discipline.ccwgdriver->thaw(gdev);
+       return 0;
+}
+
+static int qeth_core_restore(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->restore)
+               return card->discipline.ccwgdriver->restore(gdev);
+       return 0;
+}
+
 static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
        .owner = THIS_MODULE,
        .name = "qeth",
@@ -4204,6 +4248,11 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
        .set_online = qeth_core_set_online,
        .set_offline = qeth_core_set_offline,
        .shutdown = qeth_core_shutdown,
+       .prepare = qeth_core_prepare,
+       .complete = qeth_core_complete,
+       .freeze = qeth_core_freeze,
+       .thaw = qeth_core_thaw,
+       .restore = qeth_core_restore,
 };
 
 static ssize_t
index ecd3d06c0d5cc464b7c3ac90197e05a1bc3c17ce..81d7f268418a41aa4c1a52ac2c959fd570cee35f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/net/qeth_l2_main.c
  *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007, 2009
  *    Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
  *              Frank Pavlic <fpavlic@de.ibm.com>,
  *              Thomas Spatzier <tspat@de.ibm.com>,
@@ -1141,12 +1141,62 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
        qeth_clear_qdio_buffers(card);
 }
 
+static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+
+       if (card->dev)
+               netif_device_detach(card->dev);
+       qeth_set_allowed_threads(card, 0, 1);
+       wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
+       if (gdev->state == CCWGROUP_OFFLINE)
+               return 0;
+       if (card->state == CARD_STATE_UP) {
+               card->use_hard_stop = 1;
+               __qeth_l2_set_offline(card->gdev, 1);
+       } else
+               __qeth_l2_set_offline(card->gdev, 0);
+       return 0;
+}
+
+static int qeth_l2_pm_resume(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       int rc = 0;
+
+       if (gdev->state == CCWGROUP_OFFLINE)
+               goto out;
+
+       if (card->state == CARD_STATE_RECOVER) {
+               rc = __qeth_l2_set_online(card->gdev, 1);
+               if (rc) {
+                       if (card->dev) {
+                               rtnl_lock();
+                               dev_close(card->dev);
+                               rtnl_unlock();
+                       }
+               }
+       } else
+               rc = __qeth_l2_set_online(card->gdev, 0);
+out:
+       qeth_set_allowed_threads(card, 0xffffffff, 0);
+       if (card->dev)
+               netif_device_attach(card->dev);
+       if (rc)
+               dev_warn(&card->gdev->dev, "The qeth device driver "
+                       "failed to recover an error on the device\n");
+       return rc;
+}
+
 struct ccwgroup_driver qeth_l2_ccwgroup_driver = {
        .probe = qeth_l2_probe_device,
        .remove = qeth_l2_remove_device,
        .set_online = qeth_l2_set_online,
        .set_offline = qeth_l2_set_offline,
        .shutdown = qeth_l2_shutdown,
+       .freeze = qeth_l2_pm_suspend,
+       .thaw = qeth_l2_pm_resume,
+       .restore = qeth_l2_pm_resume,
 };
 EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver);
 
index 6f2386e9d6e2b2c8466da5e99c23496430cd8f65..54872406864e006bcccfb75549b2ffd39ed1f180 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/net/qeth_l3_main.c
  *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007, 2009
  *    Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
  *              Frank Pavlic <fpavlic@de.ibm.com>,
  *              Thomas Spatzier <tspat@de.ibm.com>,
@@ -3283,12 +3283,62 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev)
        qeth_clear_qdio_buffers(card);
 }
 
+static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+
+       if (card->dev)
+               netif_device_detach(card->dev);
+       qeth_set_allowed_threads(card, 0, 1);
+       wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
+       if (gdev->state == CCWGROUP_OFFLINE)
+               return 0;
+       if (card->state == CARD_STATE_UP) {
+               card->use_hard_stop = 1;
+               __qeth_l3_set_offline(card->gdev, 1);
+       } else
+               __qeth_l3_set_offline(card->gdev, 0);
+       return 0;
+}
+
+static int qeth_l3_pm_resume(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       int rc = 0;
+
+       if (gdev->state == CCWGROUP_OFFLINE)
+               goto out;
+
+       if (card->state == CARD_STATE_RECOVER) {
+               rc = __qeth_l3_set_online(card->gdev, 1);
+               if (rc) {
+                       if (card->dev) {
+                               rtnl_lock();
+                               dev_close(card->dev);
+                               rtnl_unlock();
+                       }
+               }
+       } else
+               rc = __qeth_l3_set_online(card->gdev, 0);
+out:
+       qeth_set_allowed_threads(card, 0xffffffff, 0);
+       if (card->dev)
+               netif_device_attach(card->dev);
+       if (rc)
+               dev_warn(&card->gdev->dev, "The qeth device driver "
+                       "failed to recover an error on the device\n");
+       return rc;
+}
+
 struct ccwgroup_driver qeth_l3_ccwgroup_driver = {
        .probe = qeth_l3_probe_device,
        .remove = qeth_l3_remove_device,
        .set_online = qeth_l3_set_online,
        .set_offline = qeth_l3_set_offline,
        .shutdown = qeth_l3_shutdown,
+       .freeze = qeth_l3_pm_suspend,
+       .thaw = qeth_l3_pm_resume,
+       .restore = qeth_l3_pm_resume,
 };
 EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver);
 
index 164e090c2625b03b8218c1e90286ca4b04b4559e..e76a320d373baeb99e32b16a9ac954ad65a00380 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * IUCV special message driver
  *
- * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2003, 2009
+ *
  * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  * This program is free software; you can redistribute it and/or modify
@@ -40,6 +41,8 @@ MODULE_AUTHOR
 MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
 
 static struct iucv_path *smsg_path;
+/* dummy device used as trigger for PM functions */
+static struct device *smsg_dev;
 
 static DEFINE_SPINLOCK(smsg_list_lock);
 static LIST_HEAD(smsg_list);
@@ -132,14 +135,51 @@ void smsg_unregister_callback(char *prefix,
        kfree(cb);
 }
 
+static int smsg_pm_freeze(struct device *dev)
+{
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "smsg_pm_freeze\n");
+#endif
+       if (smsg_path)
+               iucv_path_sever(smsg_path, NULL);
+       return 0;
+}
+
+static int smsg_pm_restore_thaw(struct device *dev)
+{
+       int rc;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "smsg_pm_restore_thaw\n");
+#endif
+       if (smsg_path) {
+               memset(smsg_path, 0, sizeof(*smsg_path));
+               smsg_path->msglim = 255;
+               smsg_path->flags = 0;
+               rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG    ",
+                                      NULL, NULL, NULL);
+               printk(KERN_ERR "iucv_path_connect returned with rc %i\n", rc);
+       }
+       return 0;
+}
+
+static struct dev_pm_ops smsg_pm_ops = {
+       .freeze = smsg_pm_freeze,
+       .thaw = smsg_pm_restore_thaw,
+       .restore = smsg_pm_restore_thaw,
+};
+
 static struct device_driver smsg_driver = {
+       .owner = THIS_MODULE,
        .name = "SMSGIUCV",
        .bus  = &iucv_bus,
+       .pm = &smsg_pm_ops,
 };
 
 static void __exit smsg_exit(void)
 {
        cpcmd("SET SMSG IUCV", NULL, 0, NULL);
+       device_unregister(smsg_dev);
        iucv_unregister(&smsg_handler, 1);
        driver_unregister(&smsg_driver);
 }
@@ -166,12 +206,29 @@ static int __init smsg_init(void)
        rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG    ",
                               NULL, NULL, NULL);
        if (rc)
-               goto out_free;
+               goto out_free_path;
+       smsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+       if (!smsg_dev) {
+               rc = -ENOMEM;
+               goto out_free_path;
+       }
+       dev_set_name(smsg_dev, "smsg_iucv");
+       smsg_dev->bus = &iucv_bus;
+       smsg_dev->parent = iucv_root;
+       smsg_dev->release = (void (*)(struct device *))kfree;
+       smsg_dev->driver = &smsg_driver;
+       rc = device_register(smsg_dev);
+       if (rc)
+               goto out_free_dev;
+
        cpcmd("SET SMSG IUCV", NULL, 0, NULL);
        return 0;
 
-out_free:
+out_free_dev:
+       kfree(smsg_dev);
+out_free_path:
        iucv_path_free(smsg_path);
+       smsg_path = NULL;
 out_register:
        iucv_unregister(&smsg_handler, 1);
 out_driver:
index b2fe5cdbcaeec3cb4462b22040fa6282bd70c7b5..d9da5c42ccbe6ca617bf4f304f0f9ecb1c058ef2 100644 (file)
 
 #define ZFCP_MODEL_PRIV 0x4
 
+static int zfcp_ccw_suspend(struct ccw_device *cdev)
+
+{
+       struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
+
+       down(&zfcp_data.config_sema);
+
+       zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL);
+       zfcp_erp_wait(adapter);
+
+       up(&zfcp_data.config_sema);
+
+       return 0;
+}
+
+static int zfcp_ccw_activate(struct ccw_device *cdev)
+
+{
+       struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
+
+       zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL,
+                                      ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
+       zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
+                               "ccresu2", NULL);
+       zfcp_erp_wait(adapter);
+       flush_work(&adapter->scan_work);
+
+       return 0;
+}
+
 static struct ccw_device_id zfcp_ccw_device_id[] = {
        { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) },
        { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) },
@@ -227,6 +257,9 @@ static struct ccw_driver zfcp_ccw_driver = {
        .set_offline = zfcp_ccw_set_offline,
        .notify      = zfcp_ccw_notify,
        .shutdown    = zfcp_ccw_shutdown,
+       .freeze      = zfcp_ccw_suspend,
+       .thaw        = zfcp_ccw_activate,
+       .restore     = zfcp_ccw_activate,
 };
 
 /**
index 124f660a0383173b8426fe9c9a1c7fd9e5fba0bb..75ac19b1192ff40d144fec752b7937b158abe86e 100644 (file)
@@ -303,7 +303,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
                                struct device_node *dp)
 {
        DATA *data = file->private_data;
-       struct openpromio *opp;
+       struct openpromio *opp = NULL;
        int bufsize, error = 0;
        static int cnt;
        void __user *argp = (void __user *)arg;
index ed0e3e55652afdec9c99d480458a5577e1e1a0d0..538135783aab017b0c2ba0ea782801912b0b93a1 100644 (file)
@@ -646,7 +646,7 @@ static int aha1740_probe (struct device *dev)
 
 static __devexit int aha1740_remove (struct device *dev)
 {
-       struct Scsi_Host *shpnt = dev->driver_data;
+       struct Scsi_Host *shpnt = dev_get_drvdata(dev);
        struct aha1740_hostdata *host = HOSTDATA (shpnt);
 
        scsi_remove_host(shpnt);
index 11d2602ae88ecd2ffd4c2ab8b759538dac8a02c8..869a11bdccbdf3cf63773b2bebc1ff1358d623a8 100644 (file)
@@ -1877,7 +1877,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        unsigned long wait_switch = 0;
        int rc;
 
-       vdev->dev.driver_data = NULL;
+       dev_set_drvdata(&vdev->dev, NULL);
 
        host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
        if (!host) {
@@ -1949,7 +1949,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
                        scsi_scan_host(host);
        }
 
-       vdev->dev.driver_data = hostdata;
+       dev_set_drvdata(&vdev->dev, hostdata);
        return 0;
 
       add_srp_port_failed:
@@ -1968,7 +1968,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 
 static int ibmvscsi_remove(struct vio_dev *vdev)
 {
-       struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
+       struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev);
        unmap_persist_bufs(hostdata);
        release_event_pool(&hostdata->pool, hostdata);
        ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
index e2dd6a45924a5f598f6dafa05eff545b2aa5292b..d5eaf972710978a9b24464c4e20fadbdac5babae 100644 (file)
@@ -892,7 +892,7 @@ free_vport:
 
 static int ibmvstgt_remove(struct vio_dev *dev)
 {
-       struct srp_target *target = (struct srp_target *) dev->dev.driver_data;
+       struct srp_target *target = dev_get_drvdata(&dev->dev);
        struct Scsi_Host *shost = target->shost;
        struct vio_port *vport = target->ldata;
 
index 15e2d132e8b9e07b99d39c4079557a3d16604cc3..2742ae8a3d091a13b989fb4f5a7de57e4f7d0490 100644 (file)
@@ -135,7 +135,7 @@ int srp_target_alloc(struct srp_target *target, struct device *dev,
        INIT_LIST_HEAD(&target->cmd_queue);
 
        target->dev = dev;
-       target->dev->driver_data = target;
+       dev_set_drvdata(target->dev, target);
 
        target->srp_iu_size = iu_size;
        target->rx_ring_size = nr;
index 2b02b1fb39a09842a1b18216699ac31b83eef3bb..8d0f0de76b6336098e3c76411002d1f8529244ae 100644 (file)
@@ -53,8 +53,7 @@
  * debugfs interface
  *
  * To access this interface the user should:
- * # mkdir /debug
- * # mount -t debugfs none /debug
+ * # mount -t debugfs none /sys/kernel/debug
  *
  * The lpfc debugfs directory hierarchy is:
  * lpfc/lpfcX/vportY
index b3497d7e5354dec9ab0ba49cd754f5e47867c45b..338b15c0a548e9f2d6d630d1ea3eb52954abff0a 100644 (file)
@@ -1104,11 +1104,13 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
        /* update the per-port timeout */
        uart_update_timeout(port, termios->c_cflag, baud);
 
-       /* save/disable interrupts and drain transmitter */
+       /*
+        * save/disable interrupts. The tty layer will ensure that the
+        * transmitter is empty if requested by the caller, so there's
+        * no need to wait for it here.
+        */
        imr = UART_GET_IMR(port);
        UART_PUT_IDR(port, -1);
-       while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
-               cpu_relax();
 
        /* disable receiver and transmitter */
        UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
index 285b414f30546d0a89285f823d802979adbbcac9..5d7b58f1fe42a38596072ba9355d619ffcfd54a2 100644 (file)
@@ -924,11 +924,13 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
        rational_best_approximation(16 * div * baud, sport->port.uartclk,
                1 << 16, 1 << 16, &num, &denom);
 
-       tdiv64 = sport->port.uartclk;
-       tdiv64 *= num;
-       do_div(tdiv64, denom * 16 * div);
-       tty_encode_baud_rate(sport->port.info->port.tty,
-               (speed_t)tdiv64, (speed_t)tdiv64);
+       if (port->info && port->info->port.tty) {
+               tdiv64 = sport->port.uartclk;
+               tdiv64 *= num;
+               do_div(tdiv64, denom * 16 * div);
+               tty_encode_baud_rate(sport->port.info->port.tty,
+                               (speed_t)tdiv64, (speed_t)tdiv64);
+       }
 
        num -= 1;
        denom -= 1;
index 14f8fa9135be49c664f64d80c9633bf1d405f85c..54483cd3529e00e85df152efb5cb95c3c654d924 100644 (file)
@@ -122,7 +122,7 @@ static int __devinit of_platform_serial_probe(struct of_device *ofdev,
 
        info->type = port_type;
        info->line = ret;
-       ofdev->dev.driver_data = info;
+       dev_set_drvdata(&ofdev->dev, info);
        return 0;
 out:
        kfree(info);
@@ -135,7 +135,7 @@ out:
  */
 static int of_platform_serial_remove(struct of_device *ofdev)
 {
-       struct of_serial_info *info = ofdev->dev.driver_data;
+       struct of_serial_info *info = dev_get_drvdata(&ofdev->dev);
        switch (info->type) {
 #ifdef CONFIG_SERIAL_8250
        case PORT_8250 ... PORT_MAX_8250:
index f014cc21e8131051542a0641129ce9018ec51020..011c5bddba6a52b9741ee39c9a573efcb9f972df 100644 (file)
@@ -803,7 +803,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
                                drv_data->rx, drv_data->len_in_bytes);
 
                        /* invalidate caches, if needed */
-                       if (bfin_addr_dcachable((unsigned long) drv_data->rx))
+                       if (bfin_addr_dcacheable((unsigned long) drv_data->rx))
                                invalidate_dcache_range((unsigned long) drv_data->rx,
                                                        (unsigned long) (drv_data->rx +
                                                        drv_data->len_in_bytes));
@@ -816,7 +816,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
                        dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
 
                        /* flush caches, if needed */
-                       if (bfin_addr_dcachable((unsigned long) drv_data->tx))
+                       if (bfin_addr_dcacheable((unsigned long) drv_data->tx))
                                flush_dcache_range((unsigned long) drv_data->tx,
                                                (unsigned long) (drv_data->tx +
                                                drv_data->len_in_bytes));
index 5e38ba10a3a90ed2a35687c4e73d636e1626a817..0a69672097a8195e3671e1d63b164c19fa0ababc 100644 (file)
@@ -417,7 +417,7 @@ static LIST_HEAD(thermal_hwmon_list);
 static ssize_t
 name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct thermal_hwmon_device *hwmon = dev->driver_data;
+       struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
        return sprintf(buf, "%s\n", hwmon->type);
 }
 static DEVICE_ATTR(name, 0444, name_show, NULL);
@@ -488,7 +488,7 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
                result = PTR_ERR(hwmon->device);
                goto free_mem;
        }
-       hwmon->device->driver_data = hwmon;
+       dev_set_drvdata(hwmon->device, hwmon);
        result = device_create_file(hwmon->device, &dev_attr_name);
        if (result)
                goto unregister_hwmon_device;
index 9cf9ff69e3e3505e08f9c2346b4d4095775a9981..d171b563e94c7e2bb10c092834799a434b6b8956 100644 (file)
@@ -306,6 +306,7 @@ enum {
 #define FW_GET_BYTE(p) *((__u8 *) (p))
 
 #define FW_DIR "ueagle-atm/"
+#define UEA_FW_NAME_MAX 30
 #define NB_MODEM 4
 
 #define BULK_TIMEOUT 300
@@ -1564,9 +1565,9 @@ static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
                file = cmv_file[sc->modem_index];
 
        strcpy(cmv_name, FW_DIR);
-       strlcat(cmv_name, file, FIRMWARE_NAME_MAX);
+       strlcat(cmv_name, file, UEA_FW_NAME_MAX);
        if (ver == 2)
-               strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX);
+               strlcat(cmv_name, ".v2", UEA_FW_NAME_MAX);
 }
 
 static int request_cmvs_old(struct uea_softc *sc,
@@ -1574,7 +1575,7 @@ static int request_cmvs_old(struct uea_softc *sc,
 {
        int ret, size;
        u8 *data;
-       char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+       char cmv_name[UEA_FW_NAME_MAX]; /* 30 bytes stack variable */
 
        cmvs_file_name(sc, cmv_name, 1);
        ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
@@ -1608,7 +1609,7 @@ static int request_cmvs(struct uea_softc *sc,
        int ret, size;
        u32 crc;
        u8 *data;
-       char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+       char cmv_name[UEA_FW_NAME_MAX]; /* 30 bytes stack variable */
 
        cmvs_file_name(sc, cmv_name, 2);
        ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
index d2747a49b9744bacf2962abbe2ea1b8bd3b087b5..26c09f0257dbeff29a9c8f25f39eaf15453570c0 100644 (file)
@@ -1057,8 +1057,14 @@ static const struct file_operations usblp_fops = {
        .release =      usblp_release,
 };
 
+static char *usblp_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
 static struct usb_class_driver usblp_class = {
        .name =         "lp%d",
+       .nodename =     usblp_nodename,
        .fops =         &usblp_fops,
        .minor_base =   USBLP_MINOR_BASE,
 };
index 997e659ff693eeb5ed083c2a8e76bdce76a33f97..5cef88929b3ee609af666c0d3e18772be10b1039 100644 (file)
@@ -67,6 +67,16 @@ static struct usb_class {
        struct class *class;
 } *usb_class;
 
+static char *usb_nodename(struct device *dev)
+{
+       struct usb_class_driver *drv;
+
+       drv = dev_get_drvdata(dev);
+       if (!drv || !drv->nodename)
+               return NULL;
+       return drv->nodename(dev);
+}
+
 static int init_usb_class(void)
 {
        int result = 0;
@@ -90,6 +100,7 @@ static int init_usb_class(void)
                kfree(usb_class);
                usb_class = NULL;
        }
+       usb_class->class->nodename = usb_nodename;
 
 exit:
        return result;
@@ -198,7 +209,7 @@ int usb_register_dev(struct usb_interface *intf,
        else
                temp = name;
        intf->usb_dev = device_create(usb_class->class, &intf->dev,
-                                     MKDEV(USB_MAJOR, minor), NULL,
+                                     MKDEV(USB_MAJOR, minor), class_driver,
                                      "%s", temp);
        if (IS_ERR(intf->usb_dev)) {
                down_write(&minor_rwsem);
index 55b8d3a22d266bbfb7628826f307f3e43de293e2..a26f73880c32388340fad1ef0639c8233d1c3be4 100644 (file)
@@ -310,10 +310,21 @@ static struct dev_pm_ops usb_device_pm_ops = {
 
 #endif /* CONFIG_PM */
 
+
+static char *usb_nodename(struct device *dev)
+{
+       struct usb_device *usb_dev;
+
+       usb_dev = to_usb_device(dev);
+       return kasprintf(GFP_KERNEL, "bus/usb/%03d/%03d",
+                        usb_dev->bus->busnum, usb_dev->devnum);
+}
+
 struct device_type usb_device_type = {
        .name =         "usb_device",
        .release =      usb_release_dev,
        .uevent =       usb_dev_uevent,
+       .nodename =     usb_nodename,
        .pm =           &usb_device_pm_ops,
 };
 
index e954225cd769cacaaf90d21ef92c0abece6ff290..72bae8f39d814310ef477df5c987318e79000835 100644 (file)
@@ -1574,7 +1574,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
 
        udc->driver = driver;
        udc->gadget.dev.driver = &driver->driver;
-       udc->gadget.dev.driver_data = &driver->driver;
+       dev_set_drvdata(&udc->gadget.dev, &driver->driver);
        udc->enabled = 1;
        udc->selfpowered = 1;
 
@@ -1583,7 +1583,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
                DBG("driver->bind() returned %d\n", retval);
                udc->driver = NULL;
                udc->gadget.dev.driver = NULL;
-               udc->gadget.dev.driver_data = NULL;
+               dev_set_drvdata(&udc->gadget.dev, NULL);
                udc->enabled = 0;
                udc->selfpowered = 0;
                return retval;
@@ -1613,7 +1613,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 
        driver->unbind(&udc->gadget);
        udc->gadget.dev.driver = NULL;
-       udc->gadget.dev.driver_data = NULL;
+       dev_set_drvdata(&udc->gadget.dev, NULL);
        udc->driver = NULL;
 
        DBG("unbound from %s\n", driver->driver.name);
index 4b4df23efddf47fd31977e143dfc628f8378be38..eecd2a0680a216bd68a26a3eba3459cd16037ac3 100644 (file)
@@ -163,7 +163,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
        dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
                (unsigned long)virq);
 
-       ps3_system_bus_set_driver_data(dev, hcd);
+       ps3_system_bus_set_drvdata(dev, hcd);
 
        result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
 
@@ -196,8 +196,7 @@ fail_start:
 static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
 {
        unsigned int tmp;
-       struct usb_hcd *hcd =
-               (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+       struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
 
        BUG_ON(!hcd);
 
@@ -209,7 +208,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
        ehci_shutdown(hcd);
        usb_remove_hcd(hcd);
 
-       ps3_system_bus_set_driver_data(dev, NULL);
+       ps3_system_bus_set_drvdata(dev, NULL);
 
        BUG_ON(!hcd->regs);
        iounmap(hcd->regs);
index 3d19103173286e849e54a21ede9012b04426ee24..1d56259c5db1650bb610e3318aa3a969a381f4cb 100644 (file)
@@ -162,7 +162,7 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev)
        dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
                (unsigned long)virq);
 
-       ps3_system_bus_set_driver_data(dev, hcd);
+       ps3_system_bus_set_drvdata(dev, hcd);
 
        result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
 
@@ -195,8 +195,7 @@ fail_start:
 static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
 {
        unsigned int tmp;
-       struct usb_hcd *hcd =
-               (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+       struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
 
        BUG_ON(!hcd);
 
@@ -208,7 +207,7 @@ static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
        ohci_shutdown(hcd);
        usb_remove_hcd(hcd);
 
-       ps3_system_bus_set_driver_data(dev, NULL);
+       ps3_system_bus_set_drvdata(dev, NULL);
 
        BUG_ON(!hcd->regs);
        iounmap(hcd->regs);
index a4ef77ef917d9bc6be7f2b29bff6a58ba6d105e1..3c5fe5cee05abab286dcc2f00d6cc1f70b031e06 100644 (file)
@@ -726,12 +726,18 @@ static const struct file_operations iowarrior_fops = {
        .poll = iowarrior_poll,
 };
 
+static char *iowarrior_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
 /*
  * usb class driver info in order to get a minor number from the usb core,
  * and to have the device registered with devfs and the driver core
  */
 static struct usb_class_driver iowarrior_class = {
        .name = "iowarrior%d",
+       .nodename = iowarrior_nodename,
        .fops = &iowarrior_fops,
        .minor_base = IOWARRIOR_MINOR_BASE,
 };
index ab0f3226158b0d6ed735c041931a6b80ae869afb..c1e2433f640d133da219152b7f8ad7389ac51471 100644 (file)
@@ -266,12 +266,18 @@ static const struct file_operations tower_fops = {
        .llseek =       tower_llseek,
 };
 
+static char *legousbtower_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
 /*
  * usb class driver info in order to get a minor number from the usb core,
  * and to have the device registered with the driver core
  */
 static struct usb_class_driver tower_class = {
        .name =         "legousbtower%d",
+       .nodename =     legousbtower_nodename,
        .fops =         &tower_fops,
        .minor_base =   LEGO_USB_TOWER_MINOR_BASE,
 };
index 1e35ba6f18e01ef44eeda30e5685a9eb2f556317..b0b147cb4cb3aae5a0090e38145f8b48d1b0e25b 100644 (file)
@@ -111,9 +111,7 @@ struct bw2_par {
        u32                     flags;
 #define BW2_FLAG_BLANKED       0x00000001
 
-       unsigned long           physbase;
        unsigned long           which_io;
-       unsigned long           fbsize;
 };
 
 /**
@@ -167,17 +165,15 @@ static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct bw2_par *par = (struct bw2_par *)info->par;
 
        return sbusfb_mmap_helper(bw2_mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->which_io,
                                  vma);
 }
 
 static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
-       struct bw2_par *par = (struct bw2_par *) info->par;
-
        return sbusfb_ioctl_helper(cmd, arg, info,
-                                  FBTYPE_SUN2BW, 1, par->fbsize);
+                                  FBTYPE_SUN2BW, 1, info->fix.smem_len);
 }
 
 /*
@@ -294,7 +290,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *
 
        spin_lock_init(&par->lock);
 
-       par->physbase = op->resource[0].start;
+       info->fix.smem_start = op->resource[0].start;
        par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 
        sbusfb_fill_var(&info->var, dp, 1);
@@ -317,13 +313,13 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *
                        goto out_unmap_regs;
        }
 
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        info->flags = FBINFO_DEFAULT;
        info->fbops = &bw2_ops;
 
        info->screen_base = of_ioremap(&op->resource[0], 0,
-                                      par->fbsize, "bw2 ram");
+                                      info->fix.smem_len, "bw2 ram");
        if (!info->screen_base)
                goto out_unmap_regs;
 
@@ -338,12 +334,12 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *
        dev_set_drvdata(&op->dev, info);
 
        printk(KERN_INFO "%s: bwtwo at %lx:%lx\n",
-              dp->full_name, par->which_io, par->physbase);
+              dp->full_name, par->which_io, info->fix.smem_start);
 
        return 0;
 
 out_unmap_screen:
-       of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
 
 out_unmap_regs:
        of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
@@ -363,7 +359,7 @@ static int __devexit bw2_remove(struct of_device *op)
        unregister_framebuffer(info);
 
        of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
-       of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
 
        framebuffer_release(info);
 
index a2d1882791a58e11956b250afbca92fa520b9e79..fe45a3b8d0e060141e8a7cef3d7702fff15a44fa 100644 (file)
@@ -196,9 +196,7 @@ struct cg14_par {
        u32                     flags;
 #define CG14_FLAG_BLANKED      0x00000001
 
-       unsigned long           physbase;
        unsigned long           iospace;
-       unsigned long           fbsize;
 
        struct sbus_mmap_map    mmap_map[CG14_MMAP_ENTRIES];
 
@@ -271,7 +269,7 @@ static int cg14_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct cg14_par *par = (struct cg14_par *) info->par;
 
        return sbusfb_mmap_helper(par->mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->iospace, vma);
 }
 
@@ -343,7 +341,8 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 
        default:
                ret = sbusfb_ioctl_helper(cmd, arg, info,
-                                         FBTYPE_MDICOLOR, 8, par->fbsize);
+                                         FBTYPE_MDICOLOR, 8,
+                                         info->fix.smem_len);
                break;
        };
 
@@ -462,7 +461,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info,
                           par->cursor, sizeof(struct cg14_cursor));
        if (info->screen_base)
                of_iounmap(&op->resource[1],
-                          info->screen_base, par->fbsize);
+                          info->screen_base, info->fix.smem_len);
 }
 
 static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match)
@@ -488,14 +487,14 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id
 
        linebytes = of_getintprop_default(dp, "linebytes",
                                          info->var.xres);
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        if (!strcmp(dp->parent->name, "sbus") ||
            !strcmp(dp->parent->name, "sbi")) {
-               par->physbase = op->resource[0].start;
+               info->fix.smem_start = op->resource[0].start;
                par->iospace = op->resource[0].flags & IORESOURCE_BITS;
        } else {
-               par->physbase = op->resource[1].start;
+               info->fix.smem_start = op->resource[1].start;
                par->iospace = op->resource[0].flags & IORESOURCE_BITS;
        }
 
@@ -507,7 +506,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id
                                 sizeof(struct cg14_cursor), "cg14 cursor");
 
        info->screen_base = of_ioremap(&op->resource[1], 0,
-                                      par->fbsize, "cg14 ram");
+                                      info->fix.smem_len, "cg14 ram");
 
        if (!par->regs || !par->clut || !par->cursor || !info->screen_base)
                goto out_unmap_regs;
@@ -557,7 +556,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id
 
        printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n",
               dp->full_name,
-              par->iospace, par->physbase,
+              par->iospace, info->fix.smem_start,
               par->ramsize >> 20);
 
        return 0;
index 99f87fb61d0558e816541fe0f133f79c2700decc..b2319fa7286f8c77d8649ff4892f02ace8fb45e0 100644 (file)
@@ -118,9 +118,7 @@ struct cg3_par {
 #define CG3_FLAG_BLANKED       0x00000001
 #define CG3_FLAG_RDI           0x00000002
 
-       unsigned long           physbase;
        unsigned long           which_io;
-       unsigned long           fbsize;
 };
 
 /**
@@ -231,17 +229,15 @@ static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct cg3_par *par = (struct cg3_par *)info->par;
 
        return sbusfb_mmap_helper(cg3_mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->which_io,
                                  vma);
 }
 
 static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
-       struct cg3_par *par = (struct cg3_par *) info->par;
-
        return sbusfb_ioctl_helper(cmd, arg, info,
-                                  FBTYPE_SUN3COLOR, 8, par->fbsize);
+                                  FBTYPE_SUN3COLOR, 8, info->fix.smem_len);
 }
 
 /*
@@ -368,7 +364,7 @@ static int __devinit cg3_probe(struct of_device *op,
 
        spin_lock_init(&par->lock);
 
-       par->physbase = op->resource[0].start;
+       info->fix.smem_start = op->resource[0].start;
        par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 
        sbusfb_fill_var(&info->var, dp, 8);
@@ -382,7 +378,7 @@ static int __devinit cg3_probe(struct of_device *op,
 
        linebytes = of_getintprop_default(dp, "linebytes",
                                          info->var.xres);
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
                               sizeof(struct cg3_regs), "cg3 regs");
@@ -392,7 +388,7 @@ static int __devinit cg3_probe(struct of_device *op,
        info->flags = FBINFO_DEFAULT;
        info->fbops = &cg3_ops;
        info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
-                                      par->fbsize, "cg3 ram");
+                                      info->fix.smem_len, "cg3 ram");
        if (!info->screen_base)
                goto out_unmap_regs;
 
@@ -418,7 +414,7 @@ static int __devinit cg3_probe(struct of_device *op,
        dev_set_drvdata(&op->dev, info);
 
        printk(KERN_INFO "%s: cg3 at %lx:%lx\n",
-              dp->full_name, par->which_io, par->physbase);
+              dp->full_name, par->which_io, info->fix.smem_start);
 
        return 0;
 
@@ -426,7 +422,7 @@ out_dealloc_cmap:
        fb_dealloc_cmap(&info->cmap);
 
 out_unmap_screen:
-       of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
 
 out_unmap_regs:
        of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
@@ -447,7 +443,7 @@ static int __devexit cg3_remove(struct of_device *op)
        fb_dealloc_cmap(&info->cmap);
 
        of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
-       of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
 
        framebuffer_release(info);
 
index 940ec04f0f1be22665c99e548eaf9392a2fa13b1..0d47c6030e3d084011d697bf7aefe34d6f02021f 100644 (file)
@@ -263,9 +263,7 @@ struct cg6_par {
        u32                     flags;
 #define CG6_FLAG_BLANKED       0x00000001
 
-       unsigned long           physbase;
        unsigned long           which_io;
-       unsigned long           fbsize;
 };
 
 static int cg6_sync(struct fb_info *info)
@@ -596,16 +594,14 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct cg6_par *par = (struct cg6_par *)info->par;
 
        return sbusfb_mmap_helper(cg6_mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->which_io, vma);
 }
 
 static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
-       struct cg6_par *par = (struct cg6_par *)info->par;
-
        return sbusfb_ioctl_helper(cmd, arg, info,
-                                  FBTYPE_SUNFAST_COLOR, 8, par->fbsize);
+                                  FBTYPE_SUNFAST_COLOR, 8, info->fix.smem_len);
 }
 
 /*
@@ -631,12 +627,12 @@ static void __devinit cg6_init_fix(struct fb_info *info, int linebytes)
                break;
        };
        if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
-               if (par->fbsize <= 0x100000)
+               if (info->fix.smem_len <= 0x100000)
                        cg6_card_name = "TGX";
                else
                        cg6_card_name = "TGX+";
        } else {
-               if (par->fbsize <= 0x100000)
+               if (info->fix.smem_len <= 0x100000)
                        cg6_card_name = "GX";
                else
                        cg6_card_name = "GX+";
@@ -738,7 +734,8 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
                of_iounmap(&op->resource[0], par->fhc, sizeof(u32));
 
        if (info->screen_base)
-               of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+               of_iounmap(&op->resource[0], info->screen_base,
+                          info->fix.smem_len);
 }
 
 static int __devinit cg6_probe(struct of_device *op,
@@ -759,7 +756,7 @@ static int __devinit cg6_probe(struct of_device *op,
 
        spin_lock_init(&par->lock);
 
-       par->physbase = op->resource[0].start;
+       info->fix.smem_start = op->resource[0].start;
        par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 
        sbusfb_fill_var(&info->var, dp, 8);
@@ -769,11 +766,11 @@ static int __devinit cg6_probe(struct of_device *op,
 
        linebytes = of_getintprop_default(dp, "linebytes",
                                          info->var.xres);
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        dblbuf = of_getintprop_default(dp, "dblbuf", 0);
        if (dblbuf)
-               par->fbsize *= 4;
+               info->fix.smem_len *= 4;
 
        par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
                                4096, "cgsix fbc");
@@ -792,7 +789,7 @@ static int __devinit cg6_probe(struct of_device *op,
        info->fbops = &cg6_ops;
 
        info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
-                                       par->fbsize, "cgsix ram");
+                                       info->fix.smem_len, "cgsix ram");
        if (!par->fbc || !par->tec || !par->thc ||
            !par->bt || !par->fhc || !info->screen_base)
                goto out_unmap_regs;
@@ -817,7 +814,7 @@ static int __devinit cg6_probe(struct of_device *op,
 
        printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n",
               dp->full_name, info->fix.id,
-              par->which_io, par->physbase);
+              par->which_io, info->fix.smem_start);
 
        return 0;
 
index 7c7e8c2da9d911081f68d3b94d46f2effd69e496..e145e2d16fe37414d40e7c1ce4df3831b3752ddc 100644 (file)
@@ -191,9 +191,7 @@ struct leo_par {
        u32                     flags;
 #define LEO_FLAG_BLANKED       0x00000001
 
-       unsigned long           physbase;
        unsigned long           which_io;
-       unsigned long           fbsize;
 };
 
 static void leo_wait(struct leo_lx_krn __iomem *lx_krn)
@@ -420,16 +418,14 @@ static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct leo_par *par = (struct leo_par *)info->par;
 
        return sbusfb_mmap_helper(leo_mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->which_io, vma);
 }
 
 static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
-       struct leo_par *par = (struct leo_par *) info->par;
-
        return sbusfb_ioctl_helper(cmd, arg, info,
-                                  FBTYPE_SUNLEO, 32, par->fbsize);
+                                  FBTYPE_SUNLEO, 32, info->fix.smem_len);
 }
 
 /*
@@ -569,7 +565,7 @@ static int __devinit leo_probe(struct of_device *op,
 
        spin_lock_init(&par->lock);
 
-       par->physbase = op->resource[0].start;
+       info->fix.smem_start = op->resource[0].start;
        par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 
        sbusfb_fill_var(&info->var, dp, 32);
@@ -577,7 +573,7 @@ static int __devinit leo_probe(struct of_device *op,
 
        linebytes = of_getintprop_default(dp, "linebytes",
                                          info->var.xres);
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        par->lc_ss0_usr =
                of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR,
@@ -627,7 +623,7 @@ static int __devinit leo_probe(struct of_device *op,
 
        printk(KERN_INFO "%s: leo at %lx:%lx\n",
               dp->full_name,
-              par->which_io, par->physbase);
+              par->which_io, info->fix.smem_start);
 
        return 0;
 
index 7000f2cd58542e54668d58ecb3374e5c6c23d3fb..7fa4ab01b0d36281536875ed1d28e68606d78984 100644 (file)
@@ -134,9 +134,7 @@ struct p9100_par {
        u32                     flags;
 #define P9100_FLAG_BLANKED     0x00000001
 
-       unsigned long           physbase;
        unsigned long           which_io;
-       unsigned long           fbsize;
 };
 
 /**
@@ -224,18 +222,16 @@ static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct p9100_par *par = (struct p9100_par *)info->par;
 
        return sbusfb_mmap_helper(p9100_mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->which_io, vma);
 }
 
 static int p9100_ioctl(struct fb_info *info, unsigned int cmd,
                       unsigned long arg)
 {
-       struct p9100_par *par = (struct p9100_par *) info->par;
-
        /* Make it look like a cg3. */
        return sbusfb_ioctl_helper(cmd, arg, info,
-                                  FBTYPE_SUN3COLOR, 8, par->fbsize);
+                                  FBTYPE_SUN3COLOR, 8, info->fix.smem_len);
 }
 
 /*
@@ -271,7 +267,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
        spin_lock_init(&par->lock);
 
        /* This is the framebuffer and the only resource apps can mmap.  */
-       par->physbase = op->resource[2].start;
+       info->fix.smem_start = op->resource[2].start;
        par->which_io = op->resource[2].flags & IORESOURCE_BITS;
 
        sbusfb_fill_var(&info->var, dp, 8);
@@ -280,7 +276,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
        info->var.blue.length = 8;
 
        linebytes = of_getintprop_default(dp, "linebytes", info->var.xres);
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        par->regs = of_ioremap(&op->resource[0], 0,
                               sizeof(struct p9100_regs), "p9100 regs");
@@ -290,7 +286,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
        info->flags = FBINFO_DEFAULT;
        info->fbops = &p9100_ops;
        info->screen_base = of_ioremap(&op->resource[2], 0,
-                                      par->fbsize, "p9100 ram");
+                                      info->fix.smem_len, "p9100 ram");
        if (!info->screen_base)
                goto out_unmap_regs;
 
@@ -311,7 +307,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
 
        printk(KERN_INFO "%s: p9100 at %lx:%lx\n",
               dp->full_name,
-              par->which_io, par->physbase);
+              par->which_io, info->fix.smem_start);
 
        return 0;
 
@@ -319,7 +315,7 @@ out_dealloc_cmap:
        fb_dealloc_cmap(&info->cmap);
 
 out_unmap_screen:
-       of_iounmap(&op->resource[2], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len);
 
 out_unmap_regs:
        of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
@@ -340,7 +336,7 @@ static int __devexit p9100_remove(struct of_device *op)
        fb_dealloc_cmap(&info->cmap);
 
        of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
-       of_iounmap(&op->resource[2], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len);
 
        framebuffer_release(info);
 
index e00c1dff55de24316d905750619781960328968c..c0af638fe702441c4095d168f4b464769296274c 100644 (file)
 #include <linux/init.h>
 
 #include <asm/abs_addr.h>
+#include <asm/iommu.h>
 #include <asm/lv1call.h>
 #include <asm/ps3av.h>
 #include <asm/ps3fb.h>
 #include <asm/ps3.h>
+#include <asm/ps3gpu.h>
 
 
 #define DEVICE_NAME            "ps3fb"
 
-#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC   0x101
-#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP   0x102
-#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP       0x600
-#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT                0x601
-#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC   0x602
-
-#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION      (1ULL << 32)
-
-#define L1GPU_DISPLAY_SYNC_HSYNC               1
-#define L1GPU_DISPLAY_SYNC_VSYNC               2
-
 #define GPU_CMD_BUF_SIZE                       (2 * 1024 * 1024)
 #define GPU_FB_START                           (64 * 1024)
 #define GPU_IOIF                               (0x0d000000UL)
@@ -462,33 +453,27 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
        src_offset += GPU_FB_START;
 
        mutex_lock(&ps3_gpu_mutex);
-       status = lv1_gpu_context_attribute(ps3fb.context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
-                                          dst_offset, GPU_IOIF + src_offset,
-                                          L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
-                                          (width << 16) | height,
-                                          line_length);
+       status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset,
+                                GPU_IOIF + src_offset,
+                                L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
+                                (width << 16) | height,
+                                line_length);
        mutex_unlock(&ps3_gpu_mutex);
 
        if (status)
-               dev_err(dev,
-                       "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
-                       __func__, status);
+               dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__,
+                       status);
 #ifdef HEAD_A
-       status = lv1_gpu_context_attribute(ps3fb.context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
-                                          0, frame_offset, 0, 0);
+       status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset);
        if (status)
-               dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
-                       __func__, status);
+               dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__,
+                       status);
 #endif
 #ifdef HEAD_B
-       status = lv1_gpu_context_attribute(ps3fb.context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
-                                          1, frame_offset, 0, 0);
+       status = lv1_gpu_display_flip(ps3fb.context_handle, 1, frame_offset);
        if (status)
-               dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
-                       __func__, status);
+               dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__,
+                       status);
 #endif
 }
 
@@ -956,73 +941,6 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
 }
 
 
-static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo,
-                               struct device *dev)
-{
-       int error;
-
-       dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver);
-       dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet);
-       dev_dbg(dev,
-               "version_gpu: %x memory_size: %x ch: %x core_freq: %d "
-               "mem_freq:%d\n",
-               dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel,
-               dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
-
-       if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
-               dev_err(dev, "%s: version_driver err:%x\n", __func__,
-                       dinfo->version_driver);
-               return -EINVAL;
-       }
-
-       error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
-                                  &ps3fb.irq_no);
-       if (error) {
-               dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error);
-               return error;
-       }
-
-       error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
-                           DEVICE_NAME, dev);
-       if (error) {
-               dev_err(dev, "%s: request_irq failed %d\n", __func__, error);
-               ps3_irq_plug_destroy(ps3fb.irq_no);
-               return error;
-       }
-
-       dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) |
-                         (1 << GPU_INTR_STATUS_FLIP_1);
-       return 0;
-}
-
-static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev)
-{
-       int status;
-
-       status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
-                                      xdr_lpar, ps3fb_videomemory.size, 0);
-       if (status) {
-               dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n",
-                       __func__, status);
-               return -ENXIO;
-       }
-       dev_dbg(dev, "video:%p ioif:%lx lpar:%llx size:%lx\n",
-               ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
-               ps3fb_videomemory.size);
-
-       status = lv1_gpu_context_attribute(ps3fb.context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
-                                          xdr_lpar, GPU_CMD_BUF_SIZE,
-                                          GPU_IOIF, 0);
-       if (status) {
-               dev_err(dev,
-                       "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
-                       __func__, status);
-               return -ENXIO;
-       }
-       return 0;
-}
-
 static struct fb_ops ps3fb_ops = {
        .fb_open        = ps3fb_open,
        .fb_release     = ps3fb_release,
@@ -1048,49 +966,18 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static int ps3fb_set_sync(struct device *dev)
-{
-       int status;
-
-#ifdef HEAD_A
-       status = lv1_gpu_context_attribute(0x0,
-                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
-                                          0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
-       if (status) {
-               dev_err(dev,
-                       "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: "
-                       "%d\n",
-                       __func__, status);
-               return -1;
-       }
-#endif
-#ifdef HEAD_B
-       status = lv1_gpu_context_attribute(0x0,
-                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
-                                          1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
-
-       if (status) {
-               dev_err(dev,
-                       "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: "
-                       "%d\n",
-                       __func__, status);
-               return -1;
-       }
-#endif
-       return 0;
-}
-
 static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
 {
        struct fb_info *info;
        struct ps3fb_par *par;
-       int retval = -ENOMEM;
+       int retval;
        u64 ddr_lpar = 0;
        u64 lpar_dma_control = 0;
        u64 lpar_driver_info = 0;
        u64 lpar_reports = 0;
        u64 lpar_reports_size = 0;
        u64 xdr_lpar;
+       struct gpu_driver_info *dinfo;
        void *fb_start;
        int status;
        struct task_struct *task;
@@ -1101,8 +988,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
                return -ENOMEM;
        }
 
-       status = ps3_open_hv_device(dev);
-       if (status) {
+       retval = ps3_open_hv_device(dev);
+       if (retval) {
                dev_err(&dev->core, "%s: ps3_open_hv_device failed\n",
                        __func__);
                goto err;
@@ -1116,7 +1003,24 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
        init_waitqueue_head(&ps3fb.wait_vsync);
 
-       ps3fb_set_sync(&dev->core);
+#ifdef HEAD_A
+       status = lv1_gpu_display_sync(0x0, 0, L1GPU_DISPLAY_SYNC_VSYNC);
+       if (status) {
+               dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n",
+                       __func__, status);
+               retval = -ENODEV;
+               goto err_close_device;
+       }
+#endif
+#ifdef HEAD_B
+       status = lv1_gpu_display_sync(0x0, 1, L1GPU_DISPLAY_SYNC_VSYNC);
+       if (status) {
+               dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n",
+                       __func__, status);
+               retval = -ENODEV;
+               goto err_close_device;
+       }
+#endif
 
        max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF;
        if (ps3fb_videomemory.size > max_ps3fb_size) {
@@ -1131,7 +1035,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        if (status) {
                dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
                        __func__, status);
-               goto err;
+               goto err_close_device;
        }
        dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar);
 
@@ -1141,33 +1045,85 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
                                          &lpar_reports, &lpar_reports_size);
        if (status) {
                dev_err(&dev->core,
-                       "%s: lv1_gpu_context_attribute failed: %d\n", __func__,
+                       "%s: lv1_gpu_context_allocate failed: %d\n", __func__,
                        status);
                goto err_gpu_memory_free;
        }
 
        /* vsync interrupt */
-       ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
-       if (!ps3fb.dinfo) {
+       dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
+       if (!dinfo) {
                dev_err(&dev->core, "%s: ioremap failed\n", __func__);
                goto err_gpu_context_free;
        }
 
-       retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core);
-       if (retval)
+       ps3fb.dinfo = dinfo;
+       dev_dbg(&dev->core, "version_driver:%x\n", dinfo->version_driver);
+       dev_dbg(&dev->core, "irq outlet:%x\n", dinfo->irq.irq_outlet);
+       dev_dbg(&dev->core, "version_gpu: %x memory_size: %x ch: %x "
+               "core_freq: %d mem_freq:%d\n", dinfo->version_gpu,
+               dinfo->memory_size, dinfo->hardware_channel,
+               dinfo->nvcore_frequency/1000000,
+               dinfo->memory_frequency/1000000);
+
+       if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
+               dev_err(&dev->core, "%s: version_driver err:%x\n", __func__,
+                       dinfo->version_driver);
+               retval = -EINVAL;
+               goto err_iounmap_dinfo;
+       }
+
+       retval = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
+                                   &ps3fb.irq_no);
+       if (retval) {
+               dev_err(&dev->core, "%s: ps3_alloc_irq failed %d\n", __func__,
+                       retval);
                goto err_iounmap_dinfo;
+       }
+
+       retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt,
+                            IRQF_DISABLED, DEVICE_NAME, &dev->core);
+       if (retval) {
+               dev_err(&dev->core, "%s: request_irq failed %d\n", __func__,
+                       retval);
+               goto err_destroy_plug;
+       }
+
+       dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) |
+                         (1 << GPU_INTR_STATUS_FLIP_1);
 
        /* Clear memory to prevent kernel info leakage into userspace */
        memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size);
 
        xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
-       retval = ps3fb_xdr_settings(xdr_lpar, &dev->core);
-       if (retval)
+
+       status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
+                                      xdr_lpar, ps3fb_videomemory.size,
+                                      CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
+                                      CBE_IOPTE_M);
+       if (status) {
+               dev_err(&dev->core, "%s: lv1_gpu_context_iomap failed: %d\n",
+                       __func__, status);
+               retval =  -ENXIO;
                goto err_free_irq;
+       }
+
+       dev_dbg(&dev->core, "video:%p ioif:%lx lpar:%llx size:%lx\n",
+               ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
+               ps3fb_videomemory.size);
+
+       status = lv1_gpu_fb_setup(ps3fb.context_handle, xdr_lpar,
+                                 GPU_CMD_BUF_SIZE, GPU_IOIF);
+       if (status) {
+               dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n",
+                       __func__, status);
+               retval = -ENXIO;
+               goto err_context_unmap;
+       }
 
        info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
        if (!info)
-               goto err_free_irq;
+               goto err_context_fb_close;
 
        par = info->par;
        par->mode_id = ~ps3fb_mode;     /* != ps3fb_mode, to trigger change */
@@ -1210,7 +1166,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        if (retval < 0)
                goto err_fb_dealloc;
 
-       dev->core.driver_data = info;
+       ps3_system_bus_set_drvdata(dev, info);
 
        dev_info(info->device, "%s %s, using %u KiB of video memory\n",
                 dev_driver_string(info->dev), dev_name(info->dev),
@@ -1232,8 +1188,14 @@ err_fb_dealloc:
        fb_dealloc_cmap(&info->cmap);
 err_framebuffer_release:
        framebuffer_release(info);
+err_context_fb_close:
+       lv1_gpu_fb_close(ps3fb.context_handle);
+err_context_unmap:
+       lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar,
+                             ps3fb_videomemory.size, CBE_IOPTE_M);
 err_free_irq:
        free_irq(ps3fb.irq_no, &dev->core);
+err_destroy_plug:
        ps3_irq_plug_destroy(ps3fb.irq_no);
 err_iounmap_dinfo:
        iounmap((u8 __force __iomem *)ps3fb.dinfo);
@@ -1241,14 +1203,16 @@ err_gpu_context_free:
        lv1_gpu_context_free(ps3fb.context_handle);
 err_gpu_memory_free:
        lv1_gpu_memory_free(ps3fb.memory_handle);
+err_close_device:
+       ps3_close_hv_device(dev);
 err:
        return retval;
 }
 
 static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
 {
-       int status;
-       struct fb_info *info = dev->core.driver_data;
+       struct fb_info *info = ps3_system_bus_get_drvdata(dev);
+       u64 xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
 
        dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
 
@@ -1268,20 +1232,14 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
                unregister_framebuffer(info);
                fb_dealloc_cmap(&info->cmap);
                framebuffer_release(info);
-               info = dev->core.driver_data = NULL;
+               ps3_system_bus_set_drvdata(dev, NULL);
        }
        iounmap((u8 __force __iomem *)ps3fb.dinfo);
-
-       status = lv1_gpu_context_free(ps3fb.context_handle);
-       if (status)
-               dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n",
-                       status);
-
-       status = lv1_gpu_memory_free(ps3fb.memory_handle);
-       if (status)
-               dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n",
-                       status);
-
+       lv1_gpu_fb_close(ps3fb.context_handle);
+       lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar,
+                             ps3fb_videomemory.size, CBE_IOPTE_M);
+       lv1_gpu_context_free(ps3fb.context_handle);
+       lv1_gpu_memory_free(ps3fb.memory_handle);
        ps3_close_hv_device(dev);
        dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
 
index 89f231dc443f0b191701cae247aca0f29c4785f2..ff43c8885028e2f20eb928cc2119977373a3d135 100644 (file)
@@ -1315,7 +1315,6 @@ static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan,
 
        strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name));
        chan->adapter.owner             = THIS_MODULE;
-       chan->adapter.class             = I2C_CLASS_TV_ANALOG;
        chan->adapter.algo_data         = &chan->algo;
        chan->adapter.dev.parent        = dev;
        chan->algo.setsda               = tdfxfb_i2c_setsda;
index 2493f05e9f6176588c0f0fc3471097f62c8ae68d..15502d5e3641890f1f6646cc661b5e26d4755753 100644 (file)
@@ -384,7 +384,7 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
                fb_size = XENFB_DEFAULT_FB_LEN;
        }
 
-       dev->dev.driver_data = info;
+       dev_set_drvdata(&dev->dev, info);
        info->xbdev = dev;
        info->irq = -1;
        info->x1 = info->y1 = INT_MAX;
@@ -503,7 +503,7 @@ xenfb_make_preferred_console(void)
 
 static int xenfb_resume(struct xenbus_device *dev)
 {
-       struct xenfb_info *info = dev->dev.driver_data;
+       struct xenfb_info *info = dev_get_drvdata(&dev->dev);
 
        xenfb_disconnect_backend(info);
        xenfb_init_shared_page(info, info->fb_info);
@@ -512,7 +512,7 @@ static int xenfb_resume(struct xenbus_device *dev)
 
 static int xenfb_remove(struct xenbus_device *dev)
 {
-       struct xenfb_info *info = dev->dev.driver_data;
+       struct xenfb_info *info = dev_get_drvdata(&dev->dev);
 
        xenfb_disconnect_backend(info);
        if (info->fb_info) {
@@ -621,7 +621,7 @@ static void xenfb_disconnect_backend(struct xenfb_info *info)
 static void xenfb_backend_changed(struct xenbus_device *dev,
                                  enum xenbus_state backend_state)
 {
-       struct xenfb_info *info = dev->dev.driver_data;
+       struct xenfb_info *info = dev_get_drvdata(&dev->dev);
        int val;
 
        switch (backend_state) {
index 5f80848c320c7a66c6425e75aea21533607134fa..24c9140435323e4caabbdf00156efd0060d1be55 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -25,7 +25,6 @@
 #include <linux/module.h>
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
-#include <linux/blktrace_api.h>
 #include <scsi/sg.h>           /* for struct sg_iovec */
 
 #include <trace/events/block.h>
index 0d50d49d990ab858d1a00b24a7a9fdbdcc7e7b4b..d28d29c95f7ca23a91e9ccf3c306840484ea29ed 100644 (file)
@@ -42,6 +42,8 @@
 static struct extent_io_ops btree_extent_io_ops;
 static void end_workqueue_fn(struct btrfs_work *work);
 
+static atomic_t btrfs_bdi_num = ATOMIC_INIT(0);
+
 /*
  * end_io_wq structs are used to do processing in task context when an IO is
  * complete.  This is used during reads to verify checksums, and it is used
@@ -1342,12 +1344,25 @@ static void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
        free_extent_map(em);
 }
 
+/*
+ * If this fails, caller must call bdi_destroy() to get rid of the
+ * bdi again.
+ */
 static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi)
 {
-       bdi_init(bdi);
+       int err;
+
+       bdi->capabilities = BDI_CAP_MAP_COPY;
+       err = bdi_init(bdi);
+       if (err)
+               return err;
+
+       err = bdi_register(bdi, NULL, "btrfs-%d",
+                               atomic_inc_return(&btrfs_bdi_num));
+       if (err)
+               return err;
+
        bdi->ra_pages   = default_backing_dev_info.ra_pages;
-       bdi->state              = 0;
-       bdi->capabilities       = default_backing_dev_info.capabilities;
        bdi->unplug_io_fn       = btrfs_unplug_io_fn;
        bdi->unplug_io_data     = info;
        bdi->congested_fn       = btrfs_congested_fn;
@@ -1569,7 +1584,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        fs_info->sb = sb;
        fs_info->max_extent = (u64)-1;
        fs_info->max_inline = 8192 * 1024;
-       setup_bdi(fs_info, &fs_info->bdi);
+       if (setup_bdi(fs_info, &fs_info->bdi))
+               goto fail_bdi;
        fs_info->btree_inode = new_inode(sb);
        fs_info->btree_inode->i_ino = 1;
        fs_info->btree_inode->i_nlink = 1;
@@ -1946,8 +1962,8 @@ fail_iput:
 
        btrfs_close_devices(fs_info->fs_devices);
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
+fail_bdi:
        bdi_destroy(&fs_info->bdi);
-
 fail:
        kfree(extent_root);
        kfree(tree_root);
index 2e177d7f4bb949ac92405bbaaa5f2452d8657e2e..4e83457ea253e798ccfc8cb1d493ad7e48daa2bd 100644 (file)
@@ -543,13 +543,13 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
                        btrfs_free_log(trans, root);
                        btrfs_update_reloc_root(trans, root);
 
-                       if (root->commit_root == root->node)
-                               continue;
-
-                       free_extent_buffer(root->commit_root);
-                       root->commit_root = btrfs_root_node(root);
+                       if (root->commit_root != root->node) {
+                               free_extent_buffer(root->commit_root);
+                               root->commit_root = btrfs_root_node(root);
+                               btrfs_set_root_node(&root->root_item,
+                                                   root->node);
+                       }
 
-                       btrfs_set_root_node(&root->root_item, root->node);
                        err = btrfs_update_root(trans, fs_info->tree_root,
                                                &root->root_key,
                                                &root->root_item);
index 33a90120f6ad11673bb869f5526db633d9cfac24..4d74fc72c195daf72e9d9b8ec9a56e62a51f0227 100644 (file)
@@ -67,6 +67,8 @@ static int debugfs_u8_get(void *data, u64 *val)
        return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n");
 
 /**
  * debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value
@@ -95,6 +97,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
 struct dentry *debugfs_create_u8(const char *name, mode_t mode,
                                 struct dentry *parent, u8 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u8_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u8_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_u8);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u8);
@@ -110,6 +119,8 @@ static int debugfs_u16_get(void *data, u64 *val)
        return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n");
 
 /**
  * debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value
@@ -138,6 +149,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
 struct dentry *debugfs_create_u16(const char *name, mode_t mode,
                                  struct dentry *parent, u16 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u16_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u16_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_u16);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u16);
@@ -153,6 +171,8 @@ static int debugfs_u32_get(void *data, u64 *val)
        return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n");
 
 /**
  * debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value
@@ -181,6 +201,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
 struct dentry *debugfs_create_u32(const char *name, mode_t mode,
                                 struct dentry *parent, u32 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u32_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u32_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_u32);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u32);
@@ -197,6 +224,8 @@ static int debugfs_u64_get(void *data, u64 *val)
        return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
 
 /**
  * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value
@@ -225,15 +254,28 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
 struct dentry *debugfs_create_u64(const char *name, mode_t mode,
                                 struct dentry *parent, u64 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u64_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u64_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_u64);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u64);
 
 DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%02llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%02llx\n");
 
 DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%04llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%04llx\n");
 
 DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n");
 
 /*
  * debugfs_create_x{8,16,32} - create a debugfs file that is used to read and write an unsigned {8,16,32}-bit value
@@ -256,6 +298,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n"
 struct dentry *debugfs_create_x8(const char *name, mode_t mode,
                                 struct dentry *parent, u8 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x8_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x8_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_x8);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x8);
@@ -273,6 +322,13 @@ EXPORT_SYMBOL_GPL(debugfs_create_x8);
 struct dentry *debugfs_create_x16(const char *name, mode_t mode,
                                 struct dentry *parent, u16 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x16_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x16_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_x16);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x16);
@@ -290,6 +346,13 @@ EXPORT_SYMBOL_GPL(debugfs_create_x16);
 struct dentry *debugfs_create_x32(const char *name, mode_t mode,
                                 struct dentry *parent, u32 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x32_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x32_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_x32);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x32);
@@ -419,7 +482,7 @@ static const struct file_operations fops_blob = {
 };
 
 /**
- * debugfs_create_blob - create a debugfs file that is used to read and write a binary blob
+ * debugfs_create_blob - create a debugfs file that is used to read a binary blob
  * @name: a pointer to a string containing the name of the file to create.
  * @mode: the permission that the file should have
  * @parent: a pointer to the parent dentry for this file.  This should be a
index 0662ba6de85a46040ac83b87d66562146a009811..d22438ef7674870ad4987b9c2eb11555057e4dc8 100644 (file)
@@ -403,6 +403,7 @@ void debugfs_remove_recursive(struct dentry *dentry)
                }
                child = list_entry(parent->d_subdirs.next, struct dentry,
                                d_u.d_child);
+ next_sibling:
 
                /*
                 * If "child" isn't empty, walk down the tree and
@@ -416,6 +417,16 @@ void debugfs_remove_recursive(struct dentry *dentry)
                }
                __debugfs_remove(child, parent);
                if (parent->d_subdirs.next == &child->d_u.d_child) {
+                       /*
+                        * Try the next sibling.
+                        */
+                       if (child->d_u.d_child.next != &parent->d_subdirs) {
+                               child = list_entry(child->d_u.d_child.next,
+                                                  struct dentry,
+                                                  d_u.d_child);
+                               goto next_sibling;
+                       }
+
                        /*
                         * Avoid infinite loop if we fail to remove
                         * one dentry.
index b4260229808790859871d7cf0e013cdf2601116c..923990e4f16e13b4ebc2f9f9435aee64b24633f8 100644 (file)
@@ -241,7 +241,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
        while (*fclus < cluster) {
                /* prevent the infinite loop of cluster chain */
                if (*fclus > limit) {
-                       fat_fs_panic(sb, "%s: detected the cluster chain loop"
+                       fat_fs_error(sb, "%s: detected the cluster chain loop"
                                     " (i_pos %lld)", __func__,
                                     MSDOS_I(inode)->i_pos);
                        nr = -EIO;
@@ -252,7 +252,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
                if (nr < 0)
                        goto out;
                else if (nr == FAT_ENT_FREE) {
-                       fat_fs_panic(sb, "%s: invalid cluster chain"
+                       fat_fs_error(sb, "%s: invalid cluster chain"
                                     " (i_pos %lld)", __func__,
                                     MSDOS_I(inode)->i_pos);
                        nr = -EIO;
@@ -285,7 +285,7 @@ static int fat_bmap_cluster(struct inode *inode, int cluster)
        if (ret < 0)
                return ret;
        else if (ret == FAT_ENT_EOF) {
-               fat_fs_panic(sb, "%s: request beyond EOF (i_pos %lld)",
+               fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)",
                             __func__, MSDOS_I(inode)->i_pos);
                return -EIO;
        }
index 7c14c8cbbabaabd2ecb52220b21cfe0c6fa8dcbd..38ff75a0fe22d3b8764e9be001dd57857c5abe66 100644 (file)
@@ -1335,7 +1335,7 @@ found:
                        goto error_remove;
                }
                if (dir->i_size & (sbi->cluster_size - 1)) {
-                       fat_fs_panic(sb, "Odd directory size");
+                       fat_fs_error(sb, "Odd directory size");
                        dir->i_size = (dir->i_size + sbi->cluster_size - 1)
                                & ~((loff_t)sbi->cluster_size - 1);
                }
index e4d88527b5dd924c51186e43872127dca36ad7ee..adb0e72a176dd42bb8bdd1b4d099e021a02b02b1 100644 (file)
 #define VFAT_SFN_CREATE_WIN95  0x0100 /* emulate win95 rule for create */
 #define VFAT_SFN_CREATE_WINNT  0x0200 /* emulate winnt rule for create */
 
+#define FAT_ERRORS_CONT                1      /* ignore error and continue */
+#define FAT_ERRORS_PANIC       2      /* panic on error */
+#define FAT_ERRORS_RO          3      /* remount r/o on error */
+
 struct fat_mount_options {
        uid_t fs_uid;
        gid_t fs_gid;
@@ -26,6 +30,7 @@ struct fat_mount_options {
        char *iocharset;          /* Charset used for filename input/display */
        unsigned short shortname; /* flags for shortname display/create rule */
        unsigned char name_check; /* r = relaxed, n = normal, s = strict */
+       unsigned char errors;     /* On error: continue, panic, remount-ro */
        unsigned short allow_utime;/* permission for setting the [am]time */
        unsigned quiet:1,         /* set = fake successful chmods and chowns */
                 showexec:1,      /* set = only set x bit for com/exe/bat */
@@ -316,7 +321,7 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent,
 extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
                            struct inode *i2);
 /* fat/misc.c */
-extern void fat_fs_panic(struct super_block *s, const char *fmt, ...)
+extern void fat_fs_error(struct super_block *s, const char *fmt, ...)
        __attribute__ ((format (printf, 2, 3))) __cold;
 extern void fat_clusters_flush(struct super_block *sb);
 extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
index 618f5305c2e4f298bdb9742c5f5038ff57e9c22f..a81037721a6f12cb7e11d85f188c408ae2907699 100644 (file)
@@ -348,7 +348,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
 
        if (entry < FAT_START_ENT || sbi->max_cluster <= entry) {
                fatent_brelse(fatent);
-               fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", entry);
+               fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry);
                return -EIO;
        }
 
@@ -560,7 +560,7 @@ int fat_free_clusters(struct inode *inode, int cluster)
                        err = cluster;
                        goto error;
                } else if (cluster == FAT_ENT_FREE) {
-                       fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF",
+                       fat_fs_error(sb, "%s: deleting FAT entry beyond EOF",
                                     __func__);
                        err = -EIO;
                        goto error;
index e955a56b4e5ea0455c27782ce754d0734691ef49..b28ea646ff607cfdbe0f1ebda29158b5feadef88 100644 (file)
 #include <linux/security.h>
 #include "fat.h"
 
-int fat_generic_ioctl(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg)
+static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr)
 {
+       u32 attr;
+
+       mutex_lock(&inode->i_mutex);
+       attr = fat_make_attrs(inode);
+       mutex_unlock(&inode->i_mutex);
+
+       return put_user(attr, user_attr);
+}
+
+static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
        struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
-       u32 __user *user_attr = (u32 __user *)arg;
+       int is_dir = S_ISDIR(inode->i_mode);
+       u32 attr, oldattr;
+       struct iattr ia;
+       int err;
 
-       switch (cmd) {
-       case FAT_IOCTL_GET_ATTRIBUTES:
-       {
-               u32 attr;
+       err = get_user(attr, user_attr);
+       if (err)
+               goto out;
 
-               mutex_lock(&inode->i_mutex);
-               attr = fat_make_attrs(inode);
-               mutex_unlock(&inode->i_mutex);
+       mutex_lock(&inode->i_mutex);
+       err = mnt_want_write(file->f_path.mnt);
+       if (err)
+               goto out_unlock_inode;
 
-               return put_user(attr, user_attr);
+       /*
+        * ATTR_VOLUME and ATTR_DIR cannot be changed; this also
+        * prevents the user from turning us into a VFAT
+        * longname entry.  Also, we obviously can't set
+        * any of the NTFS attributes in the high 24 bits.
+        */
+       attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR);
+       /* Merge in ATTR_VOLUME and ATTR_DIR */
+       attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) |
+               (is_dir ? ATTR_DIR : 0);
+       oldattr = fat_make_attrs(inode);
+
+       /* Equivalent to a chmod() */
+       ia.ia_valid = ATTR_MODE | ATTR_CTIME;
+       ia.ia_ctime = current_fs_time(inode->i_sb);
+       if (is_dir)
+               ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO);
+       else {
+               ia.ia_mode = fat_make_mode(sbi, attr,
+                       S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO));
        }
-       case FAT_IOCTL_SET_ATTRIBUTES:
-       {
-               u32 attr, oldattr;
-               int err, is_dir = S_ISDIR(inode->i_mode);
-               struct iattr ia;
 
-               err = get_user(attr, user_attr);
-               if (err)
-                       return err;
+       /* The root directory has no attributes */
+       if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {
+               err = -EINVAL;
+               goto out_drop_write;
+       }
 
-               mutex_lock(&inode->i_mutex);
-
-               err = mnt_want_write(filp->f_path.mnt);
-               if (err)
-                       goto up_no_drop_write;
-
-               /*
-                * ATTR_VOLUME and ATTR_DIR cannot be changed; this also
-                * prevents the user from turning us into a VFAT
-                * longname entry.  Also, we obviously can't set
-                * any of the NTFS attributes in the high 24 bits.
-                */
-               attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR);
-               /* Merge in ATTR_VOLUME and ATTR_DIR */
-               attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) |
-                       (is_dir ? ATTR_DIR : 0);
-               oldattr = fat_make_attrs(inode);
-
-               /* Equivalent to a chmod() */
-               ia.ia_valid = ATTR_MODE | ATTR_CTIME;
-               ia.ia_ctime = current_fs_time(inode->i_sb);
-               if (is_dir)
-                       ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO);
-               else {
-                       ia.ia_mode = fat_make_mode(sbi, attr,
-                               S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO));
-               }
+       if (sbi->options.sys_immutable &&
+           ((attr | oldattr) & ATTR_SYS) &&
+           !capable(CAP_LINUX_IMMUTABLE)) {
+               err = -EPERM;
+               goto out_drop_write;
+       }
 
-               /* The root directory has no attributes */
-               if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {
-                       err = -EINVAL;
-                       goto up;
-               }
+       /*
+        * The security check is questionable...  We single
+        * out the RO attribute for checking by the security
+        * module, just because it maps to a file mode.
+        */
+       err = security_inode_setattr(file->f_path.dentry, &ia);
+       if (err)
+               goto out_drop_write;
 
-               if (sbi->options.sys_immutable) {
-                       if ((attr | oldattr) & ATTR_SYS) {
-                               if (!capable(CAP_LINUX_IMMUTABLE)) {
-                                       err = -EPERM;
-                                       goto up;
-                               }
-                       }
-               }
+       /* This MUST be done before doing anything irreversible... */
+       err = fat_setattr(file->f_path.dentry, &ia);
+       if (err)
+               goto out_drop_write;
+
+       fsnotify_change(file->f_path.dentry, ia.ia_valid);
+       if (sbi->options.sys_immutable) {
+               if (attr & ATTR_SYS)
+                       inode->i_flags |= S_IMMUTABLE;
+               else
+                       inode->i_flags &= S_IMMUTABLE;
+       }
 
-               /*
-                * The security check is questionable...  We single
-                * out the RO attribute for checking by the security
-                * module, just because it maps to a file mode.
-                */
-               err = security_inode_setattr(filp->f_path.dentry, &ia);
-               if (err)
-                       goto up;
-
-               /* This MUST be done before doing anything irreversible... */
-               err = fat_setattr(filp->f_path.dentry, &ia);
-               if (err)
-                       goto up;
-
-               fsnotify_change(filp->f_path.dentry, ia.ia_valid);
-               if (sbi->options.sys_immutable) {
-                       if (attr & ATTR_SYS)
-                               inode->i_flags |= S_IMMUTABLE;
-                       else
-                               inode->i_flags &= S_IMMUTABLE;
-               }
+       fat_save_attrs(inode, attr);
+       mark_inode_dirty(inode);
+out_drop_write:
+       mnt_drop_write(file->f_path.mnt);
+out_unlock_inode:
+       mutex_unlock(&inode->i_mutex);
+out:
+       return err;
+}
 
-               fat_save_attrs(inode, attr);
-               mark_inode_dirty(inode);
-up:
-               mnt_drop_write(filp->f_path.mnt);
-up_no_drop_write:
-               mutex_unlock(&inode->i_mutex);
-               return err;
-       }
+int fat_generic_ioctl(struct inode *inode, struct file *filp,
+                     unsigned int cmd, unsigned long arg)
+{
+       u32 __user *user_attr = (u32 __user *)arg;
+
+       switch (cmd) {
+       case FAT_IOCTL_GET_ATTRIBUTES:
+               return fat_ioctl_get_attributes(inode, user_attr);
+       case FAT_IOCTL_SET_ATTRIBUTES:
+               return fat_ioctl_set_attributes(filp, user_attr);
        default:
                return -ENOTTY; /* Inappropriate ioctl for device */
        }
@@ -225,7 +231,7 @@ static int fat_free(struct inode *inode, int skip)
                        fatent_brelse(&fatent);
                        return 0;
                } else if (ret == FAT_ENT_FREE) {
-                       fat_fs_panic(sb,
+                       fat_fs_error(sb,
                                     "%s: invalid cluster chain (i_pos %lld)",
                                     __func__, MSDOS_I(inode)->i_pos);
                        ret = -EIO;
index 51a5ecf9000ad3b95e187d0f2edac858cb164c89..304b411cb8bca697dca036fe386c8ace977305b6 100644 (file)
@@ -76,7 +76,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
                return 0;
 
        if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
-               fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)",
+               fat_fs_error(sb, "corrupted file size (i_pos %lld, %lld)",
                        MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
                return -EIO;
        }
@@ -856,6 +856,12 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
                seq_puts(m, ",flush");
        if (opts->tz_utc)
                seq_puts(m, ",tz=UTC");
+       if (opts->errors == FAT_ERRORS_CONT)
+               seq_puts(m, ",errors=continue");
+       else if (opts->errors == FAT_ERRORS_PANIC)
+               seq_puts(m, ",errors=panic");
+       else
+               seq_puts(m, ",errors=remount-ro");
 
        return 0;
 }
@@ -868,7 +874,8 @@ enum {
        Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
        Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
        Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
-       Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err,
+       Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont,
+       Opt_err_panic, Opt_err_ro, Opt_err,
 };
 
 static const match_table_t fat_tokens = {
@@ -891,6 +898,11 @@ static const match_table_t fat_tokens = {
        {Opt_showexec, "showexec"},
        {Opt_debug, "debug"},
        {Opt_immutable, "sys_immutable"},
+       {Opt_flush, "flush"},
+       {Opt_tz_utc, "tz=UTC"},
+       {Opt_err_cont, "errors=continue"},
+       {Opt_err_panic, "errors=panic"},
+       {Opt_err_ro, "errors=remount-ro"},
        {Opt_obsolate, "conv=binary"},
        {Opt_obsolate, "conv=text"},
        {Opt_obsolate, "conv=auto"},
@@ -902,8 +914,6 @@ static const match_table_t fat_tokens = {
        {Opt_obsolate, "cvf_format=%20s"},
        {Opt_obsolate, "cvf_options=%100s"},
        {Opt_obsolate, "posix"},
-       {Opt_flush, "flush"},
-       {Opt_tz_utc, "tz=UTC"},
        {Opt_err, NULL},
 };
 static const match_table_t msdos_tokens = {
@@ -973,6 +983,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
        opts->numtail = 1;
        opts->usefree = opts->nocase = 0;
        opts->tz_utc = 0;
+       opts->errors = FAT_ERRORS_RO;
        *debug = 0;
 
        if (!options)
@@ -1065,6 +1076,15 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
                case Opt_tz_utc:
                        opts->tz_utc = 1;
                        break;
+               case Opt_err_cont:
+                       opts->errors = FAT_ERRORS_CONT;
+                       break;
+               case Opt_err_panic:
+                       opts->errors = FAT_ERRORS_PANIC;
+                       break;
+               case Opt_err_ro:
+                       opts->errors = FAT_ERRORS_RO;
+                       break;
 
                /* msdos specific */
                case Opt_dots:
index ac39ebcc149676b9eb35c15c8ddcff722f43a69f..a6c20473dfd75bd83d2d6caf1d4685078c687fb4 100644 (file)
 #include "fat.h"
 
 /*
- * fat_fs_panic reports a severe file system problem and sets the file system
- * read-only. The file system can be made writable again by remounting it.
+ * fat_fs_error reports a file system problem that might indicate fa data
+ * corruption/inconsistency. Depending on 'errors' mount option the
+ * panic() is called, or error message is printed FAT and nothing is done,
+ * or filesystem is remounted read-only (default behavior).
+ * In case the file system is remounted read-only, it can be made writable
+ * again by remounting it.
  */
-void fat_fs_panic(struct super_block *s, const char *fmt, ...)
+void fat_fs_error(struct super_block *s, const char *fmt, ...)
 {
+       struct fat_mount_options *opts = &MSDOS_SB(s)->options;
        va_list args;
 
-       printk(KERN_ERR "FAT: Filesystem panic (dev %s)\n", s->s_id);
+       printk(KERN_ERR "FAT: Filesystem error (dev %s)\n", s->s_id);
 
        printk(KERN_ERR "    ");
        va_start(args, fmt);
@@ -27,13 +32,14 @@ void fat_fs_panic(struct super_block *s, const char *fmt, ...)
        va_end(args);
        printk("\n");
 
-       if (!(s->s_flags & MS_RDONLY)) {
+       if (opts->errors == FAT_ERRORS_PANIC)
+               panic("    FAT fs panic from previous error\n");
+       else if (opts->errors == FAT_ERRORS_RO && !(s->s_flags & MS_RDONLY)) {
                s->s_flags |= MS_RDONLY;
                printk(KERN_ERR "    File system has been set read-only\n");
        }
 }
-
-EXPORT_SYMBOL_GPL(fat_fs_panic);
+EXPORT_SYMBOL_GPL(fat_fs_error);
 
 /* Flushes the number of free clusters on FAT32 */
 /* XXX: Need to write one per FSINFO block.  Currently only writes 1 */
@@ -124,7 +130,7 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
                        mark_inode_dirty(inode);
        }
        if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) {
-               fat_fs_panic(sb, "clusters badly computed (%d != %llu)",
+               fat_fs_error(sb, "clusters badly computed (%d != %llu)",
                             new_fclus,
                             (llu)(inode->i_blocks >> (sbi->cluster_bits - 9)));
                fat_cache_inval_inode(inode);
index 20f522861355ae9439e5ed10303af53d8ab4c22d..82f88733b681accfa68bdeb86bed85734b9fcc6e 100644 (file)
@@ -608,7 +608,7 @@ error_inode:
                sinfo.bh = NULL;
        }
        if (corrupt < 0) {
-               fat_fs_panic(new_dir->i_sb,
+               fat_fs_error(new_dir->i_sb,
                             "%s: Filesystem corrupted (i_pos %lld)",
                             __func__, sinfo.i_pos);
        }
index f92ad9995356a5be88a260698bc72b09f1ce6401..73471b7ecc8c2bd90591f43391afaaeacf6c39af 100644 (file)
@@ -1030,7 +1030,7 @@ error_inode:
                sinfo.bh = NULL;
        }
        if (corrupt < 0) {
-               fat_fs_panic(new_dir->i_sb,
+               fat_fs_error(new_dir->i_sb,
                             "%s: Filesystem corrupted (i_pos %lld)",
                             __func__, sinfo.i_pos);
        }
index bbbd5f202e3740d7e735449eb8e6e9626d56e4f1..41d6045dbeb08b5db952e9945a054bf722470451 100644 (file)
@@ -391,6 +391,7 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
                }
                XADaddress(xp, xaddr);
                XADlength(xp, xlen);
+               XADoffset(xp, prev);
                /*
                 * only preserve the abnr flag within the xad flags
                 * of the returned hint.
index 678a067d9251f12424ee9486cc81960749bc33ec..9edcde4974aa22a37841d8b22aac86c7e435cea6 100644 (file)
@@ -475,6 +475,12 @@ struct ocfs2_path {
 #define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el)
 #define path_num_items(_path) ((_path)->p_tree_depth + 1)
 
+static int ocfs2_find_path(struct inode *inode, struct ocfs2_path *path,
+                          u32 cpos);
+static void ocfs2_adjust_rightmost_records(struct inode *inode,
+                                          handle_t *handle,
+                                          struct ocfs2_path *path,
+                                          struct ocfs2_extent_rec *insert_rec);
 /*
  * Reset the actual path elements so that we can re-use the structure
  * to build another path. Generally, this involves freeing the buffer
@@ -1012,6 +1018,54 @@ static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list  *el)
                ocfs2_rec_clusters(el, &el->l_recs[i]);
 }
 
+/*
+ * Change range of the branches in the right most path according to the leaf
+ * extent block's rightmost record.
+ */
+static int ocfs2_adjust_rightmost_branch(handle_t *handle,
+                                        struct inode *inode,
+                                        struct ocfs2_extent_tree *et)
+{
+       int status;
+       struct ocfs2_path *path = NULL;
+       struct ocfs2_extent_list *el;
+       struct ocfs2_extent_rec *rec;
+
+       path = ocfs2_new_path_from_et(et);
+       if (!path) {
+               status = -ENOMEM;
+               return status;
+       }
+
+       status = ocfs2_find_path(inode, path, UINT_MAX);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out;
+       }
+
+       status = ocfs2_extend_trans(handle, path_num_items(path) +
+                                   handle->h_buffer_credits);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out;
+       }
+
+       status = ocfs2_journal_access_path(inode, handle, path);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out;
+       }
+
+       el = path_leaf_el(path);
+       rec = &el->l_recs[le32_to_cpu(el->l_next_free_rec) - 1];
+
+       ocfs2_adjust_rightmost_records(inode, handle, path, rec);
+
+out:
+       ocfs2_free_path(path);
+       return status;
+}
+
 /*
  * Add an entire tree branch to our inode. eb_bh is the extent block
  * to start at, if we don't want to start the branch at the dinode
@@ -1038,7 +1092,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
        struct ocfs2_extent_block *eb;
        struct ocfs2_extent_list  *eb_el;
        struct ocfs2_extent_list  *el;
-       u32 new_cpos;
+       u32 new_cpos, root_end;
 
        mlog_entry_void();
 
@@ -1055,6 +1109,27 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
 
        new_blocks = le16_to_cpu(el->l_tree_depth);
 
+       eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;
+       new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list);
+       root_end = ocfs2_sum_rightmost_rec(et->et_root_el);
+
+       /*
+        * If there is a gap before the root end and the real end
+        * of the righmost leaf block, we need to remove the gap
+        * between new_cpos and root_end first so that the tree
+        * is consistent after we add a new branch(it will start
+        * from new_cpos).
+        */
+       if (root_end > new_cpos) {
+               mlog(0, "adjust the cluster end from %u to %u\n",
+                    root_end, new_cpos);
+               status = ocfs2_adjust_rightmost_branch(handle, inode, et);
+               if (status) {
+                       mlog_errno(status);
+                       goto bail;
+               }
+       }
+
        /* allocate the number of new eb blocks we need */
        new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *),
                             GFP_KERNEL);
@@ -1071,9 +1146,6 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
                goto bail;
        }
 
-       eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;
-       new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list);
-
        /* Note: new_eb_bhs[new_blocks - 1] is the guy which will be
         * linked with the rest of the tree.
         * conversly, new_eb_bhs[0] is the new bottommost leaf.
index 2a947c44e5949173817d36716ffb3c7b8bbdeec8..a1163b8b417c5cbf4ac5e1dcaf522f34a300a22b 100644 (file)
@@ -22,6 +22,9 @@
 #include <linux/crc32.h>
 #include <linux/buffer_head.h>
 #include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/fs.h>
 #include <asm/byteorder.h>
 
 #include <cluster/masklog.h>
@@ -222,6 +225,155 @@ void ocfs2_hamming_fix_block(void *data, unsigned int blocksize,
        ocfs2_hamming_fix(data, blocksize * 8, 0, fix);
 }
 
+
+/*
+ * Debugfs handling.
+ */
+
+#ifdef CONFIG_DEBUG_FS
+
+static int blockcheck_u64_get(void *data, u64 *val)
+{
+       *val = *(u64 *)data;
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(blockcheck_fops, blockcheck_u64_get, NULL, "%llu\n");
+
+static struct dentry *blockcheck_debugfs_create(const char *name,
+                                               struct dentry *parent,
+                                               u64 *value)
+{
+       return debugfs_create_file(name, S_IFREG | S_IRUSR, parent, value,
+                                  &blockcheck_fops);
+}
+
+static void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats)
+{
+       if (stats) {
+               debugfs_remove(stats->b_debug_check);
+               stats->b_debug_check = NULL;
+               debugfs_remove(stats->b_debug_failure);
+               stats->b_debug_failure = NULL;
+               debugfs_remove(stats->b_debug_recover);
+               stats->b_debug_recover = NULL;
+               debugfs_remove(stats->b_debug_dir);
+               stats->b_debug_dir = NULL;
+       }
+}
+
+static int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
+                                         struct dentry *parent)
+{
+       int rc = -EINVAL;
+
+       if (!stats)
+               goto out;
+
+       stats->b_debug_dir = debugfs_create_dir("blockcheck", parent);
+       if (!stats->b_debug_dir)
+               goto out;
+
+       stats->b_debug_check =
+               blockcheck_debugfs_create("blocks_checked",
+                                         stats->b_debug_dir,
+                                         &stats->b_check_count);
+
+       stats->b_debug_failure =
+               blockcheck_debugfs_create("checksums_failed",
+                                         stats->b_debug_dir,
+                                         &stats->b_failure_count);
+
+       stats->b_debug_recover =
+               blockcheck_debugfs_create("ecc_recoveries",
+                                         stats->b_debug_dir,
+                                         &stats->b_recover_count);
+       if (stats->b_debug_check && stats->b_debug_failure &&
+           stats->b_debug_recover)
+               rc = 0;
+
+out:
+       if (rc)
+               ocfs2_blockcheck_debug_remove(stats);
+       return rc;
+}
+#else
+static inline int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
+                                                struct dentry *parent)
+{
+       return 0;
+}
+
+static inline void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats)
+{
+}
+#endif  /* CONFIG_DEBUG_FS */
+
+/* Always-called wrappers for starting and stopping the debugfs files */
+int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
+                                          struct dentry *parent)
+{
+       return ocfs2_blockcheck_debug_install(stats, parent);
+}
+
+void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats)
+{
+       ocfs2_blockcheck_debug_remove(stats);
+}
+
+static void ocfs2_blockcheck_inc_check(struct ocfs2_blockcheck_stats *stats)
+{
+       u64 new_count;
+
+       if (!stats)
+               return;
+
+       spin_lock(&stats->b_lock);
+       stats->b_check_count++;
+       new_count = stats->b_check_count;
+       spin_unlock(&stats->b_lock);
+
+       if (!new_count)
+               mlog(ML_NOTICE, "Block check count has wrapped\n");
+}
+
+static void ocfs2_blockcheck_inc_failure(struct ocfs2_blockcheck_stats *stats)
+{
+       u64 new_count;
+
+       if (!stats)
+               return;
+
+       spin_lock(&stats->b_lock);
+       stats->b_failure_count++;
+       new_count = stats->b_failure_count;
+       spin_unlock(&stats->b_lock);
+
+       if (!new_count)
+               mlog(ML_NOTICE, "Checksum failure count has wrapped\n");
+}
+
+static void ocfs2_blockcheck_inc_recover(struct ocfs2_blockcheck_stats *stats)
+{
+       u64 new_count;
+
+       if (!stats)
+               return;
+
+       spin_lock(&stats->b_lock);
+       stats->b_recover_count++;
+       new_count = stats->b_recover_count;
+       spin_unlock(&stats->b_lock);
+
+       if (!new_count)
+               mlog(ML_NOTICE, "ECC recovery count has wrapped\n");
+}
+
+
+
+/*
+ * These are the low-level APIs for using the ocfs2_block_check structure.
+ */
+
 /*
  * This function generates check information for a block.
  * data is the block to be checked.  bc is a pointer to the
@@ -266,12 +418,15 @@ void ocfs2_block_check_compute(void *data, size_t blocksize,
  * Again, the data passed in should be the on-disk endian.
  */
 int ocfs2_block_check_validate(void *data, size_t blocksize,
-                              struct ocfs2_block_check *bc)
+                              struct ocfs2_block_check *bc,
+                              struct ocfs2_blockcheck_stats *stats)
 {
        int rc = 0;
        struct ocfs2_block_check check;
        u32 crc, ecc;
 
+       ocfs2_blockcheck_inc_check(stats);
+
        check.bc_crc32e = le32_to_cpu(bc->bc_crc32e);
        check.bc_ecc = le16_to_cpu(bc->bc_ecc);
 
@@ -282,6 +437,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize,
        if (crc == check.bc_crc32e)
                goto out;
 
+       ocfs2_blockcheck_inc_failure(stats);
        mlog(ML_ERROR,
             "CRC32 failed: stored: %u, computed %u.  Applying ECC.\n",
             (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -292,8 +448,10 @@ int ocfs2_block_check_validate(void *data, size_t blocksize,
 
        /* And check the crc32 again */
        crc = crc32_le(~0, data, blocksize);
-       if (crc == check.bc_crc32e)
+       if (crc == check.bc_crc32e) {
+               ocfs2_blockcheck_inc_recover(stats);
                goto out;
+       }
 
        mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
             (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -366,7 +524,8 @@ void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr,
  * Again, the data passed in should be the on-disk endian.
  */
 int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
-                                  struct ocfs2_block_check *bc)
+                                  struct ocfs2_block_check *bc,
+                                  struct ocfs2_blockcheck_stats *stats)
 {
        int i, rc = 0;
        struct ocfs2_block_check check;
@@ -377,6 +536,8 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
        if (!nr)
                return 0;
 
+       ocfs2_blockcheck_inc_check(stats);
+
        check.bc_crc32e = le32_to_cpu(bc->bc_crc32e);
        check.bc_ecc = le16_to_cpu(bc->bc_ecc);
 
@@ -388,6 +549,7 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
        if (crc == check.bc_crc32e)
                goto out;
 
+       ocfs2_blockcheck_inc_failure(stats);
        mlog(ML_ERROR,
             "CRC32 failed: stored: %u, computed %u.  Applying ECC.\n",
             (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -416,8 +578,10 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
        /* And check the crc32 again */
        for (i = 0, crc = ~0; i < nr; i++)
                crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size);
-       if (crc == check.bc_crc32e)
+       if (crc == check.bc_crc32e) {
+               ocfs2_blockcheck_inc_recover(stats);
                goto out;
+       }
 
        mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
             (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -448,9 +612,11 @@ int ocfs2_validate_meta_ecc(struct super_block *sb, void *data,
                            struct ocfs2_block_check *bc)
 {
        int rc = 0;
+       struct ocfs2_super *osb = OCFS2_SB(sb);
 
-       if (ocfs2_meta_ecc(OCFS2_SB(sb)))
-               rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc);
+       if (ocfs2_meta_ecc(osb))
+               rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc,
+                                               &osb->osb_ecc_stats);
 
        return rc;
 }
@@ -468,9 +634,11 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb,
                                struct ocfs2_block_check *bc)
 {
        int rc = 0;
+       struct ocfs2_super *osb = OCFS2_SB(sb);
 
-       if (ocfs2_meta_ecc(OCFS2_SB(sb)))
-               rc = ocfs2_block_check_validate_bhs(bhs, nr, bc);
+       if (ocfs2_meta_ecc(osb))
+               rc = ocfs2_block_check_validate_bhs(bhs, nr, bc,
+                                                   &osb->osb_ecc_stats);
 
        return rc;
 }
index 70ec3feda32f88d48512864ff79859bdf1af6cd6..d4b69febf70a212a8534d4d4219844f667d9b320 100644 (file)
 #define OCFS2_BLOCKCHECK_H
 
 
+/* Count errors and error correction from blockcheck.c */
+struct ocfs2_blockcheck_stats {
+       spinlock_t b_lock;
+       u64 b_check_count;      /* Number of blocks we've checked */
+       u64 b_failure_count;    /* Number of failed checksums */
+       u64 b_recover_count;    /* Number of blocks fixed by ecc */
+
+       /*
+        * debugfs entries, used if this is passed to
+        * ocfs2_blockcheck_stats_debugfs_install()
+        */
+       struct dentry *b_debug_dir;     /* Parent of the debugfs  files */
+       struct dentry *b_debug_check;   /* Exposes b_check_count */
+       struct dentry *b_debug_failure; /* Exposes b_failure_count */
+       struct dentry *b_debug_recover; /* Exposes b_recover_count */
+};
+
+
 /* High level block API */
 void ocfs2_compute_meta_ecc(struct super_block *sb, void *data,
                            struct ocfs2_block_check *bc);
@@ -37,11 +55,18 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb,
 void ocfs2_block_check_compute(void *data, size_t blocksize,
                               struct ocfs2_block_check *bc);
 int ocfs2_block_check_validate(void *data, size_t blocksize,
-                              struct ocfs2_block_check *bc);
+                              struct ocfs2_block_check *bc,
+                              struct ocfs2_blockcheck_stats *stats);
 void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr,
                                   struct ocfs2_block_check *bc);
 int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
-                                  struct ocfs2_block_check *bc);
+                                  struct ocfs2_block_check *bc,
+                                  struct ocfs2_blockcheck_stats *stats);
+
+/* Debug Initialization */
+int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
+                                          struct dentry *parent);
+void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats);
 
 /*
  * Hamming code functions
index 7e72a81bc2d4e1923f23debe1d371da66e42c72b..696c32e507160d80fde6d0fed3fd7b5724c3d6dc 100644 (file)
  * only emit the appropriage printk() when the caller passes in a constant
  * mask, as is almost always the case.
  *
- * All this bitmask nonsense is hidden from the /proc interface so that Joel
- * doesn't have an aneurism.  Reading the file gives a straight forward
- * indication of which bits are on or off:
- *     ENTRY off
- *     EXIT off
+ * All this bitmask nonsense is managed from the files under
+ * /sys/fs/o2cb/logmask/.  Reading the files gives a straightforward
+ * indication of which bits are allowed (allow) or denied (off/deny).
+ *     ENTRY deny
+ *     EXIT deny
  *     TCP off
  *     MSG off
  *     SOCKET off
- *     ERROR off
- *     NOTICE on
+ *     ERROR allow
+ *     NOTICE allow
  *
  * Writing changes the state of a given bit and requires a strictly formatted
  * single write() call:
  *
- *     write(fd, "ENTRY on", 8);
+ *     write(fd, "allow", 5);
  *
- * would turn the entry bit on.  "1" is also accepted in the place of "on", and
- * "off" and "0" behave as expected.
+ * Echoing allow/deny/off string into the logmask files can flip the bits
+ * on or off as expected; here is the bash script for example:
  *
- * Some trivial shell can flip all the bits on or off:
+ * log_mask="/sys/fs/o2cb/log_mask"
+ * for node in ENTRY EXIT TCP MSG SOCKET ERROR NOTICE; do
+ *     echo allow >"$log_mask"/"$node"
+ * done
  *
- * log_mask="/proc/fs/ocfs2_nodemanager/log_mask"
- * cat $log_mask | (
- *     while read bit status; do
- *             # $1 is "on" or "off", say
- *             echo "$bit $1" > $log_mask
- *     done
- * )
+ * The debugfs.ocfs2 tool can also flip the bits with the -l option:
+ *
+ * debugfs.ocfs2 -l TCP allow
  */
 
 /* for task_struct */
index 9fbe849f634419d9f5418d6097e789906ba460b1..334f231a422c732db5a9364596f9d9655f5dee79 100644 (file)
@@ -974,7 +974,7 @@ static int o2net_tx_can_proceed(struct o2net_node *nn,
 int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
                           size_t caller_veclen, u8 target_node, int *status)
 {
-       int ret, error = 0;
+       int ret;
        struct o2net_msg *msg = NULL;
        size_t veclen, caller_bytes = 0;
        struct kvec *vec = NULL;
@@ -1015,10 +1015,7 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
 
        o2net_set_nst_sock_time(&nst);
 
-       ret = wait_event_interruptible(nn->nn_sc_wq,
-                                      o2net_tx_can_proceed(nn, &sc, &error));
-       if (!ret && error)
-               ret = error;
+       wait_event(nn->nn_sc_wq, o2net_tx_can_proceed(nn, &sc, &ret));
        if (ret)
                goto out;
 
index c5752305627c669359f6e6cd688b9f3eecbb6958..b358f3bf896dbb5bf299fe7976397994c59c6b8d 100644 (file)
@@ -2900,6 +2900,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
        alloc = ocfs2_clusters_for_bytes(sb, bytes);
        dx_alloc = 0;
 
+       down_write(&oi->ip_alloc_sem);
+
        if (ocfs2_supports_indexed_dirs(osb)) {
                credits += ocfs2_add_dir_index_credits(sb);
 
@@ -2940,8 +2942,6 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
                goto out;
        }
 
-       down_write(&oi->ip_alloc_sem);
-
        /*
         * Prepare for worst case allocation scenario of two separate
         * extents in the unindexed tree.
@@ -2953,7 +2953,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
                mlog_errno(ret);
-               goto out_sem;
+               goto out;
        }
 
        if (vfs_dq_alloc_space_nodirty(dir,
@@ -3172,10 +3172,8 @@ out_commit:
 
        ocfs2_commit_trans(osb, handle);
 
-out_sem:
-       up_write(&oi->ip_alloc_sem);
-
 out:
+       up_write(&oi->ip_alloc_sem);
        if (data_ac)
                ocfs2_free_alloc_context(data_ac);
        if (meta_ac)
@@ -3322,11 +3320,15 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
                brelse(new_bh);
                new_bh = NULL;
 
+               down_write(&OCFS2_I(dir)->ip_alloc_sem);
+               drop_alloc_sem = 1;
                dir_i_size = i_size_read(dir);
                credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
                goto do_extend;
        }
 
+       down_write(&OCFS2_I(dir)->ip_alloc_sem);
+       drop_alloc_sem = 1;
        dir_i_size = i_size_read(dir);
        mlog(0, "extending dir %llu (i_size = %lld)\n",
             (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size);
@@ -3370,9 +3372,6 @@ do_extend:
                credits++; /* For attaching the new dirent block to the
                            * dx_root */
 
-       down_write(&OCFS2_I(dir)->ip_alloc_sem);
-       drop_alloc_sem = 1;
-
        handle = ocfs2_start_trans(osb, credits);
        if (IS_ERR(handle)) {
                status = PTR_ERR(handle);
@@ -3435,10 +3434,10 @@ bail_bh:
        *new_de_bh = new_bh;
        get_bh(*new_de_bh);
 bail:
-       if (drop_alloc_sem)
-               up_write(&OCFS2_I(dir)->ip_alloc_sem);
        if (handle)
                ocfs2_commit_trans(osb, handle);
+       if (drop_alloc_sem)
+               up_write(&OCFS2_I(dir)->ip_alloc_sem);
 
        if (data_ac)
                ocfs2_free_alloc_context(data_ac);
index e15fc7d50827019fe974b9bb61b8f5dd7312665a..6cdeaa76f27fec651b0c14f40a48e31f3aa8f71e 100644 (file)
@@ -248,6 +248,10 @@ static struct ocfs2_lock_res_ops ocfs2_nfs_sync_lops = {
        .flags          = 0,
 };
 
+static struct ocfs2_lock_res_ops ocfs2_orphan_scan_lops = {
+       .flags          = LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB,
+};
+
 static struct ocfs2_lock_res_ops ocfs2_dentry_lops = {
        .get_osb        = ocfs2_get_dentry_osb,
        .post_unlock    = ocfs2_dentry_post_unlock,
@@ -637,6 +641,19 @@ static void ocfs2_nfs_sync_lock_res_init(struct ocfs2_lock_res *res,
                                   &ocfs2_nfs_sync_lops, osb);
 }
 
+static void ocfs2_orphan_scan_lock_res_init(struct ocfs2_lock_res *res,
+                                           struct ocfs2_super *osb)
+{
+       struct ocfs2_orphan_scan_lvb *lvb;
+
+       ocfs2_lock_res_init_once(res);
+       ocfs2_build_lock_name(OCFS2_LOCK_TYPE_ORPHAN_SCAN, 0, 0, res->l_name);
+       ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_ORPHAN_SCAN,
+                                  &ocfs2_orphan_scan_lops, osb);
+       lvb = ocfs2_dlm_lvb(&res->l_lksb);
+       lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION;
+}
+
 void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
                              struct ocfs2_file_private *fp)
 {
@@ -2352,6 +2369,37 @@ void ocfs2_inode_unlock(struct inode *inode,
        mlog_exit_void();
 }
 
+int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex)
+{
+       struct ocfs2_lock_res *lockres;
+       struct ocfs2_orphan_scan_lvb *lvb;
+       int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
+       int status = 0;
+
+       lockres = &osb->osb_orphan_scan.os_lockres;
+       status = ocfs2_cluster_lock(osb, lockres, level, 0, 0);
+       if (status < 0)
+               return status;
+
+       lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
+       if (lvb->lvb_version == OCFS2_ORPHAN_LVB_VERSION)
+               *seqno = be32_to_cpu(lvb->lvb_os_seqno);
+       return status;
+}
+
+void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex)
+{
+       struct ocfs2_lock_res *lockres;
+       struct ocfs2_orphan_scan_lvb *lvb;
+       int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
+
+       lockres = &osb->osb_orphan_scan.os_lockres;
+       lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
+       lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION;
+       lvb->lvb_os_seqno = cpu_to_be32(seqno);
+       ocfs2_cluster_unlock(osb, lockres, level);
+}
+
 int ocfs2_super_lock(struct ocfs2_super *osb,
                     int ex)
 {
@@ -2842,6 +2890,7 @@ local:
        ocfs2_super_lock_res_init(&osb->osb_super_lockres, osb);
        ocfs2_rename_lock_res_init(&osb->osb_rename_lockres, osb);
        ocfs2_nfs_sync_lock_res_init(&osb->osb_nfs_sync_lockres, osb);
+       ocfs2_orphan_scan_lock_res_init(&osb->osb_orphan_scan.os_lockres, osb);
 
        osb->cconn = conn;
 
@@ -2878,6 +2927,7 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb,
        ocfs2_lock_res_free(&osb->osb_super_lockres);
        ocfs2_lock_res_free(&osb->osb_rename_lockres);
        ocfs2_lock_res_free(&osb->osb_nfs_sync_lockres);
+       ocfs2_lock_res_free(&osb->osb_orphan_scan.os_lockres);
 
        ocfs2_cluster_disconnect(osb->cconn, hangup_pending);
        osb->cconn = NULL;
@@ -3061,6 +3111,7 @@ static void ocfs2_drop_osb_locks(struct ocfs2_super *osb)
        ocfs2_simple_drop_lockres(osb, &osb->osb_super_lockres);
        ocfs2_simple_drop_lockres(osb, &osb->osb_rename_lockres);
        ocfs2_simple_drop_lockres(osb, &osb->osb_nfs_sync_lockres);
+       ocfs2_simple_drop_lockres(osb, &osb->osb_orphan_scan.os_lockres);
 }
 
 int ocfs2_drop_inode_locks(struct inode *inode)
index e1fd5721cd7f15da6e844579e1964d691af597fe..31b90d7b8f51f0dc449da138e8e7b14f118aabb4 100644 (file)
@@ -62,6 +62,14 @@ struct ocfs2_qinfo_lvb {
        __be32  lvb_free_entry;
 };
 
+#define OCFS2_ORPHAN_LVB_VERSION 1
+
+struct ocfs2_orphan_scan_lvb {
+       __u8    lvb_version;
+       __u8    lvb_reserved[3];
+       __be32  lvb_os_seqno;
+};
+
 /* ocfs2_inode_lock_full() 'arg_flags' flags */
 /* don't wait on recovery. */
 #define OCFS2_META_LOCK_RECOVERY       (0x01)
@@ -113,6 +121,9 @@ int ocfs2_super_lock(struct ocfs2_super *osb,
                     int ex);
 void ocfs2_super_unlock(struct ocfs2_super *osb,
                        int ex);
+int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex);
+void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex);
+
 int ocfs2_rename_lock(struct ocfs2_super *osb);
 void ocfs2_rename_unlock(struct ocfs2_super *osb);
 int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex);
index c2a87c885b73672db90e52aae9497c34842d1c65..07267e0da909410294a3f330eb08fea5d1feefb8 100644 (file)
@@ -187,6 +187,9 @@ static int ocfs2_sync_file(struct file *file,
        if (err)
                goto bail;
 
+       if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+               goto bail;
+
        journal = osb->journal->j_journal;
        err = jbd2_journal_force_commit(journal);
 
@@ -894,9 +897,9 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
        struct ocfs2_super *osb = OCFS2_SB(sb);
        struct buffer_head *bh = NULL;
        handle_t *handle = NULL;
-       int locked[MAXQUOTAS] = {0, 0};
-       int credits, qtype;
-       struct ocfs2_mem_dqinfo *oinfo;
+       int qtype;
+       struct dquot *transfer_from[MAXQUOTAS] = { };
+       struct dquot *transfer_to[MAXQUOTAS] = { };
 
        mlog_entry("(0x%p, '%.*s')\n", dentry,
                   dentry->d_name.len, dentry->d_name.name);
@@ -969,30 +972,37 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 
        if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
            (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
-               credits = OCFS2_INODE_UPDATE_CREDITS;
+               /*
+                * Gather pointers to quota structures so that allocation /
+                * freeing of quota structures happens here and not inside
+                * vfs_dq_transfer() where we have problems with lock ordering
+                */
                if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
                    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
                    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
-                       oinfo = sb_dqinfo(sb, USRQUOTA)->dqi_priv;
-                       status = ocfs2_lock_global_qf(oinfo, 1);
-                       if (status < 0)
+                       transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
+                                                     USRQUOTA);
+                       transfer_from[USRQUOTA] = dqget(sb, inode->i_uid,
+                                                       USRQUOTA);
+                       if (!transfer_to[USRQUOTA] || !transfer_from[USRQUOTA]) {
+                               status = -ESRCH;
                                goto bail_unlock;
-                       credits += ocfs2_calc_qinit_credits(sb, USRQUOTA) +
-                               ocfs2_calc_qdel_credits(sb, USRQUOTA);
-                       locked[USRQUOTA] = 1;
+                       }
                }
                if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
                    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
                    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
-                       oinfo = sb_dqinfo(sb, GRPQUOTA)->dqi_priv;
-                       status = ocfs2_lock_global_qf(oinfo, 1);
-                       if (status < 0)
+                       transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
+                                                     GRPQUOTA);
+                       transfer_from[GRPQUOTA] = dqget(sb, inode->i_gid,
+                                                       GRPQUOTA);
+                       if (!transfer_to[GRPQUOTA] || !transfer_from[GRPQUOTA]) {
+                               status = -ESRCH;
                                goto bail_unlock;
-                       credits += ocfs2_calc_qinit_credits(sb, GRPQUOTA) +
-                                  ocfs2_calc_qdel_credits(sb, GRPQUOTA);
-                       locked[GRPQUOTA] = 1;
+                       }
                }
-               handle = ocfs2_start_trans(osb, credits);
+               handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS +
+                                          2 * ocfs2_quota_trans_credits(sb));
                if (IS_ERR(handle)) {
                        status = PTR_ERR(handle);
                        mlog_errno(status);
@@ -1030,12 +1040,6 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 bail_commit:
        ocfs2_commit_trans(osb, handle);
 bail_unlock:
-       for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
-               if (!locked[qtype])
-                       continue;
-               oinfo = sb_dqinfo(sb, qtype)->dqi_priv;
-               ocfs2_unlock_global_qf(oinfo, 1);
-       }
        ocfs2_inode_unlock(inode, 1);
 bail_unlock_rw:
        if (size_change)
@@ -1043,6 +1047,12 @@ bail_unlock_rw:
 bail:
        brelse(bh);
 
+       /* Release quota pointers in case we acquired them */
+       for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
+               dqput(transfer_to[qtype]);
+               dqput(transfer_from[qtype]);
+       }
+
        if (!status && attr->ia_valid & ATTR_MODE) {
                status = ocfs2_acl_chmod(inode);
                if (status < 0)
index a20a0f1e37fd18e898ade8803d19ff7489df7e85..4a3b9e6b31adcc6247dc28fea3887a426f9a09d7 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/kthread.h>
+#include <linux/time.h>
+#include <linux/random.h>
 
 #define MLOG_MASK_PREFIX ML_JOURNAL
 #include <cluster/masklog.h>
@@ -52,6 +54,8 @@
 
 DEFINE_SPINLOCK(trans_inc_lock);
 
+#define ORPHAN_SCAN_SCHEDULE_TIMEOUT 300000
+
 static int ocfs2_force_read_journal(struct inode *inode);
 static int ocfs2_recover_node(struct ocfs2_super *osb,
                              int node_num, int slot_num);
@@ -1841,6 +1845,113 @@ bail:
        return status;
 }
 
+/*
+ * Scan timer should get fired every ORPHAN_SCAN_SCHEDULE_TIMEOUT. Add some
+ * randomness to the timeout to minimize multple nodes firing the timer at the
+ * same time.
+ */
+static inline unsigned long ocfs2_orphan_scan_timeout(void)
+{
+       unsigned long time;
+
+       get_random_bytes(&time, sizeof(time));
+       time = ORPHAN_SCAN_SCHEDULE_TIMEOUT + (time % 5000);
+       return msecs_to_jiffies(time);
+}
+
+/*
+ * ocfs2_queue_orphan_scan calls ocfs2_queue_recovery_completion for
+ * every slot, queuing a recovery of the slot on the ocfs2_wq thread. This
+ * is done to catch any orphans that are left over in orphan directories.
+ *
+ * ocfs2_queue_orphan_scan gets called every ORPHAN_SCAN_SCHEDULE_TIMEOUT
+ * seconds.  It gets an EX lock on os_lockres and checks sequence number
+ * stored in LVB. If the sequence number has changed, it means some other
+ * node has done the scan.  This node skips the scan and tracks the
+ * sequence number.  If the sequence number didn't change, it means a scan
+ * hasn't happened.  The node queues a scan and increments the
+ * sequence number in the LVB.
+ */
+void ocfs2_queue_orphan_scan(struct ocfs2_super *osb)
+{
+       struct ocfs2_orphan_scan *os;
+       int status, i;
+       u32 seqno = 0;
+
+       os = &osb->osb_orphan_scan;
+
+       status = ocfs2_orphan_scan_lock(osb, &seqno, DLM_LOCK_EX);
+       if (status < 0) {
+               if (status != -EAGAIN)
+                       mlog_errno(status);
+               goto out;
+       }
+
+       if (os->os_seqno != seqno) {
+               os->os_seqno = seqno;
+               goto unlock;
+       }
+
+       for (i = 0; i < osb->max_slots; i++)
+               ocfs2_queue_recovery_completion(osb->journal, i, NULL, NULL,
+                                               NULL);
+       /*
+        * We queued a recovery on orphan slots, increment the sequence
+        * number and update LVB so other node will skip the scan for a while
+        */
+       seqno++;
+       os->os_count++;
+       os->os_scantime = CURRENT_TIME;
+unlock:
+       ocfs2_orphan_scan_unlock(osb, seqno, DLM_LOCK_EX);
+out:
+       return;
+}
+
+/* Worker task that gets fired every ORPHAN_SCAN_SCHEDULE_TIMEOUT millsec */
+void ocfs2_orphan_scan_work(struct work_struct *work)
+{
+       struct ocfs2_orphan_scan *os;
+       struct ocfs2_super *osb;
+
+       os = container_of(work, struct ocfs2_orphan_scan,
+                         os_orphan_scan_work.work);
+       osb = os->os_osb;
+
+       mutex_lock(&os->os_lock);
+       ocfs2_queue_orphan_scan(osb);
+       schedule_delayed_work(&os->os_orphan_scan_work,
+                             ocfs2_orphan_scan_timeout());
+       mutex_unlock(&os->os_lock);
+}
+
+void ocfs2_orphan_scan_stop(struct ocfs2_super *osb)
+{
+       struct ocfs2_orphan_scan *os;
+
+       os = &osb->osb_orphan_scan;
+       mutex_lock(&os->os_lock);
+       cancel_delayed_work(&os->os_orphan_scan_work);
+       mutex_unlock(&os->os_lock);
+}
+
+int ocfs2_orphan_scan_init(struct ocfs2_super *osb)
+{
+       struct ocfs2_orphan_scan *os;
+
+       os = &osb->osb_orphan_scan;
+       os->os_osb = osb;
+       os->os_count = 0;
+       os->os_scantime = CURRENT_TIME;
+       mutex_init(&os->os_lock);
+
+       INIT_DELAYED_WORK(&os->os_orphan_scan_work,
+                         ocfs2_orphan_scan_work);
+       schedule_delayed_work(&os->os_orphan_scan_work,
+                             ocfs2_orphan_scan_timeout());
+       return 0;
+}
+
 struct ocfs2_orphan_filldir_priv {
        struct inode            *head;
        struct ocfs2_super      *osb;
index eb7b76331eb7733f4d9f4a5494b3509054a886b1..61045eeb3f6ea0c83f45e7e012b2aab1da34626a 100644 (file)
@@ -144,6 +144,10 @@ static inline void ocfs2_inode_set_new(struct ocfs2_super *osb,
 }
 
 /* Exported only for the journal struct init code in super.c. Do not call. */
+int ocfs2_orphan_scan_init(struct ocfs2_super *osb);
+void ocfs2_orphan_scan_stop(struct ocfs2_super *osb);
+void ocfs2_orphan_scan_exit(struct ocfs2_super *osb);
+
 void ocfs2_complete_recovery(struct work_struct *work);
 void ocfs2_wait_for_recovery(struct ocfs2_super *osb);
 
index 1386281950dbead47e4b5528cde7caae706cb3f2..18c1d9ec1c93cdc5421150e7ec39e45d4162d737 100644 (file)
@@ -47,6 +47,9 @@
 #include "ocfs2_fs.h"
 #include "ocfs2_lockid.h"
 
+/* For struct ocfs2_blockcheck_stats */
+#include "blockcheck.h"
+
 /* Most user visible OCFS2 inodes will have very few pieces of
  * metadata, but larger files (including bitmaps, etc) must be taken
  * into account when designing an access scheme. We allow a small
@@ -151,6 +154,16 @@ struct ocfs2_lock_res {
 #endif
 };
 
+struct ocfs2_orphan_scan {
+       struct mutex            os_lock;
+       struct ocfs2_super      *os_osb;
+       struct ocfs2_lock_res   os_lockres;     /* lock to synchronize scans */
+       struct delayed_work     os_orphan_scan_work;
+       struct timespec         os_scantime;  /* time this node ran the scan */
+       u32                     os_count;      /* tracks node specific scans */
+       u32                     os_seqno;       /* tracks cluster wide scans */
+};
+
 struct ocfs2_dlm_debug {
        struct kref d_refcnt;
        struct dentry *d_locking_state;
@@ -295,6 +308,7 @@ struct ocfs2_super
        struct ocfs2_dinode *local_alloc_copy;
        struct ocfs2_quota_recovery *quota_rec;
 
+       struct ocfs2_blockcheck_stats osb_ecc_stats;
        struct ocfs2_alloc_stats alloc_stats;
        char dev_str[20];               /* "major,minor" of the device */
 
@@ -341,6 +355,8 @@ struct ocfs2_super
        unsigned int                    *osb_orphan_wipes;
        wait_queue_head_t               osb_wipe_event;
 
+       struct ocfs2_orphan_scan        osb_orphan_scan;
+
        /* used to protect metaecc calculation check of xattr. */
        spinlock_t osb_xattr_lock;
 
index a53ce87481bf20b1c724d2c699fab3c52674b991..fcdba091af3dd8be6706950e83a772049bf775b1 100644 (file)
@@ -48,6 +48,7 @@ enum ocfs2_lock_type {
        OCFS2_LOCK_TYPE_FLOCK,
        OCFS2_LOCK_TYPE_QINFO,
        OCFS2_LOCK_TYPE_NFS_SYNC,
+       OCFS2_LOCK_TYPE_ORPHAN_SCAN,
        OCFS2_NUM_LOCK_TYPES
 };
 
@@ -85,6 +86,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)
                case OCFS2_LOCK_TYPE_NFS_SYNC:
                        c = 'Y';
                        break;
+               case OCFS2_LOCK_TYPE_ORPHAN_SCAN:
+                       c = 'P';
+                       break;
                default:
                        c = '\0';
        }
@@ -104,6 +108,7 @@ static char *ocfs2_lock_type_strings[] = {
        [OCFS2_LOCK_TYPE_OPEN] = "Open",
        [OCFS2_LOCK_TYPE_FLOCK] = "Flock",
        [OCFS2_LOCK_TYPE_QINFO] = "Quota",
+       [OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan",
 };
 
 static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
index 1ed0f7c868697c47c447ee611175f067def508dd..edfa60cd155c18e9ac67a1fe6ae1476900fed8b7 100644 (file)
@@ -421,6 +421,7 @@ int ocfs2_global_read_dquot(struct dquot *dquot)
        OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
        if (!dquot->dq_off) {   /* No real quota entry? */
                /* Upgrade to exclusive lock for allocation */
+               ocfs2_qinfo_unlock(info, 0);
                err = ocfs2_qinfo_lock(info, 1);
                if (err < 0)
                        goto out_qlock;
@@ -435,7 +436,8 @@ int ocfs2_global_read_dquot(struct dquot *dquot)
 out_qlock:
        if (ex)
                ocfs2_qinfo_unlock(info, 1);
-       ocfs2_qinfo_unlock(info, 0);
+       else
+               ocfs2_qinfo_unlock(info, 0);
 out:
        if (err < 0)
                mlog_errno(err);
index 07deec5e9721633e8bd88552baf840ab2cc8e2cb..5a460fa8255384f615d2dd7ca8836d3091fc58b5 100644 (file)
@@ -444,10 +444,6 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
 
        mlog_entry("ino=%lu type=%u", (unsigned long)lqinode->i_ino, type);
 
-       status = ocfs2_lock_global_qf(oinfo, 1);
-       if (status < 0)
-               goto out;
-
        list_for_each_entry_safe(rchunk, next, &(rec->r_list[type]), rc_list) {
                chunk = rchunk->rc_chunk;
                hbh = NULL;
@@ -480,12 +476,18 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                                     type);
                                goto out_put_bh;
                        }
+                       status = ocfs2_lock_global_qf(oinfo, 1);
+                       if (status < 0) {
+                               mlog_errno(status);
+                               goto out_put_dquot;
+                       }
+
                        handle = ocfs2_start_trans(OCFS2_SB(sb),
                                                   OCFS2_QSYNC_CREDITS);
                        if (IS_ERR(handle)) {
                                status = PTR_ERR(handle);
                                mlog_errno(status);
-                               goto out_put_dquot;
+                               goto out_drop_lock;
                        }
                        mutex_lock(&sb_dqopt(sb)->dqio_mutex);
                        spin_lock(&dq_data_lock);
@@ -523,6 +525,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
 out_commit:
                        mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
                        ocfs2_commit_trans(OCFS2_SB(sb), handle);
+out_drop_lock:
+                       ocfs2_unlock_global_qf(oinfo, 1);
 out_put_dquot:
                        dqput(dquot);
 out_put_bh:
@@ -537,8 +541,6 @@ out_put_bh:
                if (status < 0)
                        break;
        }
-       ocfs2_unlock_global_qf(oinfo, 1);
-out:
        if (status < 0)
                free_recovery_list(&(rec->r_list[type]));
        mlog_exit(status);
@@ -655,6 +657,9 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
        struct ocfs2_quota_recovery *rec;
        int locked = 0;
 
+       /* We don't need the lock and we have to acquire quota file locks
+        * which will later depend on this lock */
+       mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
        info->dqi_maxblimit = 0x7fffffffffffffffLL;
        info->dqi_maxilimit = 0x7fffffffffffffffLL;
        oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS);
@@ -733,6 +738,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
                goto out_err;
        }
 
+       mutex_lock(&sb_dqopt(sb)->dqio_mutex);
        return 0;
 out_err:
        if (oinfo) {
@@ -746,6 +752,7 @@ out_err:
                kfree(oinfo);
        }
        brelse(bh);
+       mutex_lock(&sb_dqopt(sb)->dqio_mutex);
        return -1;
 }
 
index 201b40a441fe806073c03bbb9fcc046f6423def7..d33767f17ba39db14dc8725ca2494fcd6ee73222 100644 (file)
@@ -119,10 +119,12 @@ static void ocfs2_release_system_inodes(struct ocfs2_super *osb);
 static int ocfs2_check_volume(struct ocfs2_super *osb);
 static int ocfs2_verify_volume(struct ocfs2_dinode *di,
                               struct buffer_head *bh,
-                              u32 sectsize);
+                              u32 sectsize,
+                              struct ocfs2_blockcheck_stats *stats);
 static int ocfs2_initialize_super(struct super_block *sb,
                                  struct buffer_head *bh,
-                                 int sector_size);
+                                 int sector_size,
+                                 struct ocfs2_blockcheck_stats *stats);
 static int ocfs2_get_sector(struct super_block *sb,
                            struct buffer_head **bh,
                            int block,
@@ -207,6 +209,7 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
        int i;
        struct ocfs2_cluster_connection *cconn = osb->cconn;
        struct ocfs2_recovery_map *rm = osb->recovery_map;
+       struct ocfs2_orphan_scan *os;
 
        out += snprintf(buf + out, len - out,
                        "%10s => Id: %-s  Uuid: %-s  Gen: 0x%X  Label: %-s\n",
@@ -308,6 +311,13 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
                                i, osb->slot_recovery_generations[i]);
        }
 
+       os = &osb->osb_orphan_scan;
+       out += snprintf(buf + out, len - out, "Orphan Scan=> ");
+       out += snprintf(buf + out, len - out, "Local: %u  Global: %u ",
+                       os->os_count, os->os_seqno);
+       out += snprintf(buf + out, len - out, " Last Scan: %lu seconds ago\n",
+                       (get_seconds() - os->os_scantime.tv_sec));
+
        return out;
 }
 
@@ -693,7 +703,8 @@ out:
 
 static int ocfs2_sb_probe(struct super_block *sb,
                          struct buffer_head **bh,
-                         int *sector_size)
+                         int *sector_size,
+                         struct ocfs2_blockcheck_stats *stats)
 {
        int status, tmpstat;
        struct ocfs1_vol_disk_hdr *hdr;
@@ -759,7 +770,8 @@ static int ocfs2_sb_probe(struct super_block *sb,
                        goto bail;
                }
                di = (struct ocfs2_dinode *) (*bh)->b_data;
-               status = ocfs2_verify_volume(di, *bh, blksize);
+               memset(stats, 0, sizeof(struct ocfs2_blockcheck_stats));
+               status = ocfs2_verify_volume(di, *bh, blksize, stats);
                if (status >= 0)
                        goto bail;
                brelse(*bh);
@@ -965,6 +977,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        struct ocfs2_super *osb = NULL;
        struct buffer_head *bh = NULL;
        char nodestr[8];
+       struct ocfs2_blockcheck_stats stats;
 
        mlog_entry("%p, %p, %i", sb, data, silent);
 
@@ -974,13 +987,13 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        /* probe for superblock */
-       status = ocfs2_sb_probe(sb, &bh, &sector_size);
+       status = ocfs2_sb_probe(sb, &bh, &sector_size, &stats);
        if (status < 0) {
                mlog(ML_ERROR, "superblock probe failed!\n");
                goto read_super_error;
        }
 
-       status = ocfs2_initialize_super(sb, bh, sector_size);
+       status = ocfs2_initialize_super(sb, bh, sector_size, &stats);
        osb = OCFS2_SB(sb);
        if (status < 0) {
                mlog_errno(status);
@@ -1090,6 +1103,18 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
                goto read_super_error;
        }
 
+       if (ocfs2_meta_ecc(osb)) {
+               status = ocfs2_blockcheck_stats_debugfs_install(
+                                               &osb->osb_ecc_stats,
+                                               osb->osb_debug_root);
+               if (status) {
+                       mlog(ML_ERROR,
+                            "Unable to create blockcheck statistics "
+                            "files\n");
+                       goto read_super_error;
+               }
+       }
+
        status = ocfs2_mount_volume(sb);
        if (osb->root_inode)
                inode = igrab(osb->root_inode);
@@ -1760,13 +1785,8 @@ static int ocfs2_mount_volume(struct super_block *sb)
        }
 
        status = ocfs2_truncate_log_init(osb);
-       if (status < 0) {
+       if (status < 0)
                mlog_errno(status);
-               goto leave;
-       }
-
-       if (ocfs2_mount_local(osb))
-               goto leave;
 
 leave:
        if (unlock_super)
@@ -1796,6 +1816,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
 
        ocfs2_truncate_log_shutdown(osb);
 
+       ocfs2_orphan_scan_stop(osb);
+
        /* This will disable recovery and flush any recovery work. */
        ocfs2_recovery_exit(osb);
 
@@ -1833,6 +1855,7 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
        if (osb->cconn)
                ocfs2_dlm_shutdown(osb, hangup_needed);
 
+       ocfs2_blockcheck_stats_debugfs_remove(&osb->osb_ecc_stats);
        debugfs_remove(osb->osb_debug_root);
 
        if (hangup_needed)
@@ -1880,7 +1903,8 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super *osb, const unsigned char *uu
 
 static int ocfs2_initialize_super(struct super_block *sb,
                                  struct buffer_head *bh,
-                                 int sector_size)
+                                 int sector_size,
+                                 struct ocfs2_blockcheck_stats *stats)
 {
        int status;
        int i, cbits, bbits;
@@ -1939,6 +1963,9 @@ static int ocfs2_initialize_super(struct super_block *sb,
        atomic_set(&osb->alloc_stats.bg_allocs, 0);
        atomic_set(&osb->alloc_stats.bg_extends, 0);
 
+       /* Copy the blockcheck stats from the superblock probe */
+       osb->osb_ecc_stats = *stats;
+
        ocfs2_init_node_maps(osb);
 
        snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u",
@@ -1951,6 +1978,13 @@ static int ocfs2_initialize_super(struct super_block *sb,
                goto bail;
        }
 
+       status = ocfs2_orphan_scan_init(osb);
+       if (status) {
+               mlog(ML_ERROR, "Unable to initialize delayed orphan scan\n");
+               mlog_errno(status);
+               goto bail;
+       }
+
        init_waitqueue_head(&osb->checkpoint_event);
        atomic_set(&osb->needs_checkpoint, 0);
 
@@ -2169,7 +2203,8 @@ bail:
  */
 static int ocfs2_verify_volume(struct ocfs2_dinode *di,
                               struct buffer_head *bh,
-                              u32 blksz)
+                              u32 blksz,
+                              struct ocfs2_blockcheck_stats *stats)
 {
        int status = -EAGAIN;
 
@@ -2182,7 +2217,8 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di,
                    OCFS2_FEATURE_INCOMPAT_META_ECC) {
                        status = ocfs2_block_check_validate(bh->b_data,
                                                            bh->b_size,
-                                                           &di->i_check);
+                                                           &di->i_check,
+                                                           stats);
                        if (status)
                                goto out;
                }
index 15631019dc634561838919310b2566e263f1d8dc..ba320e250747fd01dedcd06a85df0d2e867dbe44 100644 (file)
@@ -3154,7 +3154,7 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode,
                     le32_to_cpu(bucket_xh(bucket)->xh_entries[0].xe_name_hash));
                if (func) {
                        ret = func(inode, bucket, para);
-                       if (ret)
+                       if (ret && ret != -ERANGE)
                                mlog_errno(ret);
                        /* Fall through to bucket_relse() */
                }
@@ -3261,7 +3261,8 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
                                                  ocfs2_list_xattr_bucket,
                                                  &xl);
                if (ret) {
-                       mlog_errno(ret);
+                       if (ret != -ERANGE)
+                               mlog_errno(ret);
                        goto out;
                }
 
index a3ba217fbe74f4313a1dca88a8cc863e14766341..1d897ad808e0b1d234c302bc745a3c858848ce6b 100644 (file)
@@ -192,8 +192,11 @@ static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        int error = -ENOMEM;
        unsigned long page = get_zeroed_page(GFP_KERNEL);
-       if (page)
+       if (page) {
                error = sysfs_getlink(dentry, (char *) page); 
+               if (error < 0)
+                       free_page((unsigned long)page);
+       }
        nd_set_link(nd, error ? ERR_PTR(error) : (char *)page);
        return NULL;
 }
index 3589eab02a2f55666551e6c25393d8b740952914..3260b73abe29c322cb5f66bb5dc3337a7aedd769 100644 (file)
@@ -1937,6 +1937,9 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
        err  = bdi_init(&c->bdi);
        if (err)
                goto out_close;
+       err = bdi_register(&c->bdi, NULL, "ubifs");
+       if (err)
+               goto out_bdi;
 
        err = ubifs_parse_options(c, data, 0);
        if (err)
index 4db89e98535d25eae5be6c9496b622e1296613f7..82ec6a3c050095a018e4594fe28dec4d5408e49e 100644 (file)
@@ -47,7 +47,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20090320
+#define ACPI_CA_VERSION                 0x20090521
 
 #include "actypes.h"
 #include "actbl.h"
@@ -201,6 +201,8 @@ acpi_evaluate_object_typed(acpi_handle object,
 acpi_status
 acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer);
 
+acpi_status acpi_install_method(u8 *buffer);
+
 acpi_status
 acpi_get_next_object(acpi_object_type type,
                     acpi_handle parent,
@@ -375,7 +377,7 @@ acpi_status acpi_leave_sleep_state_prep(u8 sleep_state);
 acpi_status acpi_leave_sleep_state(u8 sleep_state);
 
 /*
- * Debug output
+ * Error/Warning output
  */
 void ACPI_INTERNAL_VAR_XFACE
 acpi_error(const char *module_name,
@@ -394,6 +396,9 @@ void ACPI_INTERNAL_VAR_XFACE
 acpi_info(const char *module_name,
          u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3);
 
+/*
+ * Debug output
+ */
 #ifdef ACPI_DEBUG_OUTPUT
 
 void ACPI_INTERNAL_VAR_XFACE
index f555d927f7c0f17bb630a2c1ca3f868205b4af68..37ba576d06e857c51a4c9b62f3d7464eee87fbd2 100644 (file)
@@ -429,20 +429,12 @@ typedef unsigned long long acpi_integer;
 
 /* Data manipulation */
 
-#define ACPI_LOWORD(l)                  ((u16)(u32)(l))
-#define ACPI_HIWORD(l)                  ((u16)((((u32)(l)) >> 16) & 0xFFFF))
-#define ACPI_LOBYTE(l)                  ((u8)(u16)(l))
-#define ACPI_HIBYTE(l)                  ((u8)((((u16)(l)) >> 8) & 0xFF))
-
-/* Full 64-bit integer must be available on both 32-bit and 64-bit platforms */
-
-struct acpi_integer_overlay {
-       u32 lo_dword;
-       u32 hi_dword;
-};
-
-#define ACPI_LODWORD(integer)           (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->lo_dword)
-#define ACPI_HIDWORD(integer)           (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->hi_dword)
+#define ACPI_LOBYTE(integer)            ((u8)   (u16)(integer))
+#define ACPI_HIBYTE(integer)            ((u8) (((u16)(integer)) >> 8))
+#define ACPI_LOWORD(integer)            ((u16)  (u32)(integer))
+#define ACPI_HIWORD(integer)            ((u16)(((u32)(integer)) >> 16))
+#define ACPI_LODWORD(integer64)         ((u32)  (u64)(integer64))
+#define ACPI_HIDWORD(integer64)         ((u32)(((u64)(integer64)) >> 32))
 
 #define ACPI_SET_BIT(target,bit)        ((target) |= (bit))
 #define ACPI_CLEAR_BIT(target,bit)      ((target) &= ~(bit))
index 8e2cdc57b1974f5430b4d39fe681090f9ffd0441..935c5d7fc86eb44f2050e5f21ba1aedd8ef0b930 100644 (file)
@@ -62,4 +62,8 @@
  */
 #define ACPI_UNUSED_VAR __attribute__ ((unused))
 
+#ifdef _ANSI
+#define inline
+#endif
+
 #endif                         /* __ACGCC_H__ */
index 6d49b2a498c4d5c92ae49d974be3b6a693b9bfae..fcb8e4b159b1cde3060d27fd1761c898fa0a0250 100644 (file)
@@ -1,11 +1,11 @@
 /******************************************************************************
  *
- * Name: aclinux.h - OS specific defines, etc.
+ * Name: aclinux.h - OS specific defines, etc. for Linux
  *
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2009, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #ifndef __ACLINUX_H__
 #define __ACLINUX_H__
 
+/* Common (in-kernel/user-space) ACPICA configuration */
+
 #define ACPI_USE_SYSTEM_CLIBRARY
 #define ACPI_USE_DO_WHILE_0
 #define ACPI_MUTEX_TYPE             ACPI_BINARY_SEMAPHORE
 
+
 #ifdef __KERNEL__
 
 #include <linux/string.h>
 #include <linux/spinlock_types.h>
 #include <asm/current.h>
 
-/* Host-dependent types and defines */
+/* Host-dependent types and defines for in-kernel ACPICA */
 
 #define ACPI_MACHINE_WIDTH          BITS_PER_LONG
-#define acpi_cache_t                        struct kmem_cache
-#define acpi_spinlock                   spinlock_t *
 #define ACPI_EXPORT_SYMBOL(symbol)  EXPORT_SYMBOL(symbol);
 #define strtoul                     simple_strtoul
 
-#else                          /* !__KERNEL__ */
+#define acpi_cache_t                        struct kmem_cache
+#define acpi_spinlock                       spinlock_t *
+#define acpi_cpu_flags                      unsigned long
+#define acpi_thread_id                      struct task_struct *
+
+#else /* !__KERNEL__ */
 
 #include <stdarg.h>
 #include <string.h>
 #include <ctype.h>
 #include <unistd.h>
 
+/* Host-dependent types and defines for user-space ACPICA */
+
+#define ACPI_FLUSH_CPU_CACHE()
+#define acpi_thread_id                      pthread_t
+
 #if defined(__ia64__) || defined(__x86_64__)
 #define ACPI_MACHINE_WIDTH          64
 #define COMPILER_DEPENDENT_INT64    long
 #define __cdecl
 #endif
 
-#define ACPI_FLUSH_CPU_CACHE()
-#endif                         /* __KERNEL__ */
+#endif /* __KERNEL__ */
 
 /* Linux uses GCC */
 
 #include "acgcc.h"
 
-#define acpi_cpu_flags unsigned long
-
-#define acpi_thread_id struct task_struct *
 
+#ifdef __KERNEL__
+/*
+ * Overrides for in-kernel ACPICA
+ */
 static inline acpi_thread_id acpi_os_get_thread_id(void)
 {
        return current;
@@ -119,30 +130,32 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
 #include <acpi/actypes.h>
 static inline void *acpi_os_allocate(acpi_size size)
 {
-       return kmalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
+       return kmalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
 }
+
 static inline void *acpi_os_allocate_zeroed(acpi_size size)
 {
-       return kzalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
+       return kzalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
 }
 
 static inline void *acpi_os_acquire_object(acpi_cache_t * cache)
 {
        return kmem_cache_zalloc(cache,
-                                irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
+               irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
 }
 
-#define ACPI_ALLOCATE(a)       acpi_os_allocate(a)
-#define ACPI_ALLOCATE_ZEROED(a)        acpi_os_allocate_zeroed(a)
-#define ACPI_FREE(a)           kfree(a)
+#define ACPI_ALLOCATE(a)        acpi_os_allocate(a)
+#define ACPI_ALLOCATE_ZEROED(a) acpi_os_allocate_zeroed(a)
+#define ACPI_FREE(a)            kfree(a)
 
-/*
- * We need to show where it is safe to preempt execution of ACPICA
- */
-#define ACPI_PREEMPTION_POINT()                \
-       do {                            \
-               if (!irqs_disabled())   \
-                       cond_resched(); \
+/* Used within ACPICA to show where it is safe to preempt execution */
+
+#define ACPI_PREEMPTION_POINT() \
+       do { \
+               if (!irqs_disabled()) \
+                       cond_resched(); \
        } while (0)
 
-#endif                         /* __ACLINUX_H__ */
+#endif /* __KERNEL__ */
+
+#endif /* __ACLINUX_H__ */
diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h
new file mode 100644 (file)
index 0000000..b18ce4f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Generic implementation of 64-bit atomics using spinlocks,
+ * useful on processors that don't have 64-bit atomic instructions.
+ *
+ * Copyright Â© 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _ASM_GENERIC_ATOMIC64_H
+#define _ASM_GENERIC_ATOMIC64_H
+
+typedef struct {
+       long long counter;
+} atomic64_t;
+
+#define ATOMIC64_INIT(i)       { (i) }
+
+extern long long atomic64_read(const atomic64_t *v);
+extern void     atomic64_set(atomic64_t *v, long long i);
+extern void     atomic64_add(long long a, atomic64_t *v);
+extern long long atomic64_add_return(long long a, atomic64_t *v);
+extern void     atomic64_sub(long long a, atomic64_t *v);
+extern long long atomic64_sub_return(long long a, atomic64_t *v);
+extern long long atomic64_dec_if_positive(atomic64_t *v);
+extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n);
+extern long long atomic64_xchg(atomic64_t *v, long long new);
+extern int      atomic64_add_unless(atomic64_t *v, long long a, long long u);
+
+#define atomic64_add_negative(a, v)    (atomic64_add_return((a), (v)) < 0)
+#define atomic64_inc(v)                        atomic64_add(1LL, (v))
+#define atomic64_inc_return(v)         atomic64_add_return(1LL, (v))
+#define atomic64_inc_and_test(v)       (atomic64_inc_return(v) == 0)
+#define atomic64_sub_and_test(a, v)    (atomic64_sub_return((a), (v)) == 0)
+#define atomic64_dec(v)                        atomic64_sub(1LL, (v))
+#define atomic64_dec_return(v)         atomic64_sub_return(1LL, (v))
+#define atomic64_dec_and_test(v)       (atomic64_dec_return((v)) == 0)
+#define atomic64_inc_not_zero(v)       atomic64_add_unless((v), 1LL, 0LL)
+
+#endif  /*  _ASM_GENERIC_ATOMIC64_H  */
index 12737be58601108f81f486fcdfac99c4875d8fb5..2a04eb54c0dd05b8eda048c8463b9a8eddabde46 100644 (file)
@@ -590,6 +590,11 @@ static inline void bio_list_merge_head(struct bio_list *bl,
        bl->head = bl2->head;
 }
 
+static inline struct bio *bio_list_peek(struct bio_list *bl)
+{
+       return bl->head;
+}
+
 static inline struct bio *bio_list_pop(struct bio_list *bl)
 {
        struct bio *bio = bl->head;
index 0b1a6cae9de1ebbc5010c2464ddc43cf33ae462b..8963d9149b5fcf77e47d9b0c32379bd8f28e2476 100644 (file)
@@ -926,6 +926,7 @@ extern void blk_queue_alignment_offset(struct request_queue *q,
                                       unsigned int alignment);
 extern void blk_queue_io_min(struct request_queue *q, unsigned int min);
 extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt);
+extern void blk_set_default_limits(struct queue_limits *lim);
 extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                            sector_t offset);
 extern void disk_stack_limits(struct gendisk *disk, struct block_device *bdev,
index a4a7b10aaa48a8b086142876272466a888069ce4..ed4e39f2c4230da03f93651f5d323f805cdb6c94 100644 (file)
@@ -114,6 +114,8 @@ extern int bus_unregister_notifier(struct bus_type *bus,
 #define BUS_NOTIFY_BOUND_DRIVER                0x00000003 /* driver bound to device */
 #define BUS_NOTIFY_UNBIND_DRIVER       0x00000004 /* driver about to be
                                                      unbound */
+#define BUS_NOTIFY_UNBOUND_DRIVER      0x00000005 /* driver is unbound
+                                                     from the device */
 
 extern struct kset *bus_get_kset(struct bus_type *bus);
 extern struct klist *bus_get_device_klist(struct bus_type *bus);
@@ -192,6 +194,7 @@ struct class {
        struct kobject                  *dev_kobj;
 
        int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
+       char *(*nodename)(struct device *dev);
 
        void (*class_release)(struct class *class);
        void (*dev_release)(struct device *dev);
@@ -287,6 +290,7 @@ struct device_type {
        const char *name;
        struct attribute_group **groups;
        int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
+       char *(*nodename)(struct device *dev);
        void (*release)(struct device *dev);
 
        struct dev_pm_ops *pm;
@@ -486,6 +490,7 @@ extern struct device *device_find_child(struct device *dev, void *data,
 extern int device_rename(struct device *dev, char *new_name);
 extern int device_move(struct device *dev, struct device *new_parent,
                       enum dpm_order dpm_order);
+extern const char *device_get_nodename(struct device *dev, const char **tmp);
 
 /*
  * Root device objects for grouping under /sys/devices
index e61c0be2a45977fb61e48b0b0eb89f016b7c978d..6925249a5ac656a7cda3c104d04914816e303ff4 100644 (file)
@@ -78,12 +78,12 @@ static inline void eisa_driver_unregister (struct eisa_driver *edrv) { }
 /* Mimics pci.h... */
 static inline void *eisa_get_drvdata (struct eisa_device *edev)
 {
-        return edev->dev.driver_data;
+        return dev_get_drvdata(&edev->dev);
 }
 
 static inline void eisa_set_drvdata (struct eisa_device *edev, void *data)
 {
-        edev->dev.driver_data = data;
+        dev_set_drvdata(&edev->dev, data);
 }
 
 /* The EISA root device. There's rumours about machines with multiple
index c8ecf5b2a207371d5662234ec4eb9be9d3420c14..d31544628436cb717b88079f7f99bf6e9b775b68 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/types.h>
 #include <linux/compiler.h>
 
-#define FIRMWARE_NAME_MAX 30 
 #define FW_ACTION_NOHOTPLUG 0
 #define FW_ACTION_HOTPLUG 1
 
index 7cbd38d363a2f051af1abbd30d7bbf90c066151e..45fc320a53c6f002fbb466d2b38315254b19ff94 100644 (file)
@@ -142,7 +142,7 @@ struct gendisk {
                                          * disks that can't be partitioned. */
 
        char disk_name[DISK_NAME_LEN];  /* name of major driver */
-
+       char *(*nodename)(struct gendisk *gd);
        /* Array of pointers to partitions indexed by partno.
         * Protected with matching bdev lock but stat and other
         * non-critical accesses use RCU.  Always access through
index 883cd44ff765d9d90fdac42c11f51062bb8b8ef3..c5a71c38a95f5521b17aef7ca178e43e2ca11b0e 100644 (file)
@@ -97,12 +97,14 @@ extern const char linux_proc_banner[];
 #define        KERN_INFO       "<6>"   /* informational                        */
 #define        KERN_DEBUG      "<7>"   /* debug-level messages                 */
 
+/* Use the default kernel loglevel */
+#define KERN_DEFAULT   "<d>"
 /*
  * Annotation for a "continued" line of log printout (only done after a
  * line that had no enclosing \n). Only to be used by core/arch code
  * during early bootup (a continued line is not SMP-safe otherwise).
  */
-#define        KERN_CONT       ""
+#define        KERN_CONT       "<c>"
 
 extern int console_printk[];
 
@@ -406,7 +408,7 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
  *
  * Use tracing_on/tracing_off when you want to quickly turn on or off
  * tracing. It simply enables or disables the recording of the trace events.
- * This also corresponds to the user space debugfs/tracing/tracing_on
+ * This also corresponds to the user space /sys/kernel/debug/tracing/tracing_on
  * file, which gives a means for the kernel and userspace to interact.
  * Place a tracing_off() in the kernel where you want tracing to end.
  * From user space, examine the trace, and then echo 1 > tracing_on
diff --git a/include/linux/mg_disk.h b/include/linux/mg_disk.h
new file mode 100644 (file)
index 0000000..e11f4d9
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  include/linux/mg_disk.c
+ *
+ *  Private data for mflash platform driver
+ *
+ * (c) 2008 mGine Co.,LTD
+ * (c) 2008 unsik Kim <donari75@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#ifndef __MG_DISK_H__
+#define __MG_DISK_H__
+
+/* name for platform device */
+#define MG_DEV_NAME "mg_disk"
+
+/* names of GPIO resource */
+#define MG_RST_PIN     "mg_rst"
+/* except MG_BOOT_DEV, reset-out pin should be assigned */
+#define MG_RSTOUT_PIN  "mg_rstout"
+
+/* device attribution */
+/* use mflash as boot device */
+#define MG_BOOT_DEV            (1 << 0)
+/* use mflash as storage device */
+#define MG_STORAGE_DEV         (1 << 1)
+/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */
+#define MG_STORAGE_DEV_SKIP_RST        (1 << 2)
+
+/* private driver data */
+struct mg_drv_data {
+       /* disk resource */
+       u32 use_polling;
+
+       /* device attribution */
+       u32 dev_attr;
+
+       /* internally used */
+       void *host;
+};
+
+#endif
index beb6ec99cfefb768b4ff43488c1a6137715eda15..052117744629bfd05e300528f99e5675574dda3e 100644 (file)
@@ -41,6 +41,7 @@ struct miscdevice  {
        struct list_head list;
        struct device *parent;
        struct device *this_device;
+       const char *devnode;
 };
 
 extern int misc_register(struct miscdevice * misc);
index b67bb5d7b2211208da085524a1e2cdf2fdb41c00..8dc5123b63057f3e16ca400847477282a993e892 100644 (file)
@@ -36,8 +36,8 @@ extern struct device platform_bus;
 
 extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);
 extern int platform_get_irq(struct platform_device *, unsigned int);
-extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, char *);
-extern int platform_get_irq_byname(struct platform_device *, char *);
+extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, const char *);
+extern int platform_get_irq_byname(struct platform_device *, const char *);
 extern int platform_add_devices(struct platform_device **, int);
 
 extern struct platform_device *platform_device_register_simple(const char *, int id,
index c900aa530070d7c08ad4a0851e684ac6931c98b9..7531b1c28201eaec27d7afc650711ed014fa0644 100644 (file)
@@ -674,7 +674,7 @@ struct user_struct {
        struct task_group *tg;
 #ifdef CONFIG_SYSFS
        struct kobject kobj;
-       struct work_struct work;
+       struct delayed_work work;
 #endif
 #endif
 
index 14df7e635d439e07d438e9890f0c8f718fa2aa15..b9dc4ca0246f1b802983e7a672d0093601f6d587 100644 (file)
@@ -198,7 +198,7 @@ static inline void tracepoint_synchronize_unregister(void)
  *     * This is how the trace record is structured and will
  *     * be saved into the ring buffer. These are the fields
  *     * that will be exposed to user-space in
- *     * /debug/tracing/events/<*>/format.
+ *     * /sys/kernel/debug/tracing/events/<*>/format.
  *     *
  *     * The declared 'local variable' is called '__entry'
  *     *
@@ -258,7 +258,7 @@ static inline void tracepoint_synchronize_unregister(void)
  * tracepoint callback (this is used by programmatic plugins and
  * can also by used by generic instrumentation like SystemTap), and
  * it is also used to expose a structured trace record in
- * /debug/tracing/events/.
+ * /sys/kernel/debug/tracing/events/.
  */
 
 #define TRACE_EVENT(name, proto, args, struct, assign, print)  \
index 7e6b5259ea35f4a9fb88d8b2cae678211e0abc4f..84929e9140341583cbc8fd7050c4e5e5a12b8d29 100644 (file)
@@ -888,6 +888,8 @@ struct usb_driver {
  * struct usb_device_driver - identifies USB device driver to usbcore
  * @name: The driver name should be unique among USB drivers,
  *     and should normally be the same as the module name.
+ * @nodename: Callback to provide a naming hint for a possible
+ *     device node to create.
  * @probe: Called to see if the driver is willing to manage a particular
  *     device.  If it is, probe returns zero and uses dev_set_drvdata()
  *     to associate driver-specific data with the device.  If unwilling
@@ -931,6 +933,7 @@ extern struct bus_type usb_bus_type;
  */
 struct usb_class_driver {
        char *name;
+       char *(*nodename)(struct device *dev);
        const struct file_operations *fops;
        int minor_base;
 };
index fed6dc31b0dae854c26ac29216fc5a08824eaa53..c4b3c6d51a72bae4e3f127b68c67ebdde8684bd8 100644 (file)
@@ -616,13 +616,13 @@ config SYSFS_DEPRECATED
        bool
 
 config SYSFS_DEPRECATED_V2
-       bool "Create deprecated sysfs layout for older userspace tools"
+       bool "remove sysfs features which may confuse old userspace tools"
        depends on SYSFS
-       default y
+       default n
        select SYSFS_DEPRECATED
        help
          This option switches the layout of sysfs to the deprecated
-         version.
+         version. Do not use it on recent distributions.
 
          The current sysfs layout features a unified device tree at
          /sys/devices/, which is able to express a hierarchy between
index e4ab36ce767222becc860650e0892399ab58b96d..215aaab09e91e1e76839f403dc2e4474a512ef40 100644 (file)
@@ -2899,7 +2899,7 @@ void print_modules(void)
        struct module *mod;
        char buf[8];
 
-       printk("Modules linked in:");
+       printk(KERN_DEFAULT "Modules linked in:");
        /* Most callers should already have preempt disabled, but make sure */
        preempt_disable();
        list_for_each_entry_rcu(mod, &modules, list)
index 5052b5497c67995f57c6b548b0b52c1989f4027b..b4d97b54c1ecfa729eaa4b07dc2f721c25bca3ca 100644 (file)
@@ -687,20 +687,35 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                                  sizeof(printk_buf) - printed_len, fmt, args);
 
 
+       p = printk_buf;
+
+       /* Do we have a loglevel in the string? */
+       if (p[0] == '<') {
+               unsigned char c = p[1];
+               if (c && p[2] == '>') {
+                       switch (c) {
+                       case '0' ... '7': /* loglevel */
+                               current_log_level = c - '0';
+                       /* Fallthrough - make sure we're on a new line */
+                       case 'd': /* KERN_DEFAULT */
+                               if (!new_text_line) {
+                                       emit_log_char('\n');
+                                       new_text_line = 1;
+                               }
+                       /* Fallthrough - skip the loglevel */
+                       case 'c': /* KERN_CONT */
+                               p += 3;
+                               break;
+                       }
+               }
+       }
+
        /*
         * Copy the output into log_buf.  If the caller didn't provide
         * appropriate log level tags, we insert them here
         */
-       for (p = printk_buf; *p; p++) {
+       for ( ; *p; p++) {
                if (new_text_line) {
-                       /* If a token, set current_log_level and skip over */
-                       if (p[0] == '<' && p[1] >= '0' && p[1] <= '7' &&
-                           p[2] == '>') {
-                               current_log_level = p[1] - '0';
-                               p += 3;
-                               printed_len -= 3;
-                       }
-
                        /* Always output the token */
                        emit_log_char('<');
                        emit_log_char(current_log_level + '0');
index 4a13e5a01ce318c62c75c991a8694096e4821f40..61071fecc82e5a6f2ed1dad5605efe35a40e3f6e 100644 (file)
@@ -147,7 +147,7 @@ config IRQSOFF_TRACER
          disabled by default and can be runtime (re-)started
          via:
 
-             echo 0 > /debugfs/tracing/tracing_max_latency
+             echo 0 > /sys/kernel/debug/tracing/tracing_max_latency
 
          (Note that kernel size and overhead increases with this option
          enabled. This option and the preempt-off timing option can be
@@ -168,7 +168,7 @@ config PREEMPT_TRACER
          disabled by default and can be runtime (re-)started
          via:
 
-             echo 0 > /debugfs/tracing/tracing_max_latency
+             echo 0 > /sys/kernel/debug/tracing/tracing_max_latency
 
          (Note that kernel size and overhead increases with this option
          enabled. This option and the irqs-off timing option can be
@@ -261,7 +261,7 @@ config PROFILE_ANNOTATED_BRANCHES
          This tracer profiles all the the likely and unlikely macros
          in the kernel. It will display the results in:
 
-         /debugfs/tracing/profile_annotated_branch
+         /sys/kernel/debug/tracing/profile_annotated_branch
 
          Note: this will add a significant overhead, only turn this
          on if you need to profile the system's use of these macros.
@@ -274,7 +274,7 @@ config PROFILE_ALL_BRANCHES
          taken in the kernel is recorded whether it hit or miss.
          The results will be displayed in:
 
-         /debugfs/tracing/profile_branch
+         /sys/kernel/debug/tracing/profile_branch
 
          This option also enables the likely/unlikely profiler.
 
@@ -323,7 +323,7 @@ config STACK_TRACER
        select KALLSYMS
        help
          This special tracer records the maximum stack footprint of the
-         kernel and displays it in debugfs/tracing/stack_trace.
+         kernel and displays it in /sys/kernel/debug/tracing/stack_trace.
 
          This tracer works by hooking into every function call that the
          kernel executes, and keeping a maximum stack depth value and
index 8acd9b81a5d76046ee52c9d1dc9224cc43edb1c2..c1878bfb2e1ec4fe8efbf56764a341023b1307c3 100644 (file)
@@ -344,7 +344,7 @@ static raw_spinlock_t ftrace_max_lock =
 /*
  * Copy the new maximum trace into the separate maximum-trace
  * structure. (this way the maximum trace is permanently saved,
- * for later retrieval via /debugfs/tracing/latency_trace)
+ * for later retrieval via /sys/kernel/debug/tracing/latency_trace)
  */
 static void
 __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
@@ -2414,21 +2414,20 @@ static const struct file_operations tracing_iter_fops = {
 
 static const char readme_msg[] =
        "tracing mini-HOWTO:\n\n"
-       "# mkdir /debug\n"
-       "# mount -t debugfs nodev /debug\n\n"
-       "# cat /debug/tracing/available_tracers\n"
+       "# mount -t debugfs nodev /sys/kernel/debug\n\n"
+       "# cat /sys/kernel/debug/tracing/available_tracers\n"
        "wakeup preemptirqsoff preemptoff irqsoff function sched_switch nop\n\n"
-       "# cat /debug/tracing/current_tracer\n"
+       "# cat /sys/kernel/debug/tracing/current_tracer\n"
        "nop\n"
-       "# echo sched_switch > /debug/tracing/current_tracer\n"
-       "# cat /debug/tracing/current_tracer\n"
+       "# echo sched_switch > /sys/kernel/debug/tracing/current_tracer\n"
+       "# cat /sys/kernel/debug/tracing/current_tracer\n"
        "sched_switch\n"
-       "# cat /debug/tracing/trace_options\n"
+       "# cat /sys/kernel/debug/tracing/trace_options\n"
        "noprint-parent nosym-offset nosym-addr noverbose\n"
-       "# echo print-parent > /debug/tracing/trace_options\n"
-       "# echo 1 > /debug/tracing/tracing_enabled\n"
-       "# cat /debug/tracing/trace > /tmp/trace.txt\n"
-       "# echo 0 > /debug/tracing/tracing_enabled\n"
+       "# echo print-parent > /sys/kernel/debug/tracing/trace_options\n"
+       "# echo 1 > /sys/kernel/debug/tracing/tracing_enabled\n"
+       "# cat /sys/kernel/debug/tracing/trace > /tmp/trace.txt\n"
+       "# echo 0 > /sys/kernel/debug/tracing/tracing_enabled\n"
 ;
 
 static ssize_t
index 850e0ba41c1e60f7983f2c3e7890bee4b2bec53c..2c000e7132acec2201a872e992ca0fc791894528 100644 (file)
@@ -75,21 +75,6 @@ static void uid_hash_remove(struct user_struct *up)
        put_user_ns(up->user_ns);
 }
 
-static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
-{
-       struct user_struct *user;
-       struct hlist_node *h;
-
-       hlist_for_each_entry(user, h, hashent, uidhash_node) {
-               if (user->uid == uid) {
-                       atomic_inc(&user->__count);
-                       return user;
-               }
-       }
-
-       return NULL;
-}
-
 #ifdef CONFIG_USER_SCHED
 
 static void sched_destroy_user(struct user_struct *up)
@@ -119,6 +104,23 @@ static int sched_create_user(struct user_struct *up) { return 0; }
 
 #if defined(CONFIG_USER_SCHED) && defined(CONFIG_SYSFS)
 
+static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
+{
+       struct user_struct *user;
+       struct hlist_node *h;
+
+       hlist_for_each_entry(user, h, hashent, uidhash_node) {
+               if (user->uid == uid) {
+                       /* possibly resurrect an "almost deleted" object */
+                       if (atomic_inc_return(&user->__count) == 1)
+                               cancel_delayed_work(&user->work);
+                       return user;
+               }
+       }
+
+       return NULL;
+}
+
 static struct kset *uids_kset; /* represents the /sys/kernel/uids/ directory */
 static DEFINE_MUTEX(uids_mutex);
 
@@ -283,12 +285,12 @@ int __init uids_sysfs_init(void)
        return uids_user_create(&root_user);
 }
 
-/* work function to remove sysfs directory for a user and free up
+/* delayed work function to remove sysfs directory for a user and free up
  * corresponding structures.
  */
 static void cleanup_user_struct(struct work_struct *w)
 {
-       struct user_struct *up = container_of(w, struct user_struct, work);
+       struct user_struct *up = container_of(w, struct user_struct, work.work);
        unsigned long flags;
        int remove_user = 0;
 
@@ -297,15 +299,12 @@ static void cleanup_user_struct(struct work_struct *w)
         */
        uids_mutex_lock();
 
-       local_irq_save(flags);
-
-       if (atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
+       spin_lock_irqsave(&uidhash_lock, flags);
+       if (atomic_read(&up->__count) == 0) {
                uid_hash_remove(up);
                remove_user = 1;
-               spin_unlock_irqrestore(&uidhash_lock, flags);
-       } else {
-               local_irq_restore(flags);
        }
+       spin_unlock_irqrestore(&uidhash_lock, flags);
 
        if (!remove_user)
                goto done;
@@ -331,16 +330,28 @@ done:
  */
 static void free_user(struct user_struct *up, unsigned long flags)
 {
-       /* restore back the count */
-       atomic_inc(&up->__count);
        spin_unlock_irqrestore(&uidhash_lock, flags);
-
-       INIT_WORK(&up->work, cleanup_user_struct);
-       schedule_work(&up->work);
+       INIT_DELAYED_WORK(&up->work, cleanup_user_struct);
+       schedule_delayed_work(&up->work, msecs_to_jiffies(1000));
 }
 
 #else  /* CONFIG_USER_SCHED && CONFIG_SYSFS */
 
+static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
+{
+       struct user_struct *user;
+       struct hlist_node *h;
+
+       hlist_for_each_entry(user, h, hashent, uidhash_node) {
+               if (user->uid == uid) {
+                       atomic_inc(&user->__count);
+                       return user;
+               }
+       }
+
+       return NULL;
+}
+
 int uids_sysfs_init(void) { return 0; }
 static inline int uids_user_create(struct user_struct *up) { return 0; }
 static inline void uids_mutex_lock(void) { }
index 9960be04cbbe608cad81733096dd49d73928dbba..bb1326d3839c9aaa468e6ad501a1087389b1934f 100644 (file)
@@ -194,4 +194,10 @@ config DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
 config NLATTR
        bool
 
+#
+# Generic 64-bit atomic support is selected if needed
+#
+config GENERIC_ATOMIC64
+       bool
+
 endmenu
index 34c5c0e6222ecf289112358c44751badd60569ab..8e9bcf9d3261cb09b91cb6f42e2e5750c8b16812 100644 (file)
@@ -95,6 +95,8 @@ obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o
 
 obj-$(CONFIG_GENERIC_CSUM) += checksum.o
 
+obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o
+
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
 
diff --git a/lib/atomic64.c b/lib/atomic64.c
new file mode 100644 (file)
index 0000000..c5e7255
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Generic implementation of 64-bit atomics using spinlocks,
+ * useful on processors that don't have 64-bit atomic instructions.
+ *
+ * Copyright Â© 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+
+/*
+ * We use a hashed array of spinlocks to provide exclusive access
+ * to each atomic64_t variable.  Since this is expected to used on
+ * systems with small numbers of CPUs (<= 4 or so), we use a
+ * relatively small array of 16 spinlocks to avoid wasting too much
+ * memory on the spinlock array.
+ */
+#define NR_LOCKS       16
+
+/*
+ * Ensure each lock is in a separate cacheline.
+ */
+static union {
+       spinlock_t lock;
+       char pad[L1_CACHE_BYTES];
+} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp;
+
+static inline spinlock_t *lock_addr(const atomic64_t *v)
+{
+       unsigned long addr = (unsigned long) v;
+
+       addr >>= L1_CACHE_SHIFT;
+       addr ^= (addr >> 8) ^ (addr >> 16);
+       return &atomic64_lock[addr & (NR_LOCKS - 1)].lock;
+}
+
+long long atomic64_read(const atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+void atomic64_set(atomic64_t *v, long long i)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+
+       spin_lock_irqsave(lock, flags);
+       v->counter = i;
+       spin_unlock_irqrestore(lock, flags);
+}
+
+void atomic64_add(long long a, atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+
+       spin_lock_irqsave(lock, flags);
+       v->counter += a;
+       spin_unlock_irqrestore(lock, flags);
+}
+
+long long atomic64_add_return(long long a, atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter += a;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+void atomic64_sub(long long a, atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+
+       spin_lock_irqsave(lock, flags);
+       v->counter -= a;
+       spin_unlock_irqrestore(lock, flags);
+}
+
+long long atomic64_sub_return(long long a, atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter -= a;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+long long atomic64_dec_if_positive(atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter - 1;
+       if (val >= 0)
+               v->counter = val;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter;
+       if (val == o)
+               v->counter = n;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+long long atomic64_xchg(atomic64_t *v, long long new)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter;
+       v->counter = new;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+int atomic64_add_unless(atomic64_t *v, long long a, long long u)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       int ret = 1;
+
+       spin_lock_irqsave(lock, flags);
+       if (v->counter != u) {
+               v->counter += a;
+               ret = 0;
+       }
+       spin_unlock_irqrestore(lock, flags);
+       return ret;
+}
+
+static int init_atomic64_lock(void)
+{
+       int i;
+
+       for (i = 0; i < NR_LOCKS; ++i)
+               spin_lock_init(&atomic64_lock[i].lock);
+       return 0;
+}
+
+pure_initcall(init_atomic64_lock);
index bacf6fe4f7a0347bb958ebc85a059ab582eb93b4..b512b746d2aff464e1c18a01c53300ef7b6e68f4 100644 (file)
@@ -793,11 +793,16 @@ static struct kset *kset_create(const char *name,
                                struct kobject *parent_kobj)
 {
        struct kset *kset;
+       int retval;
 
        kset = kzalloc(sizeof(*kset), GFP_KERNEL);
        if (!kset)
                return NULL;
-       kobject_set_name(&kset->kobj, name);
+       retval = kobject_set_name(&kset->kobj, name);
+       if (retval) {
+               kfree(kset);
+               return NULL;
+       }
        kset->uevent_ops = uevent_ops;
        kset->kobj.parent = parent_kobj;
 
index 71830ba7b986a8e4da4b448793791bf2bc65c245..6f4610a9ce55fe10de35b24c42850533bce2b7aa 100644 (file)
@@ -128,11 +128,11 @@ config SPARSEMEM_VMEMMAP
 config MEMORY_HOTPLUG
        bool "Allow for memory hot-add"
        depends on SPARSEMEM || X86_64_ACPI_NUMA
-       depends on HOTPLUG && !HIBERNATION && ARCH_ENABLE_MEMORY_HOTPLUG
+       depends on HOTPLUG && !(HIBERNATION && !S390) && ARCH_ENABLE_MEMORY_HOTPLUG
        depends on (IA64 || X86 || PPC64 || SUPERH || S390)
 
 comment "Memory hotplug is currently incompatible with Software Suspend"
-       depends on SPARSEMEM && HOTPLUG && HIBERNATION
+       depends on SPARSEMEM && HOTPLUG && HIBERNATION && !S390
 
 config MEMORY_HOTPLUG_SPARSE
        def_bool y
index 4ebe3ea837952a3f784159a9009212c3506e4a0f..a2b76a588e348e0d46f2bfed4131af6ac3eea86b 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
-#include <linux/blktrace_api.h>
 #include <asm/tlbflush.h>
 
 #include <trace/events/block.h>
index 68eb1d9b63fa5daba881a8b6551fa38f8e0eabfc..25878cc49daa268806f46dfa4e05af8d6f8f3998 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
-#include <linux/blktrace_api.h>
 #include <asm/tlbflush.h>
 
 /*
index a9b3a6f9ea95f18f2ea8325a72741fb61e0c14cf..656cbd1958250d54542c2318130dc26a81182a4a 100644 (file)
@@ -1,11 +1,12 @@
 /*
- *  linux/net/iucv/af_iucv.c
- *
  *  IUCV protocol stack for Linux on zSeries
  *
- *  Copyright 2006 IBM Corporation
+ *  Copyright IBM Corp. 2006, 2009
  *
  *  Author(s): Jennifer Hunt <jenhunt@us.ibm.com>
+ *             Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ *  PM functions:
+ *             Ursula Braun <ursula.braun@de.ibm.com>
  */
 
 #define KMSG_COMPONENT "af_iucv"
@@ -90,6 +91,122 @@ static inline void low_nmcpy(unsigned char *dst, char *src)
        memcpy(&dst[8], src, 8);
 }
 
+static int afiucv_pm_prepare(struct device *dev)
+{
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "afiucv_pm_prepare\n");
+#endif
+       return 0;
+}
+
+static void afiucv_pm_complete(struct device *dev)
+{
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "afiucv_pm_complete\n");
+#endif
+       return;
+}
+
+/**
+ * afiucv_pm_freeze() - Freeze PM callback
+ * @dev:       AFIUCV dummy device
+ *
+ * Sever all established IUCV communication pathes
+ */
+static int afiucv_pm_freeze(struct device *dev)
+{
+       struct iucv_sock *iucv;
+       struct sock *sk;
+       struct hlist_node *node;
+       int err = 0;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "afiucv_pm_freeze\n");
+#endif
+       read_lock(&iucv_sk_list.lock);
+       sk_for_each(sk, node, &iucv_sk_list.head) {
+               iucv = iucv_sk(sk);
+               skb_queue_purge(&iucv->send_skb_q);
+               skb_queue_purge(&iucv->backlog_skb_q);
+               switch (sk->sk_state) {
+               case IUCV_SEVERED:
+               case IUCV_DISCONN:
+               case IUCV_CLOSING:
+               case IUCV_CONNECTED:
+                       if (iucv->path) {
+                               err = iucv_path_sever(iucv->path, NULL);
+                               iucv_path_free(iucv->path);
+                               iucv->path = NULL;
+                       }
+                       break;
+               case IUCV_OPEN:
+               case IUCV_BOUND:
+               case IUCV_LISTEN:
+               case IUCV_CLOSED:
+               default:
+                       break;
+               }
+       }
+       read_unlock(&iucv_sk_list.lock);
+       return err;
+}
+
+/**
+ * afiucv_pm_restore_thaw() - Thaw and restore PM callback
+ * @dev:       AFIUCV dummy device
+ *
+ * socket clean up after freeze
+ */
+static int afiucv_pm_restore_thaw(struct device *dev)
+{
+       struct iucv_sock *iucv;
+       struct sock *sk;
+       struct hlist_node *node;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "afiucv_pm_restore_thaw\n");
+#endif
+       read_lock(&iucv_sk_list.lock);
+       sk_for_each(sk, node, &iucv_sk_list.head) {
+               iucv = iucv_sk(sk);
+               switch (sk->sk_state) {
+               case IUCV_CONNECTED:
+                       sk->sk_err = EPIPE;
+                       sk->sk_state = IUCV_DISCONN;
+                       sk->sk_state_change(sk);
+                       break;
+               case IUCV_DISCONN:
+               case IUCV_SEVERED:
+               case IUCV_CLOSING:
+               case IUCV_LISTEN:
+               case IUCV_BOUND:
+               case IUCV_OPEN:
+               default:
+                       break;
+               }
+       }
+       read_unlock(&iucv_sk_list.lock);
+       return 0;
+}
+
+static struct dev_pm_ops afiucv_pm_ops = {
+       .prepare = afiucv_pm_prepare,
+       .complete = afiucv_pm_complete,
+       .freeze = afiucv_pm_freeze,
+       .thaw = afiucv_pm_restore_thaw,
+       .restore = afiucv_pm_restore_thaw,
+};
+
+static struct device_driver af_iucv_driver = {
+       .owner = THIS_MODULE,
+       .name = "afiucv",
+       .bus  = &iucv_bus,
+       .pm   = &afiucv_pm_ops,
+};
+
+/* dummy device used as trigger for PM functions */
+static struct device *af_iucv_dev;
+
 /**
  * iucv_msg_length() - Returns the length of an iucv message.
  * @msg:       Pointer to struct iucv_message, MUST NOT be NULL
@@ -1556,8 +1673,30 @@ static int __init afiucv_init(void)
        err = sock_register(&iucv_sock_family_ops);
        if (err)
                goto out_proto;
+       /* establish dummy device */
+       err = driver_register(&af_iucv_driver);
+       if (err)
+               goto out_sock;
+       af_iucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+       if (!af_iucv_dev) {
+               err = -ENOMEM;
+               goto out_driver;
+       }
+       dev_set_name(af_iucv_dev, "af_iucv");
+       af_iucv_dev->bus = &iucv_bus;
+       af_iucv_dev->parent = iucv_root;
+       af_iucv_dev->release = (void (*)(struct device *))kfree;
+       af_iucv_dev->driver = &af_iucv_driver;
+       err = device_register(af_iucv_dev);
+       if (err)
+               goto out_driver;
+
        return 0;
 
+out_driver:
+       driver_unregister(&af_iucv_driver);
+out_sock:
+       sock_unregister(PF_IUCV);
 out_proto:
        proto_unregister(&iucv_proto);
 out_iucv:
@@ -1568,6 +1707,8 @@ out:
 
 static void __exit afiucv_exit(void)
 {
+       device_unregister(af_iucv_dev);
+       driver_unregister(&af_iucv_driver);
        sock_unregister(PF_IUCV);
        proto_unregister(&iucv_proto);
        iucv_unregister(&af_iucv_handler, 0);
index 61e8038a55ee300d3875ffcf01532624bc691dd6..c833481d32e383439b98504e84a68250d4f9c98e 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * IUCV base infrastructure.
  *
- * Copyright 2001, 2006 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2001, 2009
+ *
  * Author(s):
  *    Original source:
  *     Alan Altmark (Alan_Altmark@us.ibm.com)  Sept. 2000
@@ -10,6 +11,8 @@
  *     Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
  *    Rewritten for af_iucv:
  *     Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *    PM functions:
+ *     Ursula Braun (ursula.braun@de.ibm.com)
  *
  * Documentation used:
  *    The original source
@@ -45,6 +48,7 @@
 #include <linux/err.h>
 #include <linux/device.h>
 #include <linux/cpu.h>
+#include <linux/reboot.h>
 #include <net/iucv/iucv.h>
 #include <asm/atomic.h>
 #include <asm/ebcdic.h>
@@ -75,9 +79,24 @@ static int iucv_bus_match(struct device *dev, struct device_driver *drv)
        return 0;
 }
 
+static int iucv_pm_prepare(struct device *);
+static void iucv_pm_complete(struct device *);
+static int iucv_pm_freeze(struct device *);
+static int iucv_pm_thaw(struct device *);
+static int iucv_pm_restore(struct device *);
+
+static struct dev_pm_ops iucv_pm_ops = {
+       .prepare = iucv_pm_prepare,
+       .complete = iucv_pm_complete,
+       .freeze = iucv_pm_freeze,
+       .thaw = iucv_pm_thaw,
+       .restore = iucv_pm_restore,
+};
+
 struct bus_type iucv_bus = {
        .name = "iucv",
        .match = iucv_bus_match,
+       .pm = &iucv_pm_ops,
 };
 EXPORT_SYMBOL(iucv_bus);
 
@@ -147,6 +166,7 @@ enum iucv_command_codes {
        IUCV_RESUME = 14,
        IUCV_SEVER = 15,
        IUCV_SETMASK = 16,
+       IUCV_SETCONTROLMASK = 17,
 };
 
 /*
@@ -364,6 +384,18 @@ static void iucv_allow_cpu(void *data)
        parm->set_mask.ipmask = 0xf8;
        iucv_call_b2f0(IUCV_SETMASK, parm);
 
+       /*
+        * Enable all iucv control interrupts.
+        * ipmask contains bits for the different interrupts
+        *      0x80 - Flag to allow pending connections interrupts
+        *      0x40 - Flag to allow connection complete interrupts
+        *      0x20 - Flag to allow connection severed interrupts
+        *      0x10 - Flag to allow connection quiesced interrupts
+        *      0x08 - Flag to allow connection resumed interrupts
+        */
+       memset(parm, 0, sizeof(union iucv_param));
+       parm->set_mask.ipmask = 0xf8;
+       iucv_call_b2f0(IUCV_SETCONTROLMASK, parm);
        /* Set indication that iucv interrupts are allowed for this cpu. */
        cpu_set(cpu, iucv_irq_cpumask);
 }
@@ -388,6 +420,31 @@ static void iucv_block_cpu(void *data)
        cpu_clear(cpu, iucv_irq_cpumask);
 }
 
+/**
+ * iucv_block_cpu_almost
+ * @data: unused
+ *
+ * Allow connection-severed interrupts only on this cpu.
+ */
+static void iucv_block_cpu_almost(void *data)
+{
+       int cpu = smp_processor_id();
+       union iucv_param *parm;
+
+       /* Allow iucv control interrupts only */
+       parm = iucv_param_irq[cpu];
+       memset(parm, 0, sizeof(union iucv_param));
+       parm->set_mask.ipmask = 0x08;
+       iucv_call_b2f0(IUCV_SETMASK, parm);
+       /* Allow iucv-severed interrupt only */
+       memset(parm, 0, sizeof(union iucv_param));
+       parm->set_mask.ipmask = 0x20;
+       iucv_call_b2f0(IUCV_SETCONTROLMASK, parm);
+
+       /* Clear indication that iucv interrupts are allowed for this cpu. */
+       cpu_clear(cpu, iucv_irq_cpumask);
+}
+
 /**
  * iucv_declare_cpu
  * @data: unused
@@ -758,6 +815,28 @@ void iucv_unregister(struct iucv_handler *handler, int smp)
 }
 EXPORT_SYMBOL(iucv_unregister);
 
+static int iucv_reboot_event(struct notifier_block *this,
+                            unsigned long event, void *ptr)
+{
+       int i, rc;
+
+       get_online_cpus();
+       on_each_cpu(iucv_block_cpu, NULL, 1);
+       preempt_disable();
+       for (i = 0; i < iucv_max_pathid; i++) {
+               if (iucv_path_table[i])
+                       rc = iucv_sever_pathid(i, NULL);
+       }
+       preempt_enable();
+       put_online_cpus();
+       iucv_disable();
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block iucv_reboot_notifier = {
+       .notifier_call = iucv_reboot_event,
+};
+
 /**
  * iucv_path_accept
  * @path: address of iucv path structure
@@ -777,6 +856,10 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        /* Prepare parameter block. */
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
@@ -792,6 +875,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
                path->msglim = parm->ctrl.ipmsglim;
                path->flags = parm->ctrl.ipflags1;
        }
+out:
        local_bh_enable();
        return rc;
 }
@@ -821,6 +905,10 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
 
        spin_lock_bh(&iucv_table_lock);
        iucv_cleanup_queue();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        parm->ctrl.ipmsglim = path->msglim;
@@ -855,6 +943,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
                        rc = -EIO;
                }
        }
+out:
        spin_unlock_bh(&iucv_table_lock);
        return rc;
 }
@@ -876,12 +965,17 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16])
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        if (userdata)
                memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
        parm->ctrl.ippathid = path->pathid;
        rc = iucv_call_b2f0(IUCV_QUIESCE, parm);
+out:
        local_bh_enable();
        return rc;
 }
@@ -903,12 +997,17 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16])
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        if (userdata)
                memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
        parm->ctrl.ippathid = path->pathid;
        rc = iucv_call_b2f0(IUCV_RESUME, parm);
+out:
        local_bh_enable();
        return rc;
 }
@@ -927,6 +1026,10 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16])
        int rc;
 
        preempt_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        if (iucv_active_cpu != smp_processor_id())
                spin_lock_bh(&iucv_table_lock);
        rc = iucv_sever_pathid(path->pathid, userdata);
@@ -934,6 +1037,7 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16])
        list_del_init(&path->list);
        if (iucv_active_cpu != smp_processor_id())
                spin_unlock_bh(&iucv_table_lock);
+out:
        preempt_enable();
        return rc;
 }
@@ -956,6 +1060,10 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        parm->purge.ippathid = path->pathid;
@@ -967,6 +1075,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
                msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8;
                msg->tag = parm->purge.ipmsgtag;
        }
+out:
        local_bh_enable();
        return rc;
 }
@@ -1043,6 +1152,10 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
        if (msg->flags & IUCV_IPRMDATA)
                return iucv_message_receive_iprmdata(path, msg, flags,
                                                     buffer, size, residual);
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        parm->db.ipbfadr1 = (u32)(addr_t) buffer;
@@ -1058,6 +1171,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
                if (residual)
                        *residual = parm->db.ipbfln1f;
        }
+out:
        return rc;
 }
 EXPORT_SYMBOL(__iucv_message_receive);
@@ -1111,6 +1225,10 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg)
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        parm->db.ippathid = path->pathid;
@@ -1118,6 +1236,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg)
        parm->db.iptrgcls = msg->class;
        parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID);
        rc = iucv_call_b2f0(IUCV_REJECT, parm);
+out:
        local_bh_enable();
        return rc;
 }
@@ -1145,6 +1264,10 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        if (flags & IUCV_IPRMDATA) {
@@ -1162,6 +1285,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
                parm->db.iptrgcls = msg->class;
        }
        rc = iucv_call_b2f0(IUCV_REPLY, parm);
+out:
        local_bh_enable();
        return rc;
 }
@@ -1190,6 +1314,10 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
        union iucv_param *parm;
        int rc;
 
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        if (flags & IUCV_IPRMDATA) {
@@ -1212,6 +1340,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
        rc = iucv_call_b2f0(IUCV_SEND, parm);
        if (!rc)
                msg->id = parm->db.ipmsgid;
+out:
        return rc;
 }
 EXPORT_SYMBOL(__iucv_message_send);
@@ -1272,6 +1401,10 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        if (flags & IUCV_IPRMDATA) {
@@ -1297,6 +1430,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
        rc = iucv_call_b2f0(IUCV_SEND, parm);
        if (!rc)
                msg->id = parm->db.ipmsgid;
+out:
        local_bh_enable();
        return rc;
 }
@@ -1687,6 +1821,130 @@ static void iucv_external_interrupt(u16 code)
        spin_unlock(&iucv_queue_lock);
 }
 
+static int iucv_pm_prepare(struct device *dev)
+{
+       int rc = 0;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_INFO "iucv_pm_prepare\n");
+#endif
+       if (dev->driver && dev->driver->pm && dev->driver->pm->prepare)
+               rc = dev->driver->pm->prepare(dev);
+       return rc;
+}
+
+static void iucv_pm_complete(struct device *dev)
+{
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_INFO "iucv_pm_complete\n");
+#endif
+       if (dev->driver && dev->driver->pm && dev->driver->pm->complete)
+               dev->driver->pm->complete(dev);
+}
+
+/**
+ * iucv_path_table_empty() - determine if iucv path table is empty
+ *
+ * Returns 0 if there are still iucv pathes defined
+ *        1 if there are no iucv pathes defined
+ */
+int iucv_path_table_empty(void)
+{
+       int i;
+
+       for (i = 0; i < iucv_max_pathid; i++) {
+               if (iucv_path_table[i])
+                       return 0;
+       }
+       return 1;
+}
+
+/**
+ * iucv_pm_freeze() - Freeze PM callback
+ * @dev:       iucv-based device
+ *
+ * disable iucv interrupts
+ * invoke callback function of the iucv-based driver
+ * shut down iucv, if no iucv-pathes are established anymore
+ */
+static int iucv_pm_freeze(struct device *dev)
+{
+       int cpu;
+       int rc = 0;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "iucv_pm_freeze\n");
+#endif
+       for_each_cpu_mask_nr(cpu, iucv_irq_cpumask)
+               smp_call_function_single(cpu, iucv_block_cpu_almost, NULL, 1);
+       if (dev->driver && dev->driver->pm && dev->driver->pm->freeze)
+               rc = dev->driver->pm->freeze(dev);
+       if (iucv_path_table_empty())
+               iucv_disable();
+       return rc;
+}
+
+/**
+ * iucv_pm_thaw() - Thaw PM callback
+ * @dev:       iucv-based device
+ *
+ * make iucv ready for use again: allocate path table, declare interrupt buffers
+ *                               and enable iucv interrupts
+ * invoke callback function of the iucv-based driver
+ */
+static int iucv_pm_thaw(struct device *dev)
+{
+       int rc = 0;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "iucv_pm_thaw\n");
+#endif
+       if (!iucv_path_table) {
+               rc = iucv_enable();
+               if (rc)
+                       goto out;
+       }
+       if (cpus_empty(iucv_irq_cpumask)) {
+               if (iucv_nonsmp_handler)
+                       /* enable interrupts on one cpu */
+                       iucv_allow_cpu(NULL);
+               else
+                       /* enable interrupts on all cpus */
+                       iucv_setmask_mp();
+       }
+       if (dev->driver && dev->driver->pm && dev->driver->pm->thaw)
+               rc = dev->driver->pm->thaw(dev);
+out:
+       return rc;
+}
+
+/**
+ * iucv_pm_restore() - Restore PM callback
+ * @dev:       iucv-based device
+ *
+ * make iucv ready for use again: allocate path table, declare interrupt buffers
+ *                               and enable iucv interrupts
+ * invoke callback function of the iucv-based driver
+ */
+static int iucv_pm_restore(struct device *dev)
+{
+       int rc = 0;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "iucv_pm_restore %p\n", iucv_path_table);
+#endif
+       if (cpus_empty(iucv_irq_cpumask)) {
+               rc = iucv_query_maxconn();
+               rc = iucv_enable();
+               if (rc)
+                       goto out;
+       }
+       if (dev->driver && dev->driver->pm && dev->driver->pm->restore)
+               rc = dev->driver->pm->restore(dev);
+out:
+       return rc;
+}
+
 /**
  * iucv_init
  *
@@ -1740,15 +1998,20 @@ static int __init iucv_init(void)
        rc = register_hotcpu_notifier(&iucv_cpu_notifier);
        if (rc)
                goto out_free;
+       rc = register_reboot_notifier(&iucv_reboot_notifier);
+       if (rc)
+               goto out_cpu;
        ASCEBC(iucv_error_no_listener, 16);
        ASCEBC(iucv_error_no_memory, 16);
        ASCEBC(iucv_error_pathid, 16);
        iucv_available = 1;
        rc = bus_register(&iucv_bus);
        if (rc)
-               goto out_cpu;
+               goto out_reboot;
        return 0;
 
+out_reboot:
+       unregister_reboot_notifier(&iucv_reboot_notifier);
 out_cpu:
        unregister_hotcpu_notifier(&iucv_cpu_notifier);
 out_free:
@@ -1783,6 +2046,7 @@ static void __exit iucv_exit(void)
        list_for_each_entry_safe(p, n, &iucv_work_queue, list)
                kfree(p);
        spin_unlock_irq(&iucv_queue_lock);
+       unregister_reboot_notifier(&iucv_reboot_notifier);
        unregister_hotcpu_notifier(&iucv_cpu_notifier);
        for_each_possible_cpu(cpu) {
                kfree(iucv_param_irq[cpu]);
index b75d28cba3f75fef74d90d01b2fb8990984a1c55..428b065ba6959791e4f7ab4c180a914c9e3ba917 100644 (file)
@@ -26,7 +26,8 @@ config SAMPLE_TRACE_EVENTS
          This build trace event example modules.
 
 config SAMPLE_KOBJECT
-       tristate "Build kobject examples"
+       tristate "Build kobject examples -- loadable modules only"
+       depends on m
        help
          This config option will allow you to build a number of
          different kobject sample modules showing how to use kobjects,
diff --git a/samples/firmware_class/firmware_sample_driver.c b/samples/firmware_class/firmware_sample_driver.c
deleted file mode 100644 (file)
index 219a298..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * firmware_sample_driver.c -
- *
- * Copyright (c) 2003 Manuel Estrada Sainz
- *
- * Sample code on how to use request_firmware() from drivers.
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/string.h>
-#include <linux/firmware.h>
-
-static struct device ghost_device = {
-       .bus_id    = "ghost0",
-};
-
-
-static void sample_firmware_load(char *firmware, int size)
-{
-       u8 buf[size+1];
-       memcpy(buf, firmware, size);
-       buf[size] = '\0';
-       printk(KERN_INFO "firmware_sample_driver: firmware: %s\n", buf);
-}
-
-static void sample_probe_default(void)
-{
-       /* uses the default method to get the firmware */
-       const struct firmware *fw_entry;
-       int retval;
-
-       printk(KERN_INFO "firmware_sample_driver: "
-               "a ghost device got inserted :)\n");
-
-       retval = request_firmware(&fw_entry, "sample_driver_fw", &ghost_device);
-       if (retval) {
-               printk(KERN_ERR
-                      "firmware_sample_driver: Firmware not available\n");
-               return;
-       }
-
-       sample_firmware_load(fw_entry->data, fw_entry->size);
-
-       release_firmware(fw_entry);
-
-       /* finish setting up the device */
-}
-
-static void sample_probe_specific(void)
-{
-       int retval;
-       /* Uses some specific hotplug support to get the firmware from
-        * userspace  directly into the hardware, or via some sysfs file */
-
-       /* NOTE: This currently doesn't work */
-
-       printk(KERN_INFO "firmware_sample_driver: "
-               "a ghost device got inserted :)\n");
-
-       retval = request_firmware(NULL, "sample_driver_fw", &ghost_device);
-       if (retval) {
-               printk(KERN_ERR
-                      "firmware_sample_driver: Firmware load failed\n");
-               return;
-       }
-
-       /* request_firmware blocks until userspace finished, so at
-        * this point the firmware should be already in the device */
-
-       /* finish setting up the device */
-}
-
-static void sample_probe_async_cont(const struct firmware *fw, void *context)
-{
-       if (!fw) {
-               printk(KERN_ERR
-                      "firmware_sample_driver: firmware load failed\n");
-               return;
-       }
-
-       printk(KERN_INFO "firmware_sample_driver: device pointer \"%s\"\n",
-              (char *)context);
-       sample_firmware_load(fw->data, fw->size);
-}
-
-static void sample_probe_async(void)
-{
-       /* Let's say that I can't sleep */
-       int error;
-       error = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
-                                       "sample_driver_fw", &ghost_device,
-                                       "my device pointer",
-                                       sample_probe_async_cont);
-       if (error)
-               printk(KERN_ERR "firmware_sample_driver:"
-                      " request_firmware_nowait failed\n");
-}
-
-static int __init sample_init(void)
-{
-       device_initialize(&ghost_device);
-       /* since there is no real hardware insertion I just call the
-        * sample probe functions here */
-       sample_probe_specific();
-       sample_probe_default();
-       sample_probe_async();
-       return 0;
-}
-
-static void __exit sample_exit(void)
-{
-}
-
-module_init(sample_init);
-module_exit(sample_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/samples/firmware_class/firmware_sample_firmware_class.c b/samples/firmware_class/firmware_sample_firmware_class.c
deleted file mode 100644 (file)
index e6cf7a4..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * firmware_sample_firmware_class.c -
- *
- * Copyright (c) 2003 Manuel Estrada Sainz
- *
- * NOTE: This is just a probe of concept, if you think that your driver would
- * be well served by this mechanism please contact me first.
- *
- * DON'T USE THIS CODE AS IS
- *
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/firmware.h>
-
-
-MODULE_AUTHOR("Manuel Estrada Sainz");
-MODULE_DESCRIPTION("Hackish sample for using firmware class directly");
-MODULE_LICENSE("GPL");
-
-static inline struct class_device *to_class_dev(struct kobject *obj)
-{
-       return container_of(obj, struct class_device, kobj);
-}
-
-static inline
-struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
-{
-       return container_of(_attr, struct class_device_attribute, attr);
-}
-
-struct firmware_priv {
-       char fw_id[FIRMWARE_NAME_MAX];
-       s32 loading:2;
-       u32 abort:1;
-};
-
-static ssize_t firmware_loading_show(struct class_device *class_dev, char *buf)
-{
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-       return sprintf(buf, "%d\n", fw_priv->loading);
-}
-
-static ssize_t firmware_loading_store(struct class_device *class_dev,
-                                     const char *buf, size_t count)
-{
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-       int prev_loading = fw_priv->loading;
-
-       fw_priv->loading = simple_strtol(buf, NULL, 10);
-
-       switch (fw_priv->loading) {
-       case -1:
-               /* abort load an panic */
-               break;
-       case 1:
-               /* setup load */
-               break;
-       case 0:
-               if (prev_loading == 1) {
-                       /* finish load and get the device back to working
-                        * state */
-               }
-               break;
-       }
-
-       return count;
-}
-static CLASS_DEVICE_ATTR(loading, 0644,
-                        firmware_loading_show, firmware_loading_store);
-
-static ssize_t firmware_data_read(struct kobject *kobj,
-                                 struct bin_attribute *bin_attr,
-                                 char *buffer, loff_t offset, size_t count)
-{
-       struct class_device *class_dev = to_class_dev(kobj);
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-
-       /* read from the devices firmware memory */
-
-       return count;
-}
-static ssize_t firmware_data_write(struct kobject *kobj,
-                                  struct bin_attribute *bin_attr,
-                                  char *buffer, loff_t offset, size_t count)
-{
-       struct class_device *class_dev = to_class_dev(kobj);
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-
-       /* write to the devices firmware memory */
-
-       return count;
-}
-static struct bin_attribute firmware_attr_data = {
-       .attr = {.name = "data", .mode = 0644},
-       .size = 0,
-       .read = firmware_data_read,
-       .write = firmware_data_write,
-};
-static int fw_setup_class_device(struct class_device *class_dev,
-                                const char *fw_name,
-                                struct device *device)
-{
-       int retval;
-       struct firmware_priv *fw_priv;
-
-       fw_priv = kzalloc(sizeof(struct firmware_priv), GFP_KERNEL);
-       if (!fw_priv) {
-               retval = -ENOMEM;
-               goto out;
-       }
-
-       memset(class_dev, 0, sizeof(*class_dev));
-
-       strncpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX);
-       fw_priv->fw_id[FIRMWARE_NAME_MAX-1] = '\0';
-
-       strncpy(class_dev->class_id, device->bus_id, BUS_ID_SIZE);
-       class_dev->class_id[BUS_ID_SIZE-1] = '\0';
-       class_dev->dev = device;
-
-       class_dev->class = &firmware_class;
-       class_set_devdata(class_dev, fw_priv);
-       retval = class_device_register(class_dev);
-       if (retval) {
-               printk(KERN_ERR "%s: class_device_register failed\n",
-                      __func__);
-               goto error_free_fw_priv;
-       }
-
-       retval = sysfs_create_bin_file(&class_dev->kobj, &firmware_attr_data);
-       if (retval) {
-               printk(KERN_ERR "%s: sysfs_create_bin_file failed\n",
-                      __func__);
-               goto error_unreg_class_dev;
-       }
-
-       retval = class_device_create_file(class_dev,
-                                         &class_device_attr_loading);
-       if (retval) {
-               printk(KERN_ERR "%s: class_device_create_file failed\n",
-                      __func__);
-               goto error_remove_data;
-       }
-
-       goto out;
-
-error_remove_data:
-       sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data);
-error_unreg_class_dev:
-       class_device_unregister(class_dev);
-error_free_fw_priv:
-       kfree(fw_priv);
-out:
-       return retval;
-}
-static void fw_remove_class_device(struct class_device *class_dev)
-{
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-
-       class_device_remove_file(class_dev, &class_device_attr_loading);
-       sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data);
-       class_device_unregister(class_dev);
-}
-
-static struct class_device *class_dev;
-
-static struct device my_device = {
-       .bus_id    = "my_dev0",
-};
-
-static int __init firmware_sample_init(void)
-{
-       int error;
-
-       device_initialize(&my_device);
-       class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL);
-       if (!class_dev)
-               return -ENOMEM;
-
-       error = fw_setup_class_device(class_dev, "my_firmware_image",
-                                     &my_device);
-       if (error) {
-               kfree(class_dev);
-               return error;
-       }
-       return 0;
-
-}
-static void __exit firmware_sample_exit(void)
-{
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-       fw_remove_class_device(class_dev);
-       kfree(fw_priv);
-       kfree(class_dev);
-}
-
-module_init(firmware_sample_init);
-module_exit(firmware_sample_exit);
index 91033e67321e84e6479816cdff61c372f3be58d1..7109e2b5bc0acf61e39c24aff4b2074016e6078c 100755 (executable)
@@ -226,6 +226,26 @@ if ($arch eq "x86_64") {
     if ($is_module eq "0") {
         $cc .= " -mconstant-gp";
     }
+} elsif ($arch eq "sparc64") {
+    # In the objdump output there are giblets like:
+    # 0000000000000000 <igmp_net_exit-0x18>:
+    # As there's some data blobs that get emitted into the
+    # text section before the first instructions and the first
+    # real symbols.  We don't want to match that, so to combat
+    # this we use '\w' so we'll match just plain symbol names,
+    # and not those that also include hex offsets inside of the
+    # '<>' brackets.  Actually the generic function_regex setting
+    # could safely use this too.
+    $function_regex = "^([0-9a-fA-F]+)\\s+<(\\w*?)>:";
+
+    # Sparc64 calls '_mcount' instead of plain 'mcount'.
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
+
+    $alignment = 8;
+    $type = ".xword";
+    $ld .= " -m elf64_sparc";
+    $cc .= " -m64";
+    $objcopy .= " -O elf64-sparc";
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
index 902f9a992620446ed42acf46390226f71ac22fa7..db40fa04cd513f4a68d86af935fec02f27e507d2 100644 (file)
@@ -12,10 +12,9 @@ calls. Only the functions's names and the the call time are provided.
 
 Usage:
        Be sure that you have CONFIG_FUNCTION_TRACER
-       # mkdir /debugfs
-       # mount -t debug debug /debug
-       # echo function > /debug/tracing/current_tracer
-       $ cat /debug/tracing/trace_pipe > ~/raw_trace_func
+       # mount -t debugfs nodev /sys/kernel/debug
+       # echo function > /sys/kernel/debug/tracing/current_tracer
+       $ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func
        Wait some times but not too much, the script is a bit slow.
        Break the pipe (Ctrl + Z)
        $ scripts/draw_functrace.py < raw_trace_func > draw_functrace
index 80fb2baed7a72c52ea9330336039bfe0835c621a..b0adc8094009912d00db252f7388680299475f7e 100644 (file)
@@ -259,7 +259,6 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        int n_amixer = apcm->substream->runtime->channels, i = 0;
        int device = apcm->substream->pcm->device;
        unsigned int pitch;
-       unsigned long flags;
 
        if (NULL != apcm->src) {
                /* Prepared pcm playback */
@@ -311,10 +310,10 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        src = apcm->src;
        for (i = 0; i < n_amixer; i++) {
                amixer = apcm->amixers[i];
-               spin_lock_irqsave(&atc->atc_lock, flags);
+               mutex_lock(&atc->atc_mutex);
                amixer->ops->setup(amixer, &src->rsc,
                                        INIT_VOL, atc->pcm[i+device*2]);
-               spin_unlock_irqrestore(&atc->atc_lock, flags);
+               mutex_unlock(&atc->atc_mutex);
                src = src->ops->next_interleave(src);
                if (NULL == src)
                        src = apcm->src;
@@ -865,7 +864,6 @@ static int
 spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 {
        struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
-       unsigned long flags;
        unsigned int rate = apcm->substream->runtime->rate;
        unsigned int status;
        int err;
@@ -885,7 +883,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
                return -ENOENT;
        }
 
-       spin_lock_irqsave(&atc->atc_lock, flags);
+       mutex_lock(&atc->atc_mutex);
        dao->ops->get_spos(dao, &status);
        if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) {
                status &= ((~IEC958_AES3_CON_FS) << 24);
@@ -895,7 +893,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        }
        if ((rate != atc->pll_rate) && (32000 != rate))
                err = atc_pll_init(atc, rate);
-       spin_unlock_irqrestore(&atc->atc_lock, flags);
+       mutex_unlock(&atc->atc_mutex);
 
        return err;
 }
@@ -908,7 +906,6 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        struct dao *dao;
        int err;
        int i;
-       unsigned long flags;
 
        if (NULL != apcm->src)
                return 0;
@@ -934,13 +931,13 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
                        src = apcm->src;
        }
        /* Connect to SPDIFOO */
-       spin_lock_irqsave(&atc->atc_lock, flags);
+       mutex_lock(&atc->atc_mutex);
        dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
        amixer = apcm->amixers[0];
        dao->ops->set_left_input(dao, &amixer->rsc);
        amixer = apcm->amixers[1];
        dao->ops->set_right_input(dao, &amixer->rsc);
-       spin_unlock_irqrestore(&atc->atc_lock, flags);
+       mutex_unlock(&atc->atc_mutex);
 
        ct_timer_prepare(apcm->timer);
 
@@ -1088,7 +1085,6 @@ static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status)
 
 static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
 {
-       unsigned long flags;
        struct dao_desc da_dsc = {0};
        struct dao *dao;
        int err;
@@ -1096,7 +1092,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
        struct rsc *rscs[2] = {NULL};
        unsigned int spos = 0;
 
-       spin_lock_irqsave(&atc->atc_lock, flags);
+       mutex_lock(&atc->atc_mutex);
        dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
        da_dsc.msr = state ? 1 : atc->msr;
        da_dsc.passthru = state ? 1 : 0;
@@ -1114,7 +1110,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
        }
        dao->ops->set_spos(dao, spos);
        dao->ops->commit_write(dao);
-       spin_unlock_irqrestore(&atc->atc_lock, flags);
+       mutex_unlock(&atc->atc_mutex);
 
        return err;
 }
@@ -1572,7 +1568,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
        atc->msr = msr;
        atc->chip_type = chip_type;
 
-       spin_lock_init(&atc->atc_lock);
+       mutex_init(&atc->atc_mutex);
 
        /* Find card model */
        err = atc_identify_card(atc);
index a03347232e8453bde510dbb8d23c7bf551d1b940..9fe620ea5f3f3bc1ab38125e111c46e134fd2f34 100644 (file)
@@ -19,7 +19,7 @@
 #define CTATC_H
 
 #include <linux/types.h>
-#include <linux/spinlock_types.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/timer.h>
 #include <sound/core.h>
@@ -90,7 +90,7 @@ struct ct_atc {
        void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
        unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index);
 
-       spinlock_t atc_lock;
+       struct mutex atc_mutex;
 
        int (*pcm_playback_prepare)(struct ct_atc *atc,
                                    struct ct_atc_pcm *apcm);
index 779c6c3591a5b297180eb001f85e682779cebf29..93b0aedc36d448be8ae902c6f1e2e5213934a84c 100644 (file)
@@ -180,7 +180,7 @@ static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
  *
  * call this inside the lock and irq disabled
  */
-static int ct_xfitimer_reprogram(struct ct_timer *atimer)
+static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update)
 {
        struct ct_timer_instance *ti;
        unsigned int min_intr = (unsigned int)-1;
@@ -216,6 +216,8 @@ static int ct_xfitimer_reprogram(struct ct_timer *atimer)
                        ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
                                                 rate - 1, rate);
                }
+               if (ti->need_update && !can_update)
+                       min_intr = 0; /* pending to the next irq */
                if (ti->frag_count < min_intr)
                        min_intr = ti->frag_count;
        }
@@ -235,7 +237,7 @@ static void ct_xfitimer_check_period(struct ct_timer *atimer)
 
        spin_lock_irqsave(&atimer->list_lock, flags);
        list_for_each_entry(ti, &atimer->instance_head, instance_list) {
-               if (ti->need_update) {
+               if (ti->running && ti->need_update) {
                        ti->need_update = 0;
                        ti->apcm->interrupt(ti->apcm);
                }
@@ -252,7 +254,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer)
        spin_lock_irqsave(&atimer->lock, flags);
        atimer->irq_handling = 1;
        do {
-               update = ct_xfitimer_reprogram(atimer);
+               update = ct_xfitimer_reprogram(atimer, 1);
                spin_unlock(&atimer->lock);
                if (update)
                        ct_xfitimer_check_period(atimer);
@@ -265,6 +267,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer)
 static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
 {
        ti->frag_count = ti->substream->runtime->period_size;
+       ti->running = 0;
        ti->need_update = 0;
 }
 
@@ -273,7 +276,6 @@ static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
 static void ct_xfitimer_update(struct ct_timer *atimer)
 {
        unsigned long flags;
-       int update;
 
        spin_lock_irqsave(&atimer->lock, flags);
        if (atimer->irq_handling) {
@@ -284,10 +286,8 @@ static void ct_xfitimer_update(struct ct_timer *atimer)
        }
 
        ct_xfitimer_irq_stop(atimer);
-       update = ct_xfitimer_reprogram(atimer);
+       ct_xfitimer_reprogram(atimer, 0);
        spin_unlock_irqrestore(&atimer->lock, flags);
-       if (update)
-               ct_xfitimer_check_period(atimer);
 }
 
 static void ct_xfitimer_start(struct ct_timer_instance *ti)
@@ -298,6 +298,8 @@ static void ct_xfitimer_start(struct ct_timer_instance *ti)
        spin_lock_irqsave(&atimer->lock, flags);
        if (list_empty(&ti->running_list))
                atimer->wc = ct_xfitimer_get_wc(atimer);
+       ti->running = 1;
+       ti->need_update = 0;
        list_add(&ti->running_list, &atimer->running_head);
        spin_unlock_irqrestore(&atimer->lock, flags);
        ct_xfitimer_update(atimer);
@@ -310,7 +312,7 @@ static void ct_xfitimer_stop(struct ct_timer_instance *ti)
 
        spin_lock_irqsave(&atimer->lock, flags);
        list_del_init(&ti->running_list);
-       ti->need_update = 0;
+       ti->running = 0;
        spin_unlock_irqrestore(&atimer->lock, flags);
        ct_xfitimer_update(atimer);
 }
index 337d2a59c67e5da26127d35b82cc5ce9460d6cfc..d22b26068014a775cde4efb3b16fc6f9a3dfd3c7 100644 (file)
@@ -9014,6 +9014,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
                ALC888_ACER_ASPIRE_4930G),
        SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
                ALC888_ACER_ASPIRE_8930G),
+       SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
+               ALC888_ACER_ASPIRE_8930G),
        SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
index 173bebf9f51d0316f00a158912c2dd0eeacc9f8d..8aa5687f392a10abf1310015d8ddeb57e73d070a 100644 (file)
@@ -356,8 +356,6 @@ struct ichdev {
         unsigned int position;
        unsigned int pos_shift;
        unsigned int last_pos;
-       unsigned long last_pos_jiffies;
-       unsigned int jiffy_to_bytes;
         int frags;
         int lvi;
         int lvi_frag;
@@ -844,7 +842,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                val = ICH_IOCE | ICH_STARTBM;
                ichdev->last_pos = ichdev->position;
-               ichdev->last_pos_jiffies = jiffies;
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
                ichdev->suspended = 1;
@@ -1048,7 +1045,6 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream)
                        ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
        }
        snd_intel8x0_setup_periods(chip, ichdev);
-       ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ;
        return 0;
 }
 
@@ -1073,19 +1069,23 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
                    ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
                        break;
        } while (timeout--);
+       ptr = ichdev->last_pos;
        if (ptr1 != 0) {
                ptr1 <<= ichdev->pos_shift;
                ptr = ichdev->fragsize1 - ptr1;
                ptr += position;
-               ichdev->last_pos = ptr;
-               ichdev->last_pos_jiffies = jiffies;
-       } else {
-               ptr1 = jiffies - ichdev->last_pos_jiffies;
-               if (ptr1)
-                       ptr1 -= 1;
-               ptr = ichdev->last_pos + ptr1 * ichdev->jiffy_to_bytes;
-               ptr %= ichdev->size;
+               if (ptr < ichdev->last_pos) {
+                       unsigned int pos_base, last_base;
+                       pos_base = position / ichdev->fragsize1;
+                       last_base = ichdev->last_pos / ichdev->fragsize1;
+                       /* another sanity check; ptr1 can go back to full
+                        * before the base position is updated
+                        */
+                       if (pos_base == last_base)
+                               ptr = ichdev->last_pos;
+               }
        }
+       ichdev->last_pos = ptr;
        spin_unlock(&chip->reg_lock);
        if (ptr >= ichdev->size)
                return 0;
index 1fc4c8e0899c18ec1f7f12750cf80023140cd5b7..c550750c79c0654db16d480e4abee954cc71e09f 100644 (file)
@@ -375,10 +375,6 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = socdev->card->codec;
        struct ssm2602_priv *ssm2602 = codec->private_data;
 
-       if (ssm2602->master_substream == substream)
-               ssm2602->master_substream = ssm2602->slave_substream;
-
-       ssm2602->slave_substream = NULL;
        /* deactivate */
        if (!codec->active)
                ssm2602_write(codec, SSM2602_ACTIVE, 0);
index d8a9222fbf745c53077bd3a5f12e89c3f70bded0..e8d2e3e14c45528d6dd23ba73e71bead6c8fb53b 100644 (file)
@@ -1257,22 +1257,18 @@ static struct {
        int div;
 } bclk_divs[] = {
        {  10,  0 },
-       {  15,  1 },
        {  20,  2 },
        {  30,  3 },
        {  40,  4 },
        {  50,  5 },
-       {  55,  6 },
        {  60,  7 },
        {  80,  8 },
        { 100,  9 },
-       { 110, 10 },
        { 120, 11 },
        { 160, 12 },
        { 200, 13 },
        { 220, 14 },
        { 240, 15 },
-       { 250, 16 },
        { 300, 17 },
        { 320, 18 },
        { 440, 19 },
index c89a3cdf31e4aea8ad464baf720512deb0ccd319..326955dea36cef8fb6cc3fdb05e7516e7b05e578 100644 (file)
@@ -184,7 +184,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
 
        /* set cpu DAI configuration */
        ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
-                       SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBS_CFS);
+                       SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
index 3f44150d8e30b6a9d8f5920e497627b397c0f049..1d70829464ef3698c85df7918b9c0c4acfaf1239 100644 (file)
@@ -1389,6 +1389,9 @@ int snd_soc_init_card(struct snd_soc_device *socdev)
        snprintf(codec->card->longname, sizeof(codec->card->longname),
                 "%s (%s)", card->name, codec->name);
 
+       /* Make sure all DAPM widgets are instantiated */
+       snd_soc_dapm_new_widgets(codec);
+
        ret = snd_card_register(codec->card);
        if (ret < 0) {
                printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
index 2b302bbffe7361c6faccc1eb84099f2e1c5b1baf..12522e6913d92d068676f4b3916571b03dae2d87 100644 (file)
@@ -27,6 +27,11 @@ MODULE_DESCRIPTION("Core sound module");
 MODULE_AUTHOR("Alan Cox");
 MODULE_LICENSE("GPL");
 
+static char *sound_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));
+}
+
 static int __init init_soundcore(void)
 {
        int rc;
@@ -41,6 +46,8 @@ static int __init init_soundcore(void)
                return PTR_ERR(sound_class);
        }
 
+       sound_class->nodename = sound_nodename;
+
        return 0;
 }
 
index f0f7624f91781efd574a883b78da048b5f9dbafb..f6f201eb24ceeb00145b406d6fbf18bf09d08817 100644 (file)
@@ -1989,7 +1989,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        USB_DEVICE(0x0ccd, 0x0028),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                .vendor_name = "TerraTec",
-               .product_name = "Aureon 5.1 MkII",
+               .product_name = "Aureon5.1MkII",
                .ifnum = QUIRK_NO_INTERFACE
        }
 },