Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6
Linus Torvalds [Fri, 12 Oct 2007 22:49:37 +0000 (15:49 -0700)]
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/driver-2.6: (75 commits)
  PM: merge device power-management source files
  sysfs: add copyrights
  kobject: update the copyrights
  kset: add some kerneldoc to help describe what these strange things are
  Driver core: rename ktype_edd and ktype_efivar
  Driver core: rename ktype_driver
  Driver core: rename ktype_device
  Driver core: rename ktype_class
  driver core: remove subsystem_init()
  sysfs: move sysfs file poll implementation to sysfs_open_dirent
  sysfs: implement sysfs_open_dirent
  sysfs: move sysfs_dirent->s_children into sysfs_dirent->s_dir
  sysfs: make sysfs_root a regular directory dirent
  sysfs: open code sysfs_attach_dentry()
  sysfs: make s_elem an anonymous union
  sysfs: make bin attr open get active reference of parent too
  sysfs: kill unnecessary NULL pointer check in sysfs_release()
  sysfs: kill unnecessary sysfs_get() in open paths
  sysfs: reposition sysfs_dirent->s_mode.
  sysfs: kill sysfs_update_file()
  ...

348 files changed:
Documentation/DocBook/Makefile
Documentation/DocBook/s390-drivers.tmpl [new file with mode: 0644]
Documentation/filesystems/ntfs.txt
Documentation/kernel-parameters.txt
Documentation/s390/00-INDEX [new file with mode: 0644]
Documentation/s390/CommonIO
Documentation/s390/cds.txt
Documentation/usb/authorization.txt [new file with mode: 0644]
Documentation/usb/power-management.txt [new file with mode: 0644]
Documentation/usb/usb-serial.txt
Documentation/usb/usbmon.txt
MAINTAINERS
arch/arm/mach-imx/cpufreq.c
arch/arm/mach-sa1100/cpu-sa1110.c
arch/arm/plat-omap/cpu-omap.c
arch/blackfin/mach-bf533/cpu.c
arch/blackfin/mach-bf537/boards/generic_board.c
arch/blackfin/mach-bf537/boards/pnav10.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/i386/Kconfig
arch/ia64/kernel/cpufreq/acpi-cpufreq.c
arch/powerpc/platforms/cell/cbe_cpufreq.c
arch/powerpc/platforms/pasemi/cpufreq.c
arch/powerpc/platforms/powermac/cpufreq_32.c
arch/powerpc/platforms/powermac/cpufreq_64.c
arch/s390/appldata/appldata_base.c
arch/s390/kernel/audit.c
arch/s390/kernel/audit.h [new file with mode: 0644]
arch/s390/kernel/compat_audit.c
arch/s390/kernel/cpcmd.c
arch/s390/kernel/dis.c
arch/s390/kernel/ipl.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/mm/fault.c
arch/sh/kernel/cpufreq.c
arch/sparc64/kernel/us2e_cpufreq.c
arch/x86/kernel/Makefile_32
arch/x86/kernel/Makefile_64
arch/x86/kernel/apic_64.c
arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
arch/x86/kernel/cpu/cpufreq/e_powersaver.c
arch/x86/kernel/cpu/cpufreq/elanfreq.c
arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
arch/x86/kernel/cpu/cpufreq/longhaul.c
arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
arch/x86/kernel/cpu/cpufreq/powernow-k6.c
arch/x86/kernel/cpu/cpufreq/powernow-k7.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/cpufreq/sc520_freq.c
arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
arch/x86/kernel/geode_32.c
arch/x86/kernel/hpet.c [moved from arch/x86/kernel/hpet_32.c with 81% similarity]
arch/x86/kernel/hpet_64.c [deleted file]
arch/x86/kernel/i8253.c [moved from arch/x86/kernel/i8253_32.c with 99% similarity]
arch/x86/kernel/i8259_32.c
arch/x86/kernel/i8259_64.c
arch/x86/kernel/mfgpt_32.c [new file with mode: 0644]
arch/x86/kernel/nmi_32.c
arch/x86/kernel/nmi_64.c
arch/x86/kernel/process_64.c
arch/x86/kernel/quirks.c
arch/x86/kernel/setup_64.c
arch/x86/kernel/smpboot_64.c
arch/x86/kernel/time_32.c
arch/x86/kernel/time_64.c
arch/x86/kernel/tsc_64.c
arch/x86_64/Kconfig
block/Kconfig
block/Makefile
drivers/acpi/processor_idle.c
drivers/block/Kconfig
drivers/cpufreq/Kconfig
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/cpufreq_stats.c
drivers/input/misc/pcspkr.c
drivers/isdn/hisax/avm_pci.c
drivers/isdn/hisax/bkm_a8.c
drivers/isdn/hisax/diva.c
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/sedlbauer.c
drivers/isdn/hisax/telespci.c
drivers/isdn/hisax/w6692.c
drivers/isdn/hysdn/hysdn_init.c
drivers/mmc/core/host.c
drivers/net/bnx2.c
drivers/net/tg3.c
drivers/s390/block/dasd_int.h
drivers/s390/block/xpram.c
drivers/s390/char/con3215.c
drivers/s390/char/con3270.c
drivers/s390/char/sclp.c
drivers/s390/char/tape_3590.c
drivers/s390/char/tty3270.c
drivers/s390/char/tty3270.h [new file with mode: 0644]
drivers/s390/char/vmwatchdog.c
drivers/s390/char/zcore.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chp.c
drivers/s390/cio/cio.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/qdio.c
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/zcrypt_mono.c
drivers/s390/crypto/zcrypt_pcixcc.c
drivers/s390/crypto/zcrypt_pcixcc.h
drivers/s390/scsi/zfcp_ccw.c
drivers/s390/scsi/zfcp_dbf.c
drivers/s390/scsi/zfcp_erp.c
drivers/usb/Makefile
drivers/usb/atm/cxacru.c
drivers/usb/atm/speedtch.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/class/usblp.c
drivers/usb/core/config.c
drivers/usb/core/devio.c
drivers/usb/core/driver.c
drivers/usb/core/endpoint.c
drivers/usb/core/generic.c
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/sysfs.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/atmel_usba_udc.c [new file with mode: 0644]
drivers/usb/gadget/atmel_usba_udc.h [new file with mode: 0644]
drivers/usb/gadget/config.c
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_usb2_udc.c
drivers/usb/gadget/gmidi.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/lh7a40x_udc.h
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pxa2xx_udc.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/gadget/serial.c
drivers/usb/gadget/usbstring.c
drivers/usb/gadget/zero.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-ppc-soc.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/ohci-dbg.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-mem.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci-ppc-of.c
drivers/usb/host/ohci-ppc-soc.c
drivers/usb/host/ohci-q.c
drivers/usb/host/ohci-ssb.c [new file with mode: 0644]
drivers/usb/host/ohci.h
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/u132-hcd.c
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-q.c
drivers/usb/misc/adutux.c
drivers/usb/misc/berry_charge.c
drivers/usb/misc/ftdi-elan.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/sisusbvga/sisusb.h
drivers/usb/misc/sisusbvga/sisusb_con.c
drivers/usb/misc/sisusbvga/sisusb_init.c
drivers/usb/misc/sisusbvga/sisusb_init.h
drivers/usb/misc/sisusbvga/sisusb_struct.h
drivers/usb/mon/mon_bin.c
drivers/usb/mon/mon_main.c
drivers/usb/mon/mon_text.c
drivers/usb/mon/usb_mon.h
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/ark3116.c
drivers/usb/serial/bus.c
drivers/usb/serial/ch341.c [new file with mode: 0644]
drivers/usb/serial/cp2101.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/funsoft.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/safe_serial.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/visor.c
drivers/usb/storage/initializers.c
drivers/usb/storage/initializers.h
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/usb/usb-skeleton.c
fs/dlm/dlm_internal.h
fs/dlm/lock.c
fs/dlm/lock.h
fs/dlm/lockspace.c
fs/dlm/lowcomms.c
fs/dlm/member.c
fs/dlm/midcomms.c
fs/dlm/rcom.c
fs/dlm/rcom.h
fs/dlm/recoverd.c
fs/dlm/requestqueue.c
fs/dlm/requestqueue.h
fs/gfs2/bmap.c
fs/gfs2/daemon.c
fs/gfs2/daemon.h
fs/gfs2/dir.c
fs/gfs2/eaops.c
fs/gfs2/eaops.h
fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/glops.c
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/locking/dlm/lock_dlm.h
fs/gfs2/locking/dlm/plock.c
fs/gfs2/locking/dlm/thread.c
fs/gfs2/locking/nolock/main.c
fs/gfs2/log.c
fs/gfs2/log.h
fs/gfs2/lops.c
fs/gfs2/main.c
fs/gfs2/meta_io.c
fs/gfs2/meta_io.h
fs/gfs2/mount.c
fs/gfs2/ops_address.c
fs/gfs2/ops_export.c
fs/gfs2/ops_file.c
fs/gfs2/ops_fstype.c
fs/gfs2/ops_inode.c
fs/gfs2/ops_super.c
fs/gfs2/quota.c
fs/gfs2/recovery.c
fs/gfs2/rgrp.c
fs/gfs2/super.c
fs/gfs2/sys.c
fs/gfs2/trans.c
fs/gfs2/trans.h
fs/ntfs/ChangeLog
fs/ntfs/Makefile
fs/ntfs/aops.c
fs/ntfs/attrib.c
fs/ntfs/file.c
fs/ntfs/inode.c
fs/ntfs/logfile.c
fs/ntfs/runlist.c
fs/ocfs2/alloc.c
fs/ocfs2/alloc.h
fs/ocfs2/aops.c
fs/ocfs2/aops.h
fs/ocfs2/dir.c
fs/ocfs2/dir.h
fs/ocfs2/dlmglue.c
fs/ocfs2/dlmglue.h
fs/ocfs2/export.c
fs/ocfs2/extent_map.c
fs/ocfs2/file.c
fs/ocfs2/file.h
fs/ocfs2/inode.c
fs/ocfs2/inode.h
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/namei.c
fs/ocfs2/namei.h
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_fs.h
fs/ocfs2/super.c
fs/ocfs2/sysfile.c
include/asm-s390/cache.h
include/asm-s390/ccwdev.h
include/asm-s390/ccwgroup.h
include/asm-s390/cio.h
include/asm-s390/cmb.h
include/asm-s390/page.h
include/asm-s390/pgtable.h
include/asm-s390/s390_ext.h
include/asm-s390/system.h
include/asm-s390/zcrypt.h
include/asm-x86/8253pit.h [deleted file]
include/asm-x86/8253pit_32.h [deleted file]
include/asm-x86/8253pit_64.h [deleted file]
include/asm-x86/apic_64.h
include/asm-x86/geode.h
include/asm-x86/hardirq_32.h
include/asm-x86/hpet.h
include/asm-x86/hpet_32.h [deleted file]
include/asm-x86/hpet_64.h [deleted file]
include/asm-x86/i8253.h
include/asm-x86/i8253_32.h [deleted file]
include/asm-x86/i8253_64.h [deleted file]
include/asm-x86/pda.h
include/asm-x86/proto.h
include/asm-x86/timex.h
include/asm-x86/timex_32.h [deleted file]
include/asm-x86/timex_64.h [deleted file]
include/asm-x86/tsc.h
include/asm-x86/vsyscall.h
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/clockchips.h
include/linux/cpufreq.h
include/linux/gfs2_ondisk.h
include/linux/jiffies.h
include/linux/kernel.h
include/linux/pci_ids.h
include/linux/usb.h
include/linux/usb/gadget.h [moved from include/linux/usb_gadget.h with 92% similarity]
include/linux/usb/quirks.h
include/linux/usb/serial.h
include/linux/usb_sl811.h [deleted file]
kernel/time/Kconfig
kernel/time/Makefile
kernel/time/clockevents.c
kernel/time/tick-broadcast.c
kernel/time/tick-common.c

index 08687e4..1a7f530 100644 (file)
@@ -11,7 +11,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
            procfs-guide.xml writing_usb_driver.xml \
            kernel-api.xml filesystems.xml lsm.xml usb.xml \
            gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
-           genericirq.xml
+           genericirq.xml s390-drivers.xml
 
 ###
 # The build process is as follows (targets):
diff --git a/Documentation/DocBook/s390-drivers.tmpl b/Documentation/DocBook/s390-drivers.tmpl
new file mode 100644 (file)
index 0000000..254e769
--- /dev/null
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="s390drivers">
+ <bookinfo>
+  <title>Writing s390 channel device drivers</title>
+
+  <authorgroup>
+   <author>
+    <firstname>Cornelia</firstname>
+    <surname>Huck</surname>
+    <affiliation>
+     <address>
+       <email>cornelia.huck@de.ibm.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2007</year>
+   <holder>IBM Corp.</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+     This documentation 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.
+   </para>
+
+   <para>
+     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.
+   </para>
+
+   <para>
+     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., 59 Temple Place, Suite 330, Boston,
+     MA 02111-1307 USA
+   </para>
+
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="intro">
+   <title>Introduction</title>
+  <para>
+    This document describes the interfaces available for device drivers that
+    drive s390 based channel attached devices. This includes interfaces for
+    interaction with the hardware and interfaces for interacting with the
+    common driver core. Those interfaces are provided by the s390 common I/O
+    layer.
+  </para>
+  <para>
+    The document assumes a familarity with the technical terms associated
+    with the s390 channel I/O architecture. For a description of this
+    architecture, please refer to the "z/Architecture: Principles of
+    Operation", IBM publication no. SA22-7832.
+  </para>
+  <para>
+    While most I/O devices on a s390 system are typically driven through the
+    channel I/O mechanism described here, there are various other methods
+    (like the diag interface). These are out of the scope of this document.
+  </para>
+  <para>
+    Some additional information can also be found in the kernel source
+    under Documentation/s390/driver-model.txt.
+  </para>
+  </chapter>
+  <chapter id="ccw">
+   <title>The ccw bus</title>
+  <para>
+       The ccw bus typically contains the majority of devices available to
+       a s390 system. Named after the channel command word (ccw), the basic
+       command structure used to address its devices, the ccw bus contains
+       so-called channel attached devices. They are addressed via subchannels,
+       visible on the css bus. A device driver, however, will never interact
+       with the subchannel directly, but only via the device on the ccw bus,
+       the ccw device.
+  </para>
+    <sect1 id="channelIO">
+     <title>I/O functions for channel-attached devices</title>
+    <para>
+      Some hardware structures have been translated into C structures for use
+      by the common I/O layer and device drivers. For more information on
+      the hardware structures represented here, please consult the Principles
+      of Operation.
+    </para>
+!Iinclude/asm-s390/cio.h
+    </sect1>
+    <sect1 id="ccwdev">
+     <title>ccw devices</title>
+    <para>
+      Devices that want to initiate channel I/O need to attach to the ccw bus.
+      Interaction with the driver core is done via the common I/O layer, which
+      provides the abstractions of ccw devices and ccw device drivers.
+    </para>
+    <para>
+      The functions that initiate or terminate channel I/O all act upon a
+      ccw device structure. Device drivers must not bypass those functions
+      or strange side effects may happen.
+    </para>
+!Iinclude/asm-s390/ccwdev.h
+!Edrivers/s390/cio/device.c
+!Edrivers/s390/cio/device_ops.c
+    </sect1>
+    <sect1 id="cmf">
+     <title>The channel-measurement facility</title>
+  <para>
+       The channel-measurement facility provides a means to collect
+       measurement data which is made available by the channel subsystem
+       for each channel attached device.
+  </para>
+!Iinclude/asm-s390/cmb.h
+!Edrivers/s390/cio/cmf.c
+    </sect1>
+  </chapter>
+
+  <chapter id="ccwgroup">
+   <title>The ccwgroup bus</title>
+  <para>
+       The ccwgroup bus only contains artificial devices, created by the user.
+       Many networking devices (e.g. qeth) are in fact composed of several
+       ccw devices (like read, write and data channel for qeth). The
+       ccwgroup bus provides a mechanism to create a meta-device which
+       contains those ccw devices as slave devices and can be associated
+       with the netdevice.
+  </para>
+   <sect1 id="ccwgroupdevices">
+    <title>ccw group devices</title>
+!Iinclude/asm-s390/ccwgroup.h
+!Edrivers/s390/cio/ccwgroup.c
+   </sect1>
+  </chapter>
+
+</book>
index 8ee10ec..e79ee2d 100644 (file)
@@ -407,7 +407,7 @@ raiddev /dev/md0
        device          /dev/hda5
        raid-disk       0
        device          /dev/hdb1
-       raid-disl       1
+       raid-disk       1
 
 For linear raid, just change the raid-level above to "raid-level linear", for
 mirrors, change it to "raid-level 1", and for stripe sets with parity, change
@@ -457,6 +457,8 @@ ChangeLog
 
 Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 
+2.1.29:
+       - Fix a deadlock when mounting read-write.
 2.1.28:
        - Fix a deadlock.
 2.1.27:
index bdddd3c..912c57c 100644 (file)
@@ -1009,6 +1009,10 @@ and is between 256 and 4096 characters. It is defined in the file
        meye.*=         [HW] Set MotionEye Camera parameters
                        See Documentation/video4linux/meye.txt.
 
+       mfgpt_irq=      [IA-32] Specify the IRQ to use for the
+                       Multi-Function General Purpose Timers on AMD Geode
+                       platforms.
+
        mga=            [HW,DRM]
 
        mousedev.tap_time=
@@ -1160,6 +1164,9 @@ and is between 256 and 4096 characters. It is defined in the file
 
        nomce           [X86-32] Machine Check Exception
 
+       nomfgpt         [X86-32] Disable Multi-Function General Purpose
+                       Timer usage (for AMD Geode machines).
+
        noreplace-paravirt      [X86-32,PV_OPS] Don't patch paravirt_ops
 
        noreplace-smp   [X86-32,SMP] Don't replace SMP instructions
diff --git a/Documentation/s390/00-INDEX b/Documentation/s390/00-INDEX
new file mode 100644 (file)
index 0000000..3a2b963
--- /dev/null
@@ -0,0 +1,26 @@
+00-INDEX
+       - this file.
+3270.ChangeLog
+       - ChangeLog for the UTS Global 3270-support patch (outdated).
+3270.txt
+       - how to use the IBM 3270 display system support.
+cds.txt
+       - s390 common device support (common I/O layer).
+CommonIO
+       - common I/O layer command line parameters, procfs and debugfs  entries
+config3270.sh
+       - example configuration for 3270 devices.
+DASD
+       - information on the DASD disk device driver.
+Debugging390.txt
+       - hints for debugging on s390 systems.
+driver-model.txt
+       - information on s390 devices and the driver model.
+monreader.txt
+       - information on accessing the z/VM monitor stream from Linux.
+s390dbf.txt
+       - information on using the s390 debug feature.
+TAPE
+       - information on the driver for channel-attached tapes.
+zfcpdump
+       - information on the s390 SCSI dump tool.
index 22f82f2..86320aa 100644 (file)
@@ -1,5 +1,5 @@
-S/390 common I/O-Layer - command line parameters and /proc entries
-==================================================================
+S/390 common I/O-Layer - command line parameters, procfs and debugfs entries
+============================================================================
 
 Command line parameters
 -----------------------
@@ -7,9 +7,9 @@ Command line parameters
 * cio_msg = yes | no
   
   Determines whether information on found devices and sensed device 
-  characteristics should be shown during startup, i. e. messages of the types 
-  "Detected device 0.0.4711 on subchannel 0.0.0042" and "SenseID: Device
-  0.0.4711 reports: ...".
+  characteristics should be shown during startup or when new devices are
+  found, i. e. messages of the types "Detected device 0.0.4711 on subchannel
+  0.0.0042" and "SenseID: Device 0.0.4711 reports: ...".
 
   Default is off.
 
@@ -26,8 +26,10 @@ Command line parameters
   An ignored device can be un-ignored later; see the "/proc entries"-section for
   details.
 
-  The devices must be given either as bus ids (0.0.abcd) or as hexadecimal
-  device numbers (0xabcd or abcd, for 2.4 backward compatibility).
+  The devices must be given either as bus ids (0.x.abcd) or as hexadecimal
+  device numbers (0xabcd or abcd, for 2.4 backward compatibility). If you
+  give a device number 0xabcd, it will be interpreted as 0.0.abcd.
+
   You can use the 'all' keyword to ignore all devices.
   The '!' operator will cause the I/O-layer to _not_ ignore a device.
   The command line is parsed from left to right.
@@ -81,31 +83,36 @@ Command line parameters
   will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored
   devices.
 
-  The devices can be specified either by bus id (0.0.abcd) or, for 2.4 backward
-  compatibility, by the device number in hexadecimal (0xabcd or abcd).
+  The devices can be specified either by bus id (0.x.abcd) or, for 2.4 backward
+  compatibility, by the device number in hexadecimal (0xabcd or abcd). Device
+  numbers given as 0xabcd will be interpreted as 0.0.abcd.
+
+* For some of the information present in the /proc filesystem in 2.4 (namely,
+  /proc/subchannels and /proc/chpids), see driver-model.txt.
+  Information formerly in /proc/irq_count is now in /proc/interrupts.
+
 
+debugfs entries
+---------------
 
-* /proc/s390dbf/cio_*/ (S/390 debug feature)
+* /sys/kernel/debug/s390dbf/cio_*/ (S/390 debug feature)
 
   Some views generated by the debug feature to hold various debug outputs.
 
-  - /proc/s390dbf/cio_crw/sprintf
+  - /sys/kernel/debug/s390dbf/cio_crw/sprintf
     Messages from the processing of pending channel report words (machine check
-    handling), which will also show when CONFIG_DEBUG_CRW is defined.
+    handling).
 
-  - /proc/s390dbf/cio_msg/sprintf
-    Various debug messages from the common I/O-layer; generally, messages which 
-    will also show when CONFIG_DEBUG_IO is defined.
+  - /sys/kernel/debug/s390dbf/cio_msg/sprintf
+    Various debug messages from the common I/O-layer, including messages
+    printed when cio_msg=yes.
 
-  - /proc/s390dbf/cio_trace/hex_ascii
+  - /sys/kernel/debug/s390dbf/cio_trace/hex_ascii
     Logs the calling of functions in the common I/O-layer and, if applicable, 
     which subchannel they were called for, as well as dumps of some data
     structures (like irb in an error case).
 
   The level of logging can be changed to be more or less verbose by piping to 
-  /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on
-  the S/390 debug feature (Documentation/s390/s390dbf.txt) for details.
-
-* For some of the information present in the /proc filesystem in 2.4 (namely,
-  /proc/subchannels and /proc/chpids), see driver-model.txt.
-  Information formerly in /proc/irq_count is now in /proc/interrupts.
+  /sys/kernel/debug/s390dbf/cio_*/level a number between 0 and 6; see the
+  documentation on the S/390 debug feature (Documentation/s390/s390dbf.txt)
+  for details.
index 58919d6..3081927 100644 (file)
@@ -286,10 +286,10 @@ first:
             timeout value
 -EIO:       the common I/O layer terminated the request due to an error state
 
-If the concurrent sense flag in the extended status word in the irb is set, the
-field irb->scsw.count describes the number of device specific sense bytes
-available in the extended control word irb->scsw.ecw[0]. No device sensing by
-the device driver itself is required.
+If the concurrent sense flag in the extended status word (esw) in the irb is
+set, the field erw.scnt in the esw describes the number of device specific
+sense bytes available in the extended control word irb->scsw.ecw[]. No device
+sensing by the device driver itself is required.
 
 The device interrupt handler can use the following definitions to investigate
 the primary unit check source coded in sense byte 0 :
diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt
new file mode 100644 (file)
index 0000000..2af4006
--- /dev/null
@@ -0,0 +1,92 @@
+
+Authorizing (or not) your USB devices to connect to the system
+
+(C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation
+
+This feature allows you to control if a USB device can be used (or
+not) in a system. This feature will allow you to implement a lock-down
+of USB devices, fully controlled by user space.
+
+As of now, when a USB device is connected it is configured and
+it's interfaces inmediately made available to the users. With this
+modification, only if root authorizes the device to be configured will
+then it be possible to use it.
+
+Usage:
+
+Authorize a device to connect:
+
+$ echo 1 > /sys/usb/devices/DEVICE/authorized
+
+Deauthorize a device:
+
+$ echo 0 > /sys/usb/devices/DEVICE/authorized
+
+Set new devices connected to hostX to be deauthorized by default (ie:
+lock down):
+
+$ echo 0 > /sys/bus/devices/usbX/authorized_default
+
+Remove the lock down:
+
+$ echo 1 > /sys/bus/devices/usbX/authorized_default
+
+By default, Wired USB devices are authorized by default to
+connect. Wireless USB hosts deauthorize by default all new connected
+devices (this is so because we need to do an authentication phase
+before authorizing).
+
+
+Example system lockdown (lame)
+-----------------------
+
+Imagine you want to implement a lockdown so only devices of type XYZ
+can be connected (for example, it is a kiosk machine with a visible
+USB port):
+
+boot up
+rc.local ->
+
+ for host in /sys/bus/devices/usb*
+ do
+    echo 0 > $host/authorized_default
+ done
+
+Hookup an script to udev, for new USB devices
+
+ if device_is_my_type $DEV
+ then
+   echo 1 > $device_path/authorized
+ done
+
+
+Now, device_is_my_type() is where the juice for a lockdown is. Just
+checking if the class, type and protocol match something is the worse
+security verification you can make (or the best, for someone willing
+to break it). If you need something secure, use crypto and Certificate
+Authentication or stuff like that. Something simple for an storage key
+could be:
+
+function device_is_my_type()
+{
+   echo 1 > authorized         # temporarily authorize it
+                                # FIXME: make sure none can mount it
+   mount DEVICENODE /mntpoint
+   sum=$(md5sum /mntpoint/.signature)
+   if [ $sum = $(cat /etc/lockdown/keysum) ]
+   then
+        echo "We are good, connected"
+        umount /mntpoint
+        # Other stuff so others can use it
+   else
+        echo 0 > authorized
+   fi
+}
+
+
+Of course, this is lame, you'd want to do a real certificate
+verification stuff with PKI, so you don't depend on a shared secret,
+etc, but you get the idea. Anybody with access to a device gadget kit
+can fake descriptors and device info. Don't trust that. You are
+welcome.
+
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt
new file mode 100644 (file)
index 0000000..97842de
--- /dev/null
@@ -0,0 +1,517 @@
+                       Power Management for USB
+
+                Alan Stern <stern@rowland.harvard.edu>
+
+                           October 5, 2007
+
+
+
+       What is Power Management?
+       -------------------------
+
+Power Management (PM) is the practice of saving energy by suspending
+parts of a computer system when they aren't being used.  While a
+component is "suspended" it is in a nonfunctional low-power state; it
+might even be turned off completely.  A suspended component can be
+"resumed" (returned to a functional full-power state) when the kernel
+needs to use it.  (There also are forms of PM in which components are
+placed in a less functional but still usable state instead of being
+suspended; an example would be reducing the CPU's clock rate.  This
+document will not discuss those other forms.)
+
+When the parts being suspended include the CPU and most of the rest of
+the system, we speak of it as a "system suspend".  When a particular
+device is turned off while the system as a whole remains running, we
+call it a "dynamic suspend" (also known as a "runtime suspend" or
+"selective suspend").  This document concentrates mostly on how
+dynamic PM is implemented in the USB subsystem, although system PM is
+covered to some extent (see Documentation/power/*.txt for more
+information about system PM).
+
+Note: Dynamic PM support for USB is present only if the kernel was
+built with CONFIG_USB_SUSPEND enabled.  System PM support is present
+only if the kernel was built with CONFIG_SUSPEND or CONFIG_HIBERNATION
+enabled.
+
+
+       What is Remote Wakeup?
+       ----------------------
+
+When a device has been suspended, it generally doesn't resume until
+the computer tells it to.  Likewise, if the entire computer has been
+suspended, it generally doesn't resume until the user tells it to, say
+by pressing a power button or opening the cover.
+
+However some devices have the capability of resuming by themselves, or
+asking the kernel to resume them, or even telling the entire computer
+to resume.  This capability goes by several names such as "Wake On
+LAN"; we will refer to it generically as "remote wakeup".  When a
+device is enabled for remote wakeup and it is suspended, it may resume
+itself (or send a request to be resumed) in response to some external
+event.  Examples include a suspended keyboard resuming when a key is
+pressed, or a suspended USB hub resuming when a device is plugged in.
+
+
+       When is a USB device idle?
+       --------------------------
+
+A device is idle whenever the kernel thinks it's not busy doing
+anything important and thus is a candidate for being suspended.  The
+exact definition depends on the device's driver; drivers are allowed
+to declare that a device isn't idle even when there's no actual
+communication taking place.  (For example, a hub isn't considered idle
+unless all the devices plugged into that hub are already suspended.)
+In addition, a device isn't considered idle so long as a program keeps
+its usbfs file open, whether or not any I/O is going on.
+
+If a USB device has no driver, its usbfs file isn't open, and it isn't
+being accessed through sysfs, then it definitely is idle.
+
+
+       Forms of dynamic PM
+       -------------------
+
+Dynamic suspends can occur in two ways: manual and automatic.
+"Manual" means that the user has told the kernel to suspend a device,
+whereas "automatic" means that the kernel has decided all by itself to
+suspend a device.  Automatic suspend is called "autosuspend" for
+short.  In general, a device won't be autosuspended unless it has been
+idle for some minimum period of time, the so-called idle-delay time.
+
+Of course, nothing the kernel does on its own initiative should
+prevent the computer or its devices from working properly.  If a
+device has been autosuspended and a program tries to use it, the
+kernel will automatically resume the device (autoresume).  For the
+same reason, an autosuspended device will usually have remote wakeup
+enabled, if the device supports remote wakeup.
+
+It is worth mentioning that many USB drivers don't support
+autosuspend.  In fact, at the time of this writing (Linux 2.6.23) the
+only drivers which do support it are the hub driver, kaweth, asix,
+usblp, usblcd, and usb-skeleton (which doesn't count).  If a
+non-supporting driver is bound to a device, the device won't be
+autosuspended.  In effect, the kernel pretends the device is never
+idle.
+
+We can categorize power management events in two broad classes:
+external and internal.  External events are those triggered by some
+agent outside the USB stack: system suspend/resume (triggered by
+userspace), manual dynamic suspend/resume (also triggered by
+userspace), and remote wakeup (triggered by the device).  Internal
+events are those triggered within the USB stack: autosuspend and
+autoresume.
+
+
+       The user interface for dynamic PM
+       ---------------------------------
+
+The user interface for controlling dynamic PM is located in the power/
+subdirectory of each USB device's sysfs directory, that is, in
+/sys/bus/usb/devices/.../power/ where "..." is the device's ID.  The
+relevant attribute files are: wakeup, level, and autosuspend.
+
+       power/wakeup
+
+               This file is empty if the device does not support
+               remote wakeup.  Otherwise the file contains either the
+               word "enabled" or the word "disabled", and you can
+               write those words to the file.  The setting determines
+               whether or not remote wakeup will be enabled when the
+               device is next suspended.  (If the setting is changed
+               while the device is suspended, the change won't take
+               effect until the following suspend.)
+
+       power/level
+
+               This file contains one of three words: "on", "auto",
+               or "suspend".  You can write those words to the file
+               to change the device's setting.
+
+               "on" means that the device should be resumed and
+               autosuspend is not allowed.  (Of course, system
+               suspends are still allowed.)
+
+               "auto" is the normal state in which the kernel is
+               allowed to autosuspend and autoresume the device.
+
+               "suspend" means that the device should remain
+               suspended, and autoresume is not allowed.  (But remote
+               wakeup may still be allowed, since it is controlled
+               separately by the power/wakeup attribute.)
+
+       power/autosuspend
+
+               This file contains an integer value, which is the
+               number of seconds the device should remain idle before
+               the kernel will autosuspend it (the idle-delay time).
+               The default is 2.  0 means to autosuspend as soon as
+               the device becomes idle, and -1 means never to
+               autosuspend.  You can write a number to the file to
+               change the autosuspend idle-delay time.
+
+Writing "-1" to power/autosuspend and writing "on" to power/level do
+essentially the same thing -- they both prevent the device from being
+autosuspended.  Yes, this is a redundancy in the API.
+
+(In 2.6.21 writing "0" to power/autosuspend would prevent the device
+from being autosuspended; the behavior was changed in 2.6.22.  The
+power/autosuspend attribute did not exist prior to 2.6.21, and the
+power/level attribute did not exist prior to 2.6.22.)
+
+
+       Changing the default idle-delay time
+       ------------------------------------
+
+The default autosuspend idle-delay time is controlled by a module
+parameter in usbcore.  You can specify the value when usbcore is
+loaded.  For example, to set it to 5 seconds instead of 2 you would
+do:
+
+       modprobe usbcore autosuspend=5
+
+Equivalently, you could add to /etc/modprobe.conf a line saying:
+
+       options usbcore autosuspend=5
+
+Some distributions load the usbcore module very early during the boot
+process, by means of a program or script running from an initramfs
+image.  To alter the parameter value you would have to rebuild that
+image.
+
+If usbcore is compiled into the kernel rather than built as a loadable
+module, you can add
+
+       usbcore.autosuspend=5
+
+to the kernel's boot command line.
+
+Finally, the parameter value can be changed while the system is
+running.  If you do:
+
+       echo 5 >/sys/module/usbcore/parameters/autosuspend
+
+then each new USB device will have its autosuspend idle-delay
+initialized to 5.  (The idle-delay values for already existing devices
+will not be affected.)
+
+Setting the initial default idle-delay to -1 will prevent any
+autosuspend of any USB device.  This is a simple alternative to
+disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the
+added benefit of allowing you to enable autosuspend for selected
+devices.
+
+
+       Warnings
+       --------
+
+The USB specification states that all USB devices must support power
+management.  Nevertheless, the sad fact is that many devices do not
+support it very well.  You can suspend them all right, but when you
+try to resume them they disconnect themselves from the USB bus or
+they stop working entirely.  This seems to be especially prevalent
+among printers and scanners, but plenty of other types of device have
+the same deficiency.
+
+For this reason, by default the kernel disables autosuspend (the
+power/level attribute is initialized to "on") for all devices other
+than hubs.  Hubs, at least, appear to be reasonably well-behaved in
+this regard.
+
+(In 2.6.21 and 2.6.22 this wasn't the case.  Autosuspend was enabled
+by default for almost all USB devices.  A number of people experienced
+problems as a result.)
+
+This means that non-hub devices won't be autosuspended unless the user
+or a program explicitly enables it.  As of this writing there aren't
+any widespread programs which will do this; we hope that in the near
+future device managers such as HAL will take on this added
+responsibility.  In the meantime you can always carry out the
+necessary operations by hand or add them to a udev script.  You can
+also change the idle-delay time; 2 seconds is not the best choice for
+every device.
+
+Sometimes it turns out that even when a device does work okay with
+autosuspend there are still problems.  For example, there are
+experimental patches adding autosuspend support to the usbhid driver,
+which manages keyboards and mice, among other things.  Tests with a
+number of keyboards showed that typing on a suspended keyboard, while
+causing the keyboard to do a remote wakeup all right, would
+nonetheless frequently result in lost keystrokes.  Tests with mice
+showed that some of them would issue a remote-wakeup request in
+response to button presses but not to motion, and some in response to
+neither.
+
+The kernel will not prevent you from enabling autosuspend on devices
+that can't handle it.  It is even possible in theory to damage a
+device by suspending it at the wrong time -- for example, suspending a
+USB hard disk might cause it to spin down without parking the heads.
+(Highly unlikely, but possible.)  Take care.
+
+
+       The driver interface for Power Management
+       -----------------------------------------
+
+The requirements for a USB driver to support external power management
+are pretty modest; the driver need only define
+
+       .suspend
+       .resume
+       .reset_resume
+
+methods in its usb_driver structure, and the reset_resume method is
+optional.  The methods' jobs are quite simple:
+
+       The suspend method is called to warn the driver that the
+       device is going to be suspended.  If the driver returns a
+       negative error code, the suspend will be aborted.  Normally
+       the driver will return 0, in which case it must cancel all
+       outstanding URBs (usb_kill_urb()) and not submit any more.
+
+       The resume method is called to tell the driver that the
+       device has been resumed and the driver can return to normal
+       operation.  URBs may once more be submitted.
+
+       The reset_resume method is called to tell the driver that
+       the device has been resumed and it also has been reset.
+       The driver should redo any necessary device initialization,
+       since the device has probably lost most or all of its state
+       (although the interfaces will be in the same altsettings as
+       before the suspend).
+
+The reset_resume method is used by the USB Persist facility (see
+Documentation/usb/persist.txt) and it can also be used under certain
+circumstances when CONFIG_USB_PERSIST is not enabled.  Currently, if a
+device is reset during a resume and the driver does not have a
+reset_resume method, the driver won't receive any notification about
+the resume.  Later kernels will call the driver's disconnect method;
+2.6.23 doesn't do this.
+
+USB drivers are bound to interfaces, so their suspend and resume
+methods get called when the interfaces are suspended or resumed.  In
+principle one might want to suspend some interfaces on a device (i.e.,
+force the drivers for those interface to stop all activity) without
+suspending the other interfaces.  The USB core doesn't allow this; all
+interfaces are suspended when the device itself is suspended and all
+interfaces are resumed when the device is resumed.  It isn't possible
+to suspend or resume some but not all of a device's interfaces.  The
+closest you can come is to unbind the interfaces' drivers.
+
+
+       The driver interface for autosuspend and autoresume
+       ---------------------------------------------------
+
+To support autosuspend and autoresume, a driver should implement all
+three of the methods listed above.  In addition, a driver indicates
+that it supports autosuspend by setting the .supports_autosuspend flag
+in its usb_driver structure.  It is then responsible for informing the
+USB core whenever one of its interfaces becomes busy or idle.  The
+driver does so by calling these three functions:
+
+       int  usb_autopm_get_interface(struct usb_interface *intf);
+       void usb_autopm_put_interface(struct usb_interface *intf);
+       int  usb_autopm_set_interface(struct usb_interface *intf);
+
+The functions work by maintaining a counter in the usb_interface
+structure.  When intf->pm_usage_count is > 0 then the interface is
+deemed to be busy, and the kernel will not autosuspend the interface's
+device.  When intf->pm_usage_count is <= 0 then the interface is
+considered to be idle, and the kernel may autosuspend the device.
+
+(There is a similar pm_usage_count field in struct usb_device,
+associated with the device itself rather than any of its interfaces.
+This field is used only by the USB core.)
+
+The driver owns intf->pm_usage_count; it can modify the value however
+and whenever it likes.  A nice aspect of the usb_autopm_* routines is
+that the changes they make are protected by the usb_device structure's
+PM mutex (udev->pm_mutex); however drivers may change pm_usage_count
+without holding the mutex.
+
+       usb_autopm_get_interface() increments pm_usage_count and
+       attempts an autoresume if the new value is > 0 and the
+       device is suspended.
+
+       usb_autopm_put_interface() decrements pm_usage_count and
+       attempts an autosuspend if the new value is <= 0 and the
+       device isn't suspended.
+
+       usb_autopm_set_interface() leaves pm_usage_count alone.
+       It attempts an autoresume if the value is > 0 and the device
+       is suspended, and it attempts an autosuspend if the value is
+       <= 0 and the device isn't suspended.
+
+There also are a couple of utility routines drivers can use:
+
+       usb_autopm_enable() sets pm_usage_cnt to 1 and then calls
+       usb_autopm_set_interface(), which will attempt an autoresume.
+
+       usb_autopm_disable() sets pm_usage_cnt to 0 and then calls
+       usb_autopm_set_interface(), which will attempt an autosuspend.
+
+The conventional usage pattern is that a driver calls
+usb_autopm_get_interface() in its open routine and
+usb_autopm_put_interface() in its close or release routine.  But
+other patterns are possible.
+
+The autosuspend attempts mentioned above will often fail for one
+reason or another.  For example, the power/level attribute might be
+set to "on", or another interface in the same device might not be
+idle.  This is perfectly normal.  If the reason for failure was that
+the device hasn't been idle for long enough, a delayed workqueue
+routine is automatically set up to carry out the operation when the
+autosuspend idle-delay has expired.
+
+Autoresume attempts also can fail.  This will happen if power/level is
+set to "suspend" or if the device doesn't manage to resume properly.
+Unlike autosuspend, there's no delay for an autoresume.
+
+
+       Other parts of the driver interface
+       -----------------------------------
+
+Sometimes a driver needs to make sure that remote wakeup is enabled
+during autosuspend.  For example, there's not much point
+autosuspending a keyboard if the user can't cause the keyboard to do a
+remote wakeup by typing on it.  If the driver sets
+intf->needs_remote_wakeup to 1, the kernel won't autosuspend the
+device if remote wakeup isn't available or has been disabled through
+the power/wakeup attribute.  (If the device is already autosuspended,
+though, setting this flag won't cause the kernel to autoresume it.
+Normally a driver would set this flag in its probe method, at which
+time the device is guaranteed not to be autosuspended.)
+
+The usb_autopm_* routines have to run in a sleepable process context;
+they must not be called from an interrupt handler or while holding a
+spinlock.  In fact, the entire autosuspend mechanism is not well geared
+toward interrupt-driven operation.  However there is one thing a
+driver can do in an interrupt handler:
+
+       usb_mark_last_busy(struct usb_device *udev);
+
+This sets udev->last_busy to the current time.  udev->last_busy is the
+field used for idle-delay calculations; updating it will cause any
+pending autosuspend to be moved back.  The usb_autopm_* routines will
+also set the last_busy field to the current time.
+
+Calling urb_mark_last_busy() from within an URB completion handler is
+subject to races: The kernel may have just finished deciding the
+device has been idle for long enough but not yet gotten around to
+calling the driver's suspend method.  The driver would have to be
+responsible for synchronizing its suspend method with its URB
+completion handler and causing the autosuspend to fail with -EBUSY if
+an URB had completed too recently.
+
+External suspend calls should never be allowed to fail in this way,
+only autosuspend calls.  The driver can tell them apart by checking
+udev->auto_pm; this flag will be set to 1 for internal PM events
+(autosuspend or autoresume) and 0 for external PM events.
+
+Many of the ingredients in the autosuspend framework are oriented
+towards interfaces: The usb_interface structure contains the
+pm_usage_cnt field, and the usb_autopm_* routines take an interface
+pointer as their argument.  But somewhat confusingly, a few of the
+pieces (usb_mark_last_busy() and udev->auto_pm) use the usb_device
+structure instead.  Drivers need to keep this straight; they can call
+interface_to_usbdev() to find the device structure for a given
+interface.
+
+
+       Locking requirements
+       --------------------
+
+All three suspend/resume methods are always called while holding the
+usb_device's PM mutex.  For external events -- but not necessarily for
+autosuspend or autoresume -- the device semaphore (udev->dev.sem) will
+also be held.  This implies that external suspend/resume events are
+mutually exclusive with calls to probe, disconnect, pre_reset, and
+post_reset; the USB core guarantees that this is true of internal
+suspend/resume events as well.
+
+If a driver wants to block all suspend/resume calls during some
+critical section, it can simply acquire udev->pm_mutex.
+Alternatively, if the critical section might call some of the
+usb_autopm_* routines, the driver can avoid deadlock by doing:
+
+       down(&udev->dev.sem);
+       rc = usb_autopm_get_interface(intf);
+
+and at the end of the critical section:
+
+       if (!rc)
+               usb_autopm_put_interface(intf);
+       up(&udev->dev.sem);
+
+Holding the device semaphore will block all external PM calls, and the
+usb_autopm_get_interface() will prevent any internal PM calls, even if
+it fails.  (Exercise: Why?)
+
+The rules for locking order are:
+
+       Never acquire any device semaphore while holding any PM mutex.
+
+       Never acquire udev->pm_mutex while holding the PM mutex for
+       a device that isn't a descendant of udev.
+
+In other words, PM mutexes should only be acquired going up the device
+tree, and they should be acquired only after locking all the device
+semaphores you need to hold.  These rules don't matter to drivers very
+much; they usually affect just the USB core.
+
+Still, drivers do need to be careful.  For example, many drivers use a
+private mutex to synchronize their normal I/O activities with their
+disconnect method.  Now if the driver supports autosuspend then it
+must call usb_autopm_put_interface() from somewhere -- maybe from its
+close method.  It should make the call while holding the private mutex,
+since a driver shouldn't call any of the usb_autopm_* functions for an
+interface from which it has been unbound.
+
+But the usb_autpm_* routines always acquire the device's PM mutex, and
+consequently the locking order has to be: private mutex first, PM
+mutex second.  Since the suspend method is always called with the PM
+mutex held, it mustn't try to acquire the private mutex.  It has to
+synchronize with the driver's I/O activities in some other way.
+
+
+       Interaction between dynamic PM and system PM
+       --------------------------------------------
+
+Dynamic power management and system power management can interact in
+a couple of ways.
+
+Firstly, a device may already be manually suspended or autosuspended
+when a system suspend occurs.  Since system suspends are supposed to
+be as transparent as possible, the device should remain suspended
+following the system resume.  The 2.6.23 kernel obeys this principle
+for manually suspended devices but not for autosuspended devices; they
+do get resumed when the system wakes up.  (Presumably they will be
+autosuspended again after their idle-delay time expires.)  In later
+kernels this behavior will be fixed.
+
+(There is an exception.  If a device would undergo a reset-resume
+instead of a normal resume, and the device is enabled for remote
+wakeup, then the reset-resume takes place even if the device was
+already suspended when the system suspend began.  The justification is
+that a reset-resume is a kind of remote-wakeup event.  Or to put it
+another way, a device which needs a reset won't be able to generate
+normal remote-wakeup signals, so it ought to be resumed immediately.)
+
+Secondly, a dynamic power-management event may occur as a system
+suspend is underway.  The window for this is short, since system
+suspends don't take long (a few seconds usually), but it can happen.
+For example, a suspended device may send a remote-wakeup signal while
+the system is suspending.  The remote wakeup may succeed, which would
+cause the system suspend to abort.  If the remote wakeup doesn't
+succeed, it may still remain active and thus cause the system to
+resume as soon as the system suspend is complete.  Or the remote
+wakeup may fail and get lost.  Which outcome occurs depends on timing
+and on the hardware and firmware design.
+
+More interestingly, a device might undergo a manual resume or
+autoresume during system suspend.  With current kernels this shouldn't
+happen, because manual resumes must be initiated by userspace and
+autoresumes happen in response to I/O requests, but all user processes
+and I/O should be quiescent during a system suspend -- thanks to the
+freezer.  However there are plans to do away with the freezer, which
+would mean these things would become possible.  If and when this comes
+about, the USB core will carefully arrange matters so that either type
+of resume will block until the entire system has resumed.
index 5b635ae..4e0b62b 100644 (file)
@@ -428,6 +428,17 @@ Options supported:
   See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
   information on this driver.
 
+Winchiphead CH341 Driver
+
+  This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
+  also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
+  supported by the driver. The protocol was analyzed from the behaviour
+  of the Windows driver, no datasheet is available at present.
+  The manufacturer's website: http://www.winchiphead.com/.
+  For any questions or problems with this driver, please contact
+  frank@kingswood-consulting.co.uk.
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with
index 53ae866..2917ce4 100644 (file)
@@ -34,9 +34,12 @@ if usbmon is built into the kernel.
 Verify that bus sockets are present.
 
 # ls /sys/kernel/debug/usbmon
-1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
+0s  0t  0u  1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
 #
 
+Now you can choose to either use the sockets numbered '0' (to capture packets on
+all buses), and skip to step #3, or find the bus used by your device with step #2.
+
 2. Find which bus connects to the desired device
 
 Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
@@ -56,6 +59,10 @@ Bus=03 means it's bus 3.
 
 # cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out
 
+to listen on a single bus, otherwise, to listen on all buses, type:
+
+# cat /sys/kernel/debug/usbmon/0u > /tmp/1.mon.out
+
 This process will be reading until killed. Naturally, the output can be
 redirected to a desirable location. This is preferred, because it is going
 to be quite long.
index c4eca56..60e649f 100644 (file)
@@ -677,6 +677,13 @@ P: Haavard Skinnemoen
 M:     hskinnemoen@atmel.com
 S:     Supported
 
+ATMEL USBA UDC DRIVER
+P:     Haavard Skinnemoen
+M:     hskinnemoen@atmel.com
+L:     kernel@avr32linux.org
+W:     http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
+S:     Supported
+
 ATMEL WIRELESS DRIVER
 P:     Simon Kelley
 M:     simon@thekelleys.org.uk
index 467d899..e548ba7 100644 (file)
@@ -269,7 +269,6 @@ static int __init imx_cpufreq_driver_init(struct cpufreq_policy *policy)
                return -EINVAL;
 
        policy->cur = policy->min = policy->max = imx_get_speed(0);
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.min_freq = 8000;
        policy->cpuinfo.max_freq = 200000;
         /* Manual states, that PLL stabilizes in two CLK32 periods */
index 78f4c13..36b47ff 100644 (file)
@@ -331,7 +331,6 @@ static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -EINVAL;
        policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.min_freq = 59000;
        policy->cpuinfo.max_freq = 287000;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
index a0c71dc..c0d63b0 100644 (file)
@@ -108,7 +108,6 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -EINVAL;
        policy->cur = policy->min = policy->max = omap_getspeed(0);
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
        policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
index 6fd9cfd..b7a0e0f 100644 (file)
@@ -118,8 +118,6 @@ static int __init __bf533_cpu_init(struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -EINVAL;
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        /*Now ,only support one cpu */
        policy->cur = bf533_getfreq(0);
index 5e9d09e..6668c8e 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
index 20507e9..f83a254 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 
 #include <linux/spi/ad7877.h>
 
index 47d7d4a..f42ba3a 100644 (file)
@@ -40,7 +40,7 @@
 #include <linux/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
index 2d85e4b..6bbbc27 100644 (file)
@@ -1206,6 +1206,16 @@ config SCx200HR_TIMER
          processor goes idle (as is done by the scheduler).  The
          other workaround is idle=poll boot option.
 
+config GEODE_MFGPT_TIMER
+       bool "Geode Multi-Function General Purpose Timer (MFGPT) events"
+       depends on MGEODE_LX && GENERIC_TIME && GENERIC_CLOCKEVENTS
+       default y
+       help
+         This driver provides a clock event source based on the MFGPT
+         timer(s) in the CS5535 and CS5536 companion chip for the geode.
+         MFGPTs have a better resolution and max interval than the
+         generic PIT, and are suitable for use as high-res timers.
+
 config K8_NB
        def_bool y
        depends on AGP_AMD64
index 8c6ec70..b8498ea 100644 (file)
@@ -321,8 +321,6 @@ acpi_cpufreq_cpu_init (
                            data->acpi_data.states[i].transition_latency * 1000;
                }
        }
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        policy->cur = processor_get_freq(data, policy->cpu);
 
        /* table init */
index 901236f..5123e9d 100644 (file)
@@ -107,8 +107,6 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
                pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
        }
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        /* if DEBUG is enabled set_pmode() measures the latency
         * of a transition */
        policy->cpuinfo.transition_latency = 25000;
index 3ae0838..1cfb8b0 100644 (file)
@@ -195,8 +195,6 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
                pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
        }
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        policy->cpuinfo.transition_latency = get_gizmo_latency();
 
        cur_astate = get_cur_astate(policy->cpu);
index 1fe35da..c04abcc 100644 (file)
@@ -410,7 +410,6 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
        if (policy->cpu != 0)
                return -ENODEV;
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency      = CPUFREQ_ETERNAL;
        policy->cur = cur_freq;
 
index 00f5029..4dfb4bc 100644 (file)
@@ -357,7 +357,6 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
 
 static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
        /* secondary CPUs are tied to the primary one by the
index 62391fb..ac61cf4 100644 (file)
@@ -547,8 +547,7 @@ static void __cpuinit appldata_online_cpu(int cpu)
        spin_unlock(&appldata_timer_lock);
 }
 
-static void
-appldata_offline_cpu(int cpu)
+static void __cpuinit appldata_offline_cpu(int cpu)
 {
        del_virt_timer(&per_cpu(appldata_timer, cpu));
        if (atomic_dec_and_test(&appldata_expire_count)) {
@@ -560,9 +559,9 @@ appldata_offline_cpu(int cpu)
        spin_unlock(&appldata_timer_lock);
 }
 
-static int __cpuinit
-appldata_cpu_notify(struct notifier_block *self,
-                   unsigned long action, void *hcpu)
+static int __cpuinit appldata_cpu_notify(struct notifier_block *self,
+                                        unsigned long action,
+                                        void *hcpu)
 {
        switch (action) {
        case CPU_ONLINE:
@@ -608,63 +607,15 @@ static int __init appldata_init(void)
        register_hotcpu_notifier(&appldata_nb);
 
        appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
-#ifdef MODULE
-       appldata_dir_table[0].de->owner = THIS_MODULE;
-       appldata_table[0].de->owner = THIS_MODULE;
-       appldata_table[1].de->owner = THIS_MODULE;
-#endif
 
        P_DEBUG("Base interface initialized.\n");
        return 0;
 }
 
-/*
- * appldata_exit()
- *
- * stop timer, unregister /proc entries
- */
-static void __exit appldata_exit(void)
-{
-       struct list_head *lh;
-       struct appldata_ops *ops;
-       int rc, i;
+__initcall(appldata_init);
 
-       P_DEBUG("Unloading module ...\n");
-       /*
-        * ops list should be empty, but just in case something went wrong...
-        */
-       spin_lock(&appldata_ops_lock);
-       list_for_each(lh, &appldata_ops_list) {
-               ops = list_entry(lh, struct appldata_ops, list);
-               rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
-                               (unsigned long) ops->data, ops->size,
-                               ops->mod_lvl);
-               if (rc != 0) {
-                       P_ERROR("STOP DIAG 0xDC for %s failed, "
-                               "return code: %d\n", ops->name, rc);
-               }
-       }
-       spin_unlock(&appldata_ops_lock);
-
-       for_each_online_cpu(i)
-               appldata_offline_cpu(i);
-
-       appldata_timer_active = 0;
-
-       unregister_sysctl_table(appldata_sysctl_header);
-
-       destroy_workqueue(appldata_wq);
-       P_DEBUG("... module unloaded!\n");
-}
 /**************************** init / exit <END> ******************************/
 
-
-module_init(appldata_init);
-module_exit(appldata_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Gerald Schaefer");
-MODULE_DESCRIPTION("Linux-VM Monitor Stream, base infrastructure");
-
 EXPORT_SYMBOL_GPL(appldata_register_ops);
 EXPORT_SYMBOL_GPL(appldata_unregister_ops);
 EXPORT_SYMBOL_GPL(appldata_diag);
index d1c76fe..f4932c2 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/types.h>
 #include <linux/audit.h>
 #include <asm/unistd.h>
+#include "audit.h"
 
 static unsigned dir_class[] = {
 #include <asm-generic/audit_dir_write.h>
@@ -40,7 +41,6 @@ int audit_classify_arch(int arch)
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_COMPAT
-       extern int s390_classify_syscall(unsigned);
        if (abi == AUDIT_ARCH_S390)
                return s390_classify_syscall(syscall);
 #endif
@@ -61,11 +61,6 @@ int audit_classify_syscall(int abi, unsigned syscall)
 static int __init audit_classes_init(void)
 {
 #ifdef CONFIG_COMPAT
-       extern __u32 s390_dir_class[];
-       extern __u32 s390_write_class[];
-       extern __u32 s390_read_class[];
-       extern __u32 s390_chattr_class[];
-       extern __u32 s390_signal_class[];
        audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class);
        audit_register_class(AUDIT_CLASS_READ_32, s390_read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class);
diff --git a/arch/s390/kernel/audit.h b/arch/s390/kernel/audit.h
new file mode 100644 (file)
index 0000000..12b56f4
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __ARCH_S390_KERNEL_AUDIT_H
+#define __ARCH_S390_KERNEL_AUDIT_H
+
+#include <linux/types.h>
+
+#ifdef CONFIG_COMPAT
+extern int s390_classify_syscall(unsigned);
+extern __u32 s390_dir_class[];
+extern __u32 s390_write_class[];
+extern __u32 s390_read_class[];
+extern __u32 s390_chattr_class[];
+extern __u32 s390_signal_class[];
+#endif /* CONFIG_COMPAT */
+
+#endif /* __ARCH_S390_KERNEL_AUDIT_H */
index 0569f51..d6487bf 100644 (file)
@@ -1,5 +1,6 @@
 #undef __s390x__
 #include <asm/unistd.h>
+#include "audit.h"
 
 unsigned s390_dir_class[] = {
 #include <asm-generic/audit_dir_write.h>
index 6c89f30..d8c1131 100644 (file)
@@ -2,7 +2,7 @@
  *  arch/s390/kernel/cpcmd.c
  *
  *  S390 version
- *    Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 1999,2007
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  *               Christian Borntraeger (cborntra@de.ibm.com),
  */
 static DEFINE_SPINLOCK(cpcmd_lock);
 static char cpcmd_buf[241];
 
+static int diag8_noresponse(int cmdlen)
+{
+       register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+       register unsigned long reg3 asm ("3") = cmdlen;
+
+       asm volatile(
+#ifndef CONFIG_64BIT
+               "       diag    %1,%0,0x8\n"
+#else /* CONFIG_64BIT */
+               "       sam31\n"
+               "       diag    %1,%0,0x8\n"
+               "       sam64\n"
+#endif /* CONFIG_64BIT */
+               : "+d" (reg3) : "d" (reg2) : "cc");
+       return reg3;
+}
+
+static int diag8_response(int cmdlen, char *response, int *rlen)
+{
+       register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+       register unsigned long reg3 asm ("3") = (addr_t) response;
+       register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
+       register unsigned long reg5 asm ("5") = *rlen;
+
+       asm volatile(
+#ifndef CONFIG_64BIT
+               "       diag    %2,%0,0x8\n"
+               "       brc     8,1f\n"
+               "       ar      %1,%4\n"
+#else /* CONFIG_64BIT */
+               "       sam31\n"
+               "       diag    %2,%0,0x8\n"
+               "       sam64\n"
+               "       brc     8,1f\n"
+               "       agr     %1,%4\n"
+#endif /* CONFIG_64BIT */
+               "1:\n"
+               : "+d" (reg4), "+d" (reg5)
+               : "d" (reg2), "d" (reg3), "d" (*rlen) : "cc");
+       *rlen = reg5;
+       return reg4;
+}
+
 /*
  * __cpcmd has some restrictions over cpcmd
  *  - the response buffer must reside below 2GB (if any)
@@ -28,59 +71,27 @@ static char cpcmd_buf[241];
  */
 int  __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
 {
-       unsigned cmdlen;
-       int return_code, return_len;
+       int cmdlen;
+       int rc;
+       int response_len;
 
        cmdlen = strlen(cmd);
        BUG_ON(cmdlen > 240);
        memcpy(cpcmd_buf, cmd, cmdlen);
        ASCEBC(cpcmd_buf, cmdlen);
 
-       if (response != NULL && rlen > 0) {
-               register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
-               register unsigned long reg3 asm ("3") = (addr_t) response;
-               register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
-               register unsigned long reg5 asm ("5") = rlen;
-
+       if (response) {
                memset(response, 0, rlen);
-               asm volatile(
-#ifndef CONFIG_64BIT
-                       "       diag    %2,%0,0x8\n"
-                       "       brc     8,1f\n"
-                       "       ar      %1,%4\n"
-#else /* CONFIG_64BIT */
-                       "       sam31\n"
-                       "       diag    %2,%0,0x8\n"
-                       "       sam64\n"
-                       "       brc     8,1f\n"
-                       "       agr     %1,%4\n"
-#endif /* CONFIG_64BIT */
-                       "1:\n"
-                       : "+d" (reg4), "+d" (reg5)
-                       : "d" (reg2), "d" (reg3), "d" (rlen) : "cc");
-               return_code = (int) reg4;
-               return_len = (int) reg5;
-                EBCASC(response, rlen);
+               response_len = rlen;
+               rc = diag8_response(cmdlen, response, &rlen);
+               EBCASC(response, response_len);
         } else {
-               register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
-               register unsigned long reg3 asm ("3") = cmdlen;
-               return_len = 0;
-               asm volatile(
-#ifndef CONFIG_64BIT
-                       "       diag    %1,%0,0x8\n"
-#else /* CONFIG_64BIT */
-                       "       sam31\n"
-                       "       diag    %1,%0,0x8\n"
-                       "       sam64\n"
-#endif /* CONFIG_64BIT */
-                       : "+d" (reg3) : "d" (reg2) : "cc");
-               return_code = (int) reg3;
+               rc = diag8_noresponse(cmdlen);
         }
-       if (response_code != NULL)
-               *response_code = return_code;
-       return return_len;
+       if (response_code)
+               *response_code = rc;
+       return rlen;
 }
-
 EXPORT_SYMBOL(__cpcmd);
 
 int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
@@ -109,5 +120,4 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
        }
        return len;
 }
-
 EXPORT_SYMBOL(cpcmd);
index 50d2235..c14a336 100644 (file)
@@ -1162,6 +1162,7 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
        unsigned int value;
        char separator;
        char *ptr;
+       int i;
 
        ptr = buffer;
        insn = find_insn(code);
@@ -1169,7 +1170,8 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
                ptr += sprintf(ptr, "%.5s\t", insn->name);
                /* Extract the operands. */
                separator = 0;
-               for (ops = formats[insn->format] + 1; *ops != 0; ops++) {
+               for (ops = formats[insn->format] + 1, i = 0;
+                    *ops != 0 && i < 6; ops++, i++) {
                        operand = operands + *ops;
                        value = extract_operand(code, operand);
                        if ((operand->flags & OPERAND_INDEX)  && value == 0)
@@ -1241,7 +1243,6 @@ void show_code(struct pt_regs *regs)
        }
        /* Find a starting point for the disassembly. */
        while (start < 32) {
-               hops = 0;
                for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) {
                        if (!find_insn(code + start + i))
                                break;
index 8b8f136..66b5190 100644 (file)
@@ -735,10 +735,10 @@ void do_reipl(void)
        case REIPL_METHOD_CCW_VM:
                reipl_get_ascii_loadparm(loadparm);
                if (strlen(loadparm) == 0)
-                       sprintf(buf, "IPL %X",
+                       sprintf(buf, "IPL %X CLEAR",
                                reipl_block_ccw->ipl_info.ccw.devno);
                else
-                       sprintf(buf, "IPL %X LOADPARM '%s'",
+                       sprintf(buf, "IPL %X CLEAR LOADPARM '%s'",
                                reipl_block_ccw->ipl_info.ccw.devno, loadparm);
                __cpcmd(buf, NULL, 0, NULL);
                break;
index b4622a3..849120e 100644 (file)
@@ -2,6 +2,7 @@
  * Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
+#include <asm/page.h>
 #include <asm-generic/vmlinux.lds.h>
 
 #ifndef CONFIG_64BIT
@@ -18,121 +19,142 @@ jiffies = jiffies_64;
 
 SECTIONS
 {
-  . = 0x00000000;
-  _text = .;                   /* Text and read-only data */
-  .text : {
-       *(.text.head)
+       . = 0x00000000;
+       .text : {
+       _text = .;              /* Text and read-only data */
+               *(.text.head)
        TEXT_TEXT
-       SCHED_TEXT
-       LOCK_TEXT
-       KPROBES_TEXT
-       *(.fixup)
-       *(.gnu.warning)
+               SCHED_TEXT
+               LOCK_TEXT
+               KPROBES_TEXT
+               *(.fixup)
+               *(.gnu.warning)
        } = 0x0700
 
-  _etext = .;                  /* End of text section */
+       _etext = .;             /* End of text section */
 
-  RODATA
+       RODATA
 
 #ifdef CONFIG_SHARED_KERNEL
-  . = ALIGN(1048576);          /* VM shared segments are 1MB aligned */
+       . = ALIGN(0x100000);    /* VM shared segments are 1MB aligned */
 #endif
 
-  . = ALIGN(4096);
-  _eshared = .;                        /* End of shareable data */
-
-  . = ALIGN(16);               /* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
-  NOTES
-
-  BUG_TABLE
-
-  .data : {                    /* Data */
-       DATA_DATA
-       CONSTRUCTORS
-       }
-
-  . = ALIGN(4096);
-  __nosave_begin = .;
-  .data_nosave : { *(.data.nosave) }
-  . = ALIGN(4096);
-  __nosave_end = .;
-
-  . = ALIGN(4096);
-  .data.page_aligned : { *(.data.idt) }
-
-  . = ALIGN(256);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
-
-  . = ALIGN(256);
-  .data.read_mostly : { *(.data.read_mostly) }
-  _edata = .;                  /* End of data section */
-
-  . = ALIGN(8192);             /* init_task */
-  .data.init_task : { *(.data.init_task) }
-
-  /* will be freed after init */
-  . = ALIGN(4096);             /* Init code and data */
-  __init_begin = .;
-  .init.text : { 
-       _sinittext = .;
-       *(.init.text)
-       _einittext = .;
-  }
-  /*
-   * .exit.text is discarded at runtime, not link time,
-   * to deal with references from __bug_table
-   */
-  .exit.text :  { *(.exit.text) }
-
-  .init.data : { *(.init.data) }
-  . = ALIGN(256);
-  __setup_start = .;
-  .init.setup : { *(.init.setup) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : {
-       INITCALLS
-  }
-  __initcall_end = .;
-  __con_initcall_start = .;
-  .con_initcall.init : { *(.con_initcall.init) }
-  __con_initcall_end = .;
-  SECURITY_INIT
+       . = ALIGN(PAGE_SIZE);
+       _eshared = .;           /* End of shareable data */
+
+       . = ALIGN(16);          /* Exception table */
+       __ex_table : {
+               __start___ex_table = .;
+               *(__ex_table)
+               __stop___ex_table = .;
+       }
+
+       NOTES
+       BUG_TABLE
+
+       .data : {               /* Data */
+               DATA_DATA
+               CONSTRUCTORS
+       }
+
+       . = ALIGN(PAGE_SIZE);
+       .data_nosave : {
+       __nosave_begin = .;
+               *(.data.nosave)
+       }
+       . = ALIGN(PAGE_SIZE);
+       __nosave_end = .;
+
+       . = ALIGN(PAGE_SIZE);
+       .data.page_aligned : {
+               *(.data.idt)
+       }
+
+       . = ALIGN(0x100);
+       .data.cacheline_aligned : {
+               *(.data.cacheline_aligned)
+       }
+
+       . = ALIGN(0x100);
+       .data.read_mostly : {
+               *(.data.read_mostly)
+       }
+       _edata = .;             /* End of data section */
+
+       . = ALIGN(2 * PAGE_SIZE);       /* init_task */
+       .data.init_task : {
+               *(.data.init_task)
+       }
+
+       /* will be freed after init */
+       . = ALIGN(PAGE_SIZE);   /* Init code and data */
+       __init_begin = .;
+       .init.text : {
+               _sinittext = .;
+               *(.init.text)
+               _einittext = .;
+       }
+       /*
+        * .exit.text is discarded at runtime, not link time,
+        * to deal with references from __bug_table
+       */
+       .exit.text : {
+               *(.exit.text)
+       }
+
+       .init.data : {
+               *(.init.data)
+       }
+       . = ALIGN(0x100);
+       .init.setup : {
+               __setup_start = .;
+               *(.init.setup)
+               __setup_end = .;
+       }
+       .initcall.init : {
+               __initcall_start = .;
+               INITCALLS
+               __initcall_end = .;
+       }
+
+       .con_initcall.init : {
+               __con_initcall_start = .;
+               *(.con_initcall.init)
+               __con_initcall_end = .;
+       }
+       SECURITY_INIT
 
 #ifdef CONFIG_BLK_DEV_INITRD
-  . = ALIGN(256);
-  __initramfs_start = .;
-  .init.ramfs : { *(.init.initramfs) }
-  . = ALIGN(2);
-  __initramfs_end = .;
+       . = ALIGN(0x100);
+       .init.ramfs : {
+               __initramfs_start = .;
+               *(.init.ramfs)
+               . = ALIGN(2);
+               __initramfs_end = .;
+       }
 #endif
-  PERCPU(4096)
-  . = ALIGN(4096);
-  __init_end = .;
-  /* freed after init ends here */
-
-  __bss_start = .;             /* BSS */
-  .bss : { *(.bss) }
-  . = ALIGN(2);
-  __bss_stop = .;
-
-  _end = . ;
-
-  /* Sections to be discarded */
-  /DISCARD/ : {
-       *(.exit.data) *(.exitcall.exit)
-       }
-
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
+
+       PERCPU(PAGE_SIZE)
+       . = ALIGN(PAGE_SIZE);
+       __init_end = .;         /* freed after init ends here */
+
+       /* BSS */
+       .bss : {
+               __bss_start = .;
+               *(.bss)
+               . = ALIGN(2);
+               __bss_stop = .;
+       }
+
+       _end = . ;
+
+       /* Sections to be discarded */
+       /DISCARD/ : {
+               *(.exit.data)
+               *(.exitcall.exit)
+       }
+
+       /* Debugging sections.  */
+       STABS_DEBUG
+       DWARF_DEBUG
 }
index 5405519..4c1ac34 100644 (file)
@@ -468,7 +468,7 @@ typedef struct {
        __u64 refselmk;
        __u64 refcmpmk;
        __u64 reserved;
-} __attribute__ ((packed)) pfault_refbk_t;
+} __attribute__ ((packed, aligned(8))) pfault_refbk_t;
 
 int pfault_init(void)
 {
index e618902..71d1c42 100644 (file)
@@ -93,7 +93,6 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
        policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 
-       policy->governor        = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cur             = sh_cpufreq_get(policy->cpu);
        policy->min             = policy->cpuinfo.min_freq;
        policy->max             = policy->cpuinfo.max_freq;
index 1f83fe6..791c151 100644 (file)
@@ -326,7 +326,6 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
        table[2].index = 5;
        table[3].frequency = CPUFREQ_TABLE_END;
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 0;
        policy->cur = clock_tick;
 
index c624193..7ff0206 100644 (file)
@@ -7,7 +7,7 @@ extra-y := head_32.o init_task_32.o vmlinux.lds
 obj-y  := process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
                ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
                pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-               quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o
+               quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
 
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-y                          += cpu/
@@ -37,9 +37,9 @@ obj-$(CONFIG_EFI)             += efi_32.o efi_stub_32.o
 obj-$(CONFIG_DOUBLEFAULT)      += doublefault_32.o
 obj-$(CONFIG_VM86)             += vm86_32.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
-obj-$(CONFIG_HPET_TIMER)       += hpet_32.o
+obj-$(CONFIG_HPET_TIMER)       += hpet.o
 obj-$(CONFIG_K8_NB)            += k8.o
-obj-$(CONFIG_MGEODE_LX)                += geode_32.o
+obj-$(CONFIG_MGEODE_LX)                += geode_32.o mfgpt_32.o
 
 obj-$(CONFIG_VMI)              += vmi_32.o vmiclock_32.o
 obj-$(CONFIG_PARAVIRT)         += paravirt_32.o
index 3ab017a..43da662 100644 (file)
@@ -8,8 +8,8 @@ obj-y   := process_64.o signal_64.o entry_64.o traps_64.o irq_64.o \
                ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \
                x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
                setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
-               pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc_64.o bugs_64.o \
-               perfctr-watchdog.o
+               pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
+               perfctr-watchdog.o i8253.o
 
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-$(CONFIG_X86_MCE)          += mce_64.o therm_throt.o
index 925758d..395928d 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/sysdev.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
+#include <linux/clockchips.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
 #include <asm/hpet.h>
 #include <asm/apic.h>
 
-int apic_mapped;
 int apic_verbosity;
-int apic_runs_main_timer;
-int apic_calibrate_pmtmr __initdata;
-
-int disable_apic_timer __initdata;
+int disable_apic_timer __cpuinitdata;
+static int apic_calibrate_pmtmr __initdata;
 
 /* Local APIC timer works in C2? */
 int local_apic_timer_c2_ok;
@@ -56,14 +54,78 @@ static struct resource lapic_resource = {
        .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
 };
 
+static unsigned int calibration_result;
+
+static int lapic_next_event(unsigned long delta,
+                           struct clock_event_device *evt);
+static void lapic_timer_setup(enum clock_event_mode mode,
+                             struct clock_event_device *evt);
+
+static void lapic_timer_broadcast(cpumask_t mask);
+
+static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen);
+
+static struct clock_event_device lapic_clockevent = {
+       .name           = "lapic",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
+                       | CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
+       .shift          = 32,
+       .set_mode       = lapic_timer_setup,
+       .set_next_event = lapic_next_event,
+       .broadcast      = lapic_timer_broadcast,
+       .rating         = 100,
+       .irq            = -1,
+};
+static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
+
+static int lapic_next_event(unsigned long delta,
+                           struct clock_event_device *evt)
+{
+       apic_write(APIC_TMICT, delta);
+       return 0;
+}
+
+static void lapic_timer_setup(enum clock_event_mode mode,
+                             struct clock_event_device *evt)
+{
+       unsigned long flags;
+       unsigned int v;
+
+       /* Lapic used as dummy for broadcast ? */
+       if (evt->features & CLOCK_EVT_FEAT_DUMMY)
+               return;
+
+       local_irq_save(flags);
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+       case CLOCK_EVT_MODE_ONESHOT:
+               __setup_APIC_LVTT(calibration_result,
+                                 mode != CLOCK_EVT_MODE_PERIODIC, 1);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               v = apic_read(APIC_LVTT);
+               v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+               apic_write(APIC_LVTT, v);
+               break;
+       case CLOCK_EVT_MODE_RESUME:
+               /* Nothing to do here */
+               break;
+       }
+
+       local_irq_restore(flags);
+}
+
 /*
- * cpu_mask that denotes the CPUs that needs timer interrupt coming in as
- * IPIs in place of local APIC timers
+ * Local APIC timer broadcast function
  */
-static cpumask_t timer_interrupt_broadcast_ipi_mask;
-
-/* Using APIC to generate smp_local_timer_interrupt? */
-int using_apic_timer __read_mostly = 0;
+static void lapic_timer_broadcast(cpumask_t mask)
+{
+#ifdef CONFIG_SMP
+       send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
+#endif
+}
 
 static void apic_pm_activate(void);
 
@@ -184,7 +246,10 @@ void disconnect_bsp_APIC(int virt_wire_setup)
        apic_write(APIC_SPIV, value);
 
        if (!virt_wire_setup) {
-               /* For LVT0 make it edge triggered, active high, external and enabled */
+               /*
+                * For LVT0 make it edge triggered, active high,
+                * external and enabled
+                */
                value = apic_read(APIC_LVT0);
                value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
                        APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
@@ -420,10 +485,12 @@ void __cpuinit setup_local_APIC (void)
        value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
        if (!smp_processor_id() && !value) {
                value = APIC_DM_EXTINT;
-               apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id());
+               apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n",
+                           smp_processor_id());
        } else {
                value = APIC_DM_EXTINT | APIC_LVT_MASKED;
-               apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id());
+               apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n",
+                           smp_processor_id());
        }
        apic_write(APIC_LVT0, value);
 
@@ -706,8 +773,8 @@ void __init init_apic_mappings(void)
                apic_phys = mp_lapic_addr;
 
        set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
-       apic_mapped = 1;
-       apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys);
+       apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
+                               APIC_BASE, apic_phys);
 
        /* Put local APIC into the resource map. */
        lapic_resource.start = apic_phys;
@@ -730,12 +797,14 @@ void __init init_apic_mappings(void)
                        if (smp_found_config) {
                                ioapic_phys = mp_ioapics[i].mpc_apicaddr;
                        } else {
-                               ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
+                               ioapic_phys = (unsigned long)
+                                       alloc_bootmem_pages(PAGE_SIZE);
                                ioapic_phys = __pa(ioapic_phys);
                        }
                        set_fixmap_nocache(idx, ioapic_phys);
-                       apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n",
-                                       __fix_to_virt(idx), ioapic_phys);
+                       apic_printk(APIC_VERBOSE,
+                                   "mapped IOAPIC to %016lx (%016lx)\n",
+                                   __fix_to_virt(idx), ioapic_phys);
                        idx++;
 
                        if (ioapic_res != NULL) {
@@ -758,16 +827,14 @@ void __init init_apic_mappings(void)
  * P5 APIC double write bug.
  */
 
-#define APIC_DIVISOR 16
-
-static void __setup_APIC_LVTT(unsigned int clocks)
+static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
 {
        unsigned int lvtt_value, tmp_value;
-       int cpu = smp_processor_id();
 
-       lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
-
-       if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
+       lvtt_value = LOCAL_TIMER_VECTOR;
+       if (!oneshot)
+               lvtt_value |= APIC_LVT_TIMER_PERIODIC;
+       if (!irqen)
                lvtt_value |= APIC_LVT_MASKED;
 
        apic_write(APIC_LVTT, lvtt_value);
@@ -780,44 +847,18 @@ static void __setup_APIC_LVTT(unsigned int clocks)
                                & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
                                | APIC_TDR_DIV_16);
 
-       apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
+       if (!oneshot)
+               apic_write(APIC_TMICT, clocks);
 }
 
-static void setup_APIC_timer(unsigned int clocks)
+static void setup_APIC_timer(void)
 {
-       unsigned long flags;
+       struct clock_event_device *levt = &__get_cpu_var(lapic_events);
 
-       local_irq_save(flags);
+       memcpy(levt, &lapic_clockevent, sizeof(*levt));
+       levt->cpumask = cpumask_of_cpu(smp_processor_id());
 
-       /* wait for irq slice */
-       if (hpet_address && hpet_use_timer) {
-               u32 trigger = hpet_readl(HPET_T0_CMP);
-               while (hpet_readl(HPET_T0_CMP) == trigger)
-                       /* do nothing */ ;
-       } else {
-               int c1, c2;
-               outb_p(0x00, 0x43);
-               c2 = inb_p(0x40);
-               c2 |= inb_p(0x40) << 8;
-               do {
-                       c1 = c2;
-                       outb_p(0x00, 0x43);
-                       c2 = inb_p(0x40);
-                       c2 |= inb_p(0x40) << 8;
-               } while (c2 - c1 < 300);
-       }
-       __setup_APIC_LVTT(clocks);
-       /* Turn off PIT interrupt if we use APIC timer as main timer.
-          Only works with the PM timer right now
-          TBD fix it for HPET too. */
-       if ((pmtmr_ioport != 0) &&
-               smp_processor_id() == boot_cpu_id &&
-               apic_runs_main_timer == 1 &&
-               !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
-               stop_timer_interrupt();
-               apic_runs_main_timer++;
-       }
-       local_irq_restore(flags);
+       clockevents_register_device(levt);
 }
 
 /*
@@ -835,17 +876,22 @@ static void setup_APIC_timer(unsigned int clocks)
 
 #define TICK_COUNT 100000000
 
-static int __init calibrate_APIC_clock(void)
+static void __init calibrate_APIC_clock(void)
 {
        unsigned apic, apic_start;
        unsigned long tsc, tsc_start;
        int result;
+
+       local_irq_disable();
+
        /*
         * Put whatever arbitrary (but long enough) timeout
         * value into the APIC clock, we just want to get the
         * counter running for calibration.
+        *
+        * No interrupt enable !
         */
-       __setup_APIC_LVTT(4000000000);
+       __setup_APIC_LVTT(250000000, 0, 0);
 
        apic_start = apic_read(APIC_TMCCT);
 #ifdef CONFIG_X86_PM_TIMER
@@ -867,123 +913,62 @@ static int __init calibrate_APIC_clock(void)
                result = (apic_start - apic) * 1000L * tsc_khz /
                                        (tsc - tsc_start);
        }
-       printk("result %d\n", result);
 
+       local_irq_enable();
+
+       printk(KERN_DEBUG "APIC timer calibration result %d\n", result);
 
        printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
                result / 1000 / 1000, result / 1000 % 1000);
 
-       return result * APIC_DIVISOR / HZ;
-}
+       /* Calculate the scaled math multiplication factor */
+       lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC, 32);
+       lapic_clockevent.max_delta_ns =
+               clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
+       lapic_clockevent.min_delta_ns =
+               clockevent_delta2ns(0xF, &lapic_clockevent);
 
-static unsigned int calibration_result;
+       calibration_result = result / HZ;
+}
 
 void __init setup_boot_APIC_clock (void)
 {
+       /*
+        * The local apic timer can be disabled via the kernel commandline.
+        * Register the lapic timer as a dummy clock event source on SMP
+        * systems, so the broadcast mechanism is used. On UP systems simply
+        * ignore it.
+        */
        if (disable_apic_timer) {
                printk(KERN_INFO "Disabling APIC timer\n");
+               /* No broadcast on UP ! */
+               if (num_possible_cpus() > 1)
+                       setup_APIC_timer();
                return;
        }
 
        printk(KERN_INFO "Using local APIC timer interrupts.\n");
-       using_apic_timer = 1;
-
-       local_irq_disable();
+       calibrate_APIC_clock();
 
-       calibration_result = calibrate_APIC_clock();
        /*
-        * Now set up the timer for real.
+        * If nmi_watchdog is set to IO_APIC, we need the
+        * PIT/HPET going.  Otherwise register lapic as a dummy
+        * device.
         */
-       setup_APIC_timer(calibration_result);
+       if (nmi_watchdog != NMI_IO_APIC)
+               lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+       else
+               printk(KERN_WARNING "APIC timer registered as dummy,"
+                      " due to nmi_watchdog=1!\n");
 
-       local_irq_enable();
+       setup_APIC_timer();
 }
 
 void __cpuinit setup_secondary_APIC_clock(void)
 {
-       local_irq_disable(); /* FIXME: Do we need this? --RR */
-       setup_APIC_timer(calibration_result);
-       local_irq_enable();
+       setup_APIC_timer();
 }
 
-void disable_APIC_timer(void)
-{
-       if (using_apic_timer) {
-               unsigned long v;
-
-               v = apic_read(APIC_LVTT);
-               /*
-                * When an illegal vector value (0-15) is written to an LVT
-                * entry and delivery mode is Fixed, the APIC may signal an
-                * illegal vector error, with out regard to whether the mask
-                * bit is set or whether an interrupt is actually seen on input.
-                *
-                * Boot sequence might call this function when the LVTT has
-                * '0' vector value. So make sure vector field is set to
-                * valid value.
-                */
-               v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
-               apic_write(APIC_LVTT, v);
-       }
-}
-
-void enable_APIC_timer(void)
-{
-       int cpu = smp_processor_id();
-
-       if (using_apic_timer &&
-           !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-               unsigned long v;
-
-               v = apic_read(APIC_LVTT);
-               apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
-       }
-}
-
-void switch_APIC_timer_to_ipi(void *cpumask)
-{
-       cpumask_t mask = *(cpumask_t *)cpumask;
-       int cpu = smp_processor_id();
-
-       if (cpu_isset(cpu, mask) &&
-           !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-               disable_APIC_timer();
-               cpu_set(cpu, timer_interrupt_broadcast_ipi_mask);
-       }
-}
-EXPORT_SYMBOL(switch_APIC_timer_to_ipi);
-
-void smp_send_timer_broadcast_ipi(void)
-{
-       int cpu = smp_processor_id();
-       cpumask_t mask;
-
-       cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask);
-
-       if (cpu_isset(cpu, mask)) {
-               cpu_clear(cpu, mask);
-               add_pda(apic_timer_irqs, 1);
-               smp_local_timer_interrupt();
-       }
-
-       if (!cpus_empty(mask)) {
-               send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
-       }
-}
-
-void switch_ipi_to_APIC_timer(void *cpumask)
-{
-       cpumask_t mask = *(cpumask_t *)cpumask;
-       int cpu = smp_processor_id();
-
-       if (cpu_isset(cpu, mask) &&
-           cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-               cpu_clear(cpu, timer_interrupt_broadcast_ipi_mask);
-               enable_APIC_timer();
-       }
-}
-EXPORT_SYMBOL(switch_ipi_to_APIC_timer);
-
 int setup_profiling_timer(unsigned int multiplier)
 {
        return -EINVAL;
@@ -997,8 +982,6 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
        apic_write(reg, v);
 }
 
-#undef APIC_DIVISOR
-
 /*
  * Local timer interrupt handler. It does both profiling and
  * process statistics/rescheduling.
@@ -1011,22 +994,34 @@ void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
 
 void smp_local_timer_interrupt(void)
 {
-       profile_tick(CPU_PROFILING);
-#ifdef CONFIG_SMP
-       update_process_times(user_mode(get_irq_regs()));
-#endif
-       if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
-               main_timer_handler();
+       int cpu = smp_processor_id();
+       struct clock_event_device *evt = &per_cpu(lapic_events, cpu);
+
        /*
-        * We take the 'long' return path, and there every subsystem
-        * grabs the appropriate locks (kernel lock/ irq lock).
+        * Normally we should not be here till LAPIC has been initialized but
+        * in some cases like kdump, its possible that there is a pending LAPIC
+        * timer interrupt from previous kernel's context and is delivered in
+        * new kernel the moment interrupts are enabled.
         *
-        * We might want to decouple profiling from the 'long path',
-        * and do the profiling totally in assembly.
-        *
-        * Currently this isn't too much of an issue (performance wise),
-        * we can take more than 100K local irqs per second on a 100 MHz P5.
+        * Interrupts are enabled early and LAPIC is setup much later, hence
+        * its possible that when we get here evt->event_handler is NULL.
+        * Check for event_handler being NULL and discard the interrupt as
+        * spurious.
+        */
+       if (!evt->event_handler) {
+               printk(KERN_WARNING
+                      "Spurious LAPIC timer interrupt on cpu %d\n", cpu);
+               /* Switch it off */
+               lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt);
+               return;
+       }
+
+       /*
+        * the NMI deadlock-detector uses this.
         */
+       add_pda(apic_timer_irqs, 1);
+
+       evt->event_handler(evt);
 }
 
 /*
@@ -1042,11 +1037,6 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
        struct pt_regs *old_regs = set_irq_regs(regs);
 
        /*
-        * the NMI deadlock-detector uses this.
-        */
-       add_pda(apic_timer_irqs, 1);
-
-       /*
         * NOTE! We'd better ACK the irq immediately,
         * because timer handling can be slow.
         */
@@ -1225,29 +1215,13 @@ static __init int setup_noapictimer(char *str)
        disable_apic_timer = 1;
        return 1;
 }
-
-static __init int setup_apicmaintimer(char *str)
-{
-       apic_runs_main_timer = 1;
-       nohpet = 1;
-       return 1;
-}
-__setup("apicmaintimer", setup_apicmaintimer);
-
-static __init int setup_noapicmaintimer(char *str)
-{
-       apic_runs_main_timer = -1;
-       return 1;
-}
-__setup("noapicmaintimer", setup_noapicmaintimer);
+__setup("noapictimer", setup_noapictimer);
 
 static __init int setup_apicpmtimer(char *s)
 {
        apic_calibrate_pmtmr = 1;
        notsc_setup(NULL);
-       return setup_apicmaintimer(NULL);
+       return 0;
 }
 __setup("apicpmtimer", setup_apicpmtimer);
 
-__setup("noapictimer", setup_noapictimer);
-
index b6434a7..ffd01e5 100644 (file)
@@ -646,7 +646,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
                        policy->cpuinfo.transition_latency =
                            perf->states[i].transition_latency * 1000;
        }
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 
        data->max_freq = perf->states[0].core_frequency * 1000;
        /* table init */
index 66acd50..32f0bda 100644 (file)
@@ -363,7 +363,6 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
        policy->cur = nforce2_get(policy->cpu);
        policy->min = policy->cpuinfo.min_freq;
        policy->max = policy->cpuinfo.max_freq;
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 
        return 0;
 }
index f43d98e..c11baaf 100644 (file)
@@ -253,7 +253,6 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
                f_table[k].frequency = CPUFREQ_TABLE_END;
        }
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */
        policy->cur = fsb * current_multiplier;
 
index f317276..1e7ae7d 100644 (file)
@@ -219,7 +219,6 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
        }
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        policy->cur = elanfreq_get_cpu_frequency(0);
 
index 461dabc..ed2bda1 100644 (file)
@@ -420,7 +420,6 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
                policy->min = maxfreq / POLICY_MIN_DIV;
        policy->max = maxfreq;
        policy->cur = curfreq;
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.min_freq = maxfreq / max_duration;
        policy->cpuinfo.max_freq = maxfreq;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
index f0cce3c..5045f5d 100644 (file)
@@ -710,6 +710,10 @@ static int enable_arbiter_disable(void)
        reg = 0x78;
        dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,
                             NULL);
+       /* Find PM133/VT8605 host bridge */
+       if (dev == NULL)
+               dev = pci_get_device(PCI_VENDOR_ID_VIA,
+                                    PCI_DEVICE_ID_VIA_8605_0, NULL);
        /* Find CLE266 host bridge */
        if (dev == NULL) {
                reg = 0x76;
@@ -918,7 +922,6 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
        if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))
                longhaul_setup_voltagescaling();
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 200000;    /* nsec */
        policy->cur = calc_speed(longhaul_get_cpu_mult());
 
index 4c76b51..8eb414b 100644 (file)
@@ -229,7 +229,6 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
        cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu);
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 1000000; /* assumed */
        policy->cur = stock_freq;
 
index f895240..6d02853 100644 (file)
@@ -160,7 +160,6 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
        }
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        policy->cur = busfreq * max_multiplier;
 
index ca3e1d3..7decd6a 100644 (file)
@@ -637,8 +637,6 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy)
        printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
                                minimum_speed/1000, maximum_speed/1000);
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
        policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency);
 
        policy->cur = powernow_get(0);
index 34ed53a..b273b69 100644 (file)
@@ -76,7 +76,10 @@ static u32 find_khz_freq_from_fid(u32 fid)
 /* Return a frequency in MHz, given an input fid and did */
 static u32 find_freq_from_fiddid(u32 fid, u32 did)
 {
-       return 100 * (fid + 0x10) >> did;
+       if (current_cpu_data.x86 == 0x10)
+               return 100 * (fid + 0x10) >> did;
+       else
+               return 100 * (fid + 0x8) >> did;
 }
 
 static u32 find_khz_freq_from_fiddid(u32 fid, u32 did)
@@ -1208,7 +1211,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
        /* run on any CPU again */
        set_cpus_allowed(current, oldmask);
 
-       pol->governor = CPUFREQ_DEFAULT_GOVERNOR;
        if (cpu_family == CPU_HW_PSTATE)
                pol->cpus = cpumask_of_cpu(pol->cpu);
        else
@@ -1325,21 +1327,16 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
 static int __cpuinit powernowk8_init(void)
 {
        unsigned int i, supported_cpus = 0;
-       unsigned int booted_cores = 1;
 
        for_each_online_cpu(i) {
                if (check_supported_cpu(i))
                        supported_cpus++;
        }
 
-#ifdef CONFIG_SMP
-       booted_cores = cpu_data[0].booted_cores;
-#endif
-
        if (supported_cpus == num_online_cpus()) {
                printk(KERN_INFO PFX "Found %d %s "
                        "processors (%d cpu cores) (" VERSION ")\n",
-                       supported_cpus/booted_cores,
+                       num_online_nodes(),
                        boot_cpu_data.x86_model_id, supported_cpus);
                return cpufreq_register_driver(&cpufreq_amd64_driver);
        }
index b8fb4b5..d9f3e90 100644 (file)
@@ -111,7 +111,6 @@ static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
                return -ENODEV;
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 1000000; /* 1ms */
        policy->cur = sc520_freq_get_cpu_frequency(0);
 
index 6c5dc2c..811d474 100644 (file)
@@ -393,7 +393,6 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
 
        freq = get_cur_freq(policy->cpu);
 
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */
        policy->cur = freq;
 
index a5b2346..36685e8 100644 (file)
@@ -348,7 +348,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
                (speed / 1000));
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cur = speed;
 
        result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
index e1c509a..f2b5a62 100644 (file)
@@ -290,7 +290,6 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
                (speed / 1000));
 
        /* cpuinfo and default policy values */
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
        policy->cur = speed;
 
index 41e8aec..f12d8c5 100644 (file)
@@ -145,10 +145,14 @@ EXPORT_SYMBOL_GPL(geode_gpio_setup_event);
 
 static int __init geode_southbridge_init(void)
 {
+       int timers;
+
        if (!is_geode())
                return -ENODEV;
 
        init_lbars();
+       timers = geode_mfgpt_detect();
+       printk(KERN_INFO "geode:  %d MFGPT timers available.\n", timers);
        return 0;
 }
 
similarity index 81%
rename from arch/x86/kernel/hpet_32.c
rename to arch/x86/kernel/hpet.c
index 533d493..f836707 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/hpet.h>
 #include <linux/init.h>
@@ -7,11 +8,11 @@
 #include <linux/pm.h>
 #include <linux/delay.h>
 
+#include <asm/fixmap.h>
 #include <asm/hpet.h>
+#include <asm/i8253.h>
 #include <asm/io.h>
 
-extern struct clock_event_device *global_clock_event;
-
 #define HPET_MASK      CLOCKSOURCE_MASK(32)
 #define HPET_SHIFT     22
 
@@ -22,9 +23,9 @@ extern struct clock_event_device *global_clock_event;
  * HPET address is set in acpi/boot.c, when an ACPI entry exists
  */
 unsigned long hpet_address;
-static void __iomem * hpet_virt_address;
+static void __iomem *hpet_virt_address;
 
-static inline unsigned long hpet_readl(unsigned long a)
+unsigned long hpet_readl(unsigned long a)
 {
        return readl(hpet_virt_address + a);
 }
@@ -34,6 +35,36 @@ static inline void hpet_writel(unsigned long d, unsigned long a)
        writel(d, hpet_virt_address + a);
 }
 
+#ifdef CONFIG_X86_64
+
+#include <asm/pgtable.h>
+
+static inline void hpet_set_mapping(void)
+{
+       set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
+       __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
+       hpet_virt_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE);
+}
+
+static inline void hpet_clear_mapping(void)
+{
+       hpet_virt_address = NULL;
+}
+
+#else
+
+static inline void hpet_set_mapping(void)
+{
+       hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
+}
+
+static inline void hpet_clear_mapping(void)
+{
+       iounmap(hpet_virt_address);
+       hpet_virt_address = NULL;
+}
+#endif
+
 /*
  * HPET command line enable / disable
  */
@@ -49,6 +80,13 @@ static int __init hpet_setup(char* str)
 }
 __setup("hpet=", hpet_setup);
 
+static int __init disable_hpet(char *str)
+{
+       boot_hpet_disable = 1;
+       return 1;
+}
+__setup("nohpet", disable_hpet);
+
 static inline int is_hpet_capable(void)
 {
        return (!boot_hpet_disable && hpet_address);
@@ -83,7 +121,7 @@ static void hpet_reserve_platform_timers(unsigned long id)
 
        memset(&hd, 0, sizeof (hd));
        hd.hd_phys_address = hpet_address;
-       hd.hd_address = hpet_virt_address;
+       hd.hd_address = hpet;
        hd.hd_nirqs = nrtimers;
        hd.hd_flags = HPET_DATA_PLATFORM;
        hpet_reserve_timer(&hd, 0);
@@ -111,9 +149,9 @@ static void hpet_reserve_platform_timers(unsigned long id) { }
  */
 static unsigned long hpet_period;
 
-static void hpet_set_mode(enum clock_event_mode mode,
+static void hpet_legacy_set_mode(enum clock_event_mode mode,
                          struct clock_event_device *evt);
-static int hpet_next_event(unsigned long delta,
+static int hpet_legacy_next_event(unsigned long delta,
                           struct clock_event_device *evt);
 
 /*
@@ -122,10 +160,11 @@ static int hpet_next_event(unsigned long delta,
 static struct clock_event_device hpet_clockevent = {
        .name           = "hpet",
        .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .set_mode       = hpet_set_mode,
-       .set_next_event = hpet_next_event,
+       .set_mode       = hpet_legacy_set_mode,
+       .set_next_event = hpet_legacy_next_event,
        .shift          = 32,
        .irq            = 0,
+       .rating         = 50,
 };
 
 static void hpet_start_counter(void)
@@ -140,7 +179,18 @@ static void hpet_start_counter(void)
        hpet_writel(cfg, HPET_CFG);
 }
 
-static void hpet_enable_int(void)
+static void hpet_resume_device(void)
+{
+       force_hpet_resume();
+}
+
+static void hpet_restart_counter(void)
+{
+       hpet_resume_device();
+       hpet_start_counter();
+}
+
+static void hpet_enable_legacy_int(void)
 {
        unsigned long cfg = hpet_readl(HPET_CFG);
 
@@ -149,7 +199,39 @@ static void hpet_enable_int(void)
        hpet_legacy_int_enabled = 1;
 }
 
-static void hpet_set_mode(enum clock_event_mode mode,
+static void hpet_legacy_clockevent_register(void)
+{
+       uint64_t hpet_freq;
+
+       /* Start HPET legacy interrupts */
+       hpet_enable_legacy_int();
+
+       /*
+        * The period is a femto seconds value. We need to calculate the
+        * scaled math multiplication factor for nanosecond to hpet tick
+        * conversion.
+        */
+       hpet_freq = 1000000000000000ULL;
+       do_div(hpet_freq, hpet_period);
+       hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
+                                     NSEC_PER_SEC, 32);
+       /* Calculate the min / max delta */
+       hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
+                                                          &hpet_clockevent);
+       hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
+                                                          &hpet_clockevent);
+
+       /*
+        * Start hpet with the boot cpu mask and make it
+        * global after the IO_APIC has been initialized.
+        */
+       hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
+       clockevents_register_device(&hpet_clockevent);
+       global_clock_event = &hpet_clockevent;
+       printk(KERN_DEBUG "hpet clockevent registered\n");
+}
+
+static void hpet_legacy_set_mode(enum clock_event_mode mode,
                          struct clock_event_device *evt)
 {
        unsigned long cfg, cmp, now;
@@ -190,12 +272,12 @@ static void hpet_set_mode(enum clock_event_mode mode,
                break;
 
        case CLOCK_EVT_MODE_RESUME:
-               hpet_enable_int();
+               hpet_enable_legacy_int();
                break;
        }
 }
 
-static int hpet_next_event(unsigned long delta,
+static int hpet_legacy_next_event(unsigned long delta,
                           struct clock_event_device *evt)
 {
        unsigned long cnt;
@@ -215,6 +297,13 @@ static cycle_t read_hpet(void)
        return (cycle_t)hpet_readl(HPET_COUNTER);
 }
 
+#ifdef CONFIG_X86_64
+static cycle_t __vsyscall_fn vread_hpet(void)
+{
+       return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
+}
+#endif
+
 static struct clocksource clocksource_hpet = {
        .name           = "hpet",
        .rating         = 250,
@@ -222,61 +311,17 @@ static struct clocksource clocksource_hpet = {
        .mask           = HPET_MASK,
        .shift          = HPET_SHIFT,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-       .resume         = hpet_start_counter,
+       .resume         = hpet_restart_counter,
+#ifdef CONFIG_X86_64
+       .vread          = vread_hpet,
+#endif
 };
 
-/*
- * Try to setup the HPET timer
- */
-int __init hpet_enable(void)
+static int hpet_clocksource_register(void)
 {
-       unsigned long id;
-       uint64_t hpet_freq;
        u64 tmp, start, now;
        cycle_t t1;
 
-       if (!is_hpet_capable())
-               return 0;
-
-       hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
-
-       /*
-        * Read the period and check for a sane value:
-        */
-       hpet_period = hpet_readl(HPET_PERIOD);
-       if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
-               goto out_nohpet;
-
-       /*
-        * The period is a femto seconds value. We need to calculate the
-        * scaled math multiplication factor for nanosecond to hpet tick
-        * conversion.
-        */
-       hpet_freq = 1000000000000000ULL;
-       do_div(hpet_freq, hpet_period);
-       hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
-                                     NSEC_PER_SEC, 32);
-       /* Calculate the min / max delta */
-       hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
-                                                          &hpet_clockevent);
-       hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
-                                                          &hpet_clockevent);
-
-       /*
-        * Read the HPET ID register to retrieve the IRQ routing
-        * information and the number of channels
-        */
-       id = hpet_readl(HPET_ID);
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-       /*
-        * The legacy routing mode needs at least two channels, tick timer
-        * and the rtc emulation channel.
-        */
-       if (!(id & HPET_ID_NUMBER))
-               goto out_nohpet;
-#endif
-
        /* Start the counter */
        hpet_start_counter();
 
@@ -298,7 +343,7 @@ int __init hpet_enable(void)
        if (t1 == read_hpet()) {
                printk(KERN_WARNING
                       "HPET counter not counting. HPET disabled\n");
-               goto out_nohpet;
+               return -ENODEV;
        }
 
        /* Initialize and register HPET clocksource
@@ -319,27 +364,84 @@ int __init hpet_enable(void)
 
        clocksource_register(&clocksource_hpet);
 
+       return 0;
+}
+
+/*
+ * Try to setup the HPET timer
+ */
+int __init hpet_enable(void)
+{
+       unsigned long id;
+
+       if (!is_hpet_capable())
+               return 0;
+
+       hpet_set_mapping();
+
+       /*
+        * Read the period and check for a sane value:
+        */
+       hpet_period = hpet_readl(HPET_PERIOD);
+       if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
+               goto out_nohpet;
+
+       /*
+        * Read the HPET ID register to retrieve the IRQ routing
+        * information and the number of channels
+        */
+       id = hpet_readl(HPET_ID);
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+       /*
+        * The legacy routing mode needs at least two channels, tick timer
+        * and the rtc emulation channel.
+        */
+       if (!(id & HPET_ID_NUMBER))
+               goto out_nohpet;
+#endif
+
+       if (hpet_clocksource_register())
+               goto out_nohpet;
+
        if (id & HPET_ID_LEGSUP) {
-               hpet_enable_int();
-               hpet_reserve_platform_timers(id);
-               /*
-                * Start hpet with the boot cpu mask and make it
-                * global after the IO_APIC has been initialized.
-                */
-               hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
-               clockevents_register_device(&hpet_clockevent);
-               global_clock_event = &hpet_clockevent;
+               hpet_legacy_clockevent_register();
                return 1;
        }
        return 0;
 
 out_nohpet:
-       iounmap(hpet_virt_address);
-       hpet_virt_address = NULL;
+       hpet_clear_mapping();
        boot_hpet_disable = 1;
        return 0;
 }
 
+/*
+ * Needs to be late, as the reserve_timer code calls kalloc !
+ *
+ * Not a problem on i386 as hpet_enable is called from late_time_init,
+ * but on x86_64 it is necessary !
+ */
+static __init int hpet_late_init(void)
+{
+       if (boot_hpet_disable)
+               return -ENODEV;
+
+       if (!hpet_address) {
+               if (!force_hpet_address)
+                       return -ENODEV;
+
+               hpet_address = force_hpet_address;
+               hpet_enable();
+               if (!hpet_virt_address)
+                       return -ENODEV;
+       }
+
+       hpet_reserve_platform_timers(hpet_readl(HPET_ID));
+
+       return 0;
+}
+fs_initcall(hpet_late_init);
 
 #ifdef CONFIG_HPET_EMULATE_RTC
 
diff --git a/arch/x86/kernel/hpet_64.c b/arch/x86/kernel/hpet_64.c
deleted file mode 100644 (file)
index e2d1b91..0000000
+++ /dev/null
@@ -1,493 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/mc146818rtc.h>
-#include <linux/time.h>
-#include <linux/clocksource.h>
-#include <linux/ioport.h>
-#include <linux/acpi.h>
-#include <linux/hpet.h>
-#include <asm/pgtable.h>
-#include <asm/vsyscall.h>
-#include <asm/timex.h>
-#include <asm/hpet.h>
-
-#define HPET_MASK      0xFFFFFFFF
-#define HPET_SHIFT     22
-
-/* FSEC = 10^-15 NSEC = 10^-9 */
-#define FSEC_PER_NSEC  1000000
-
-int nohpet __initdata;
-
-unsigned long hpet_address;
-unsigned long hpet_period;     /* fsecs / HPET clock */
-unsigned long hpet_tick;       /* HPET clocks / interrupt */
-
-int hpet_use_timer;            /* Use counter of hpet for time keeping,
-                                * otherwise PIT
-                                */
-
-#ifdef CONFIG_HPET
-static __init int late_hpet_init(void)
-{
-       struct hpet_data        hd;
-       unsigned int            ntimer;
-
-       if (!hpet_address)
-               return 0;
-
-       memset(&hd, 0, sizeof(hd));
-
-       ntimer = hpet_readl(HPET_ID);
-       ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
-       ntimer++;
-
-       /*
-        * Register with driver.
-        * Timer0 and Timer1 is used by platform.
-        */
-       hd.hd_phys_address = hpet_address;
-       hd.hd_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE);
-       hd.hd_nirqs = ntimer;
-       hd.hd_flags = HPET_DATA_PLATFORM;
-       hpet_reserve_timer(&hd, 0);
-#ifdef CONFIG_HPET_EMULATE_RTC
-       hpet_reserve_timer(&hd, 1);
-#endif
-       hd.hd_irq[0] = HPET_LEGACY_8254;
-       hd.hd_irq[1] = HPET_LEGACY_RTC;
-       if (ntimer > 2) {
-               struct hpet             *hpet;
-               struct hpet_timer       *timer;
-               int                     i;
-
-               hpet = (struct hpet *) fix_to_virt(FIX_HPET_BASE);
-               timer = &hpet->hpet_timers[2];
-               for (i = 2; i < ntimer; timer++, i++)
-                       hd.hd_irq[i] = (timer->hpet_config &
-                                       Tn_INT_ROUTE_CNF_MASK) >>
-                               Tn_INT_ROUTE_CNF_SHIFT;
-
-       }
-
-       hpet_alloc(&hd);
-       return 0;
-}
-fs_initcall(late_hpet_init);
-#endif
-
-int hpet_timer_stop_set_go(unsigned long tick)
-{
-       unsigned int cfg;
-
-/*
- * Stop the timers and reset the main counter.
- */
-
-       cfg = hpet_readl(HPET_CFG);
-       cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
-       hpet_writel(cfg, HPET_CFG);
-       hpet_writel(0, HPET_COUNTER);
-       hpet_writel(0, HPET_COUNTER + 4);
-
-/*
- * Set up timer 0, as periodic with first interrupt to happen at hpet_tick,
- * and period also hpet_tick.
- */
-       if (hpet_use_timer) {
-               hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
-                   HPET_TN_32BIT, HPET_T0_CFG);
-               hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */
-               hpet_writel(hpet_tick, HPET_T0_CMP); /* period */
-               cfg |= HPET_CFG_LEGACY;
-       }
-/*
- * Go!
- */
-
-       cfg |= HPET_CFG_ENABLE;
-       hpet_writel(cfg, HPET_CFG);
-
-       return 0;
-}
-
-static cycle_t read_hpet(void)
-{
-       return (cycle_t)hpet_readl(HPET_COUNTER);
-}
-
-static cycle_t __vsyscall_fn vread_hpet(void)
-{
-       return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
-}
-
-struct clocksource clocksource_hpet = {
-       .name           = "hpet",
-       .rating         = 250,
-       .read           = read_hpet,
-       .mask           = (cycle_t)HPET_MASK,
-       .mult           = 0, /* set below */
-       .shift          = HPET_SHIFT,
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-       .vread          = vread_hpet,
-};
-
-int __init hpet_arch_init(void)
-{
-       unsigned int id;
-       u64 tmp;
-
-       if (!hpet_address)
-               return -1;
-       set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
-       __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
-
-/*
- * Read the period, compute tick and quotient.
- */
-
-       id = hpet_readl(HPET_ID);
-
-       if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER))
-               return -1;
-
-       hpet_period = hpet_readl(HPET_PERIOD);
-       if (hpet_period < 100000 || hpet_period > 100000000)
-               return -1;
-
-       hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period;
-
-       hpet_use_timer = (id & HPET_ID_LEGSUP);
-
-       /*
-        * hpet period is in femto seconds per cycle
-        * so we need to convert this to ns/cyc units
-        * aproximated by mult/2^shift
-        *
-        *  fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
-        *  fsec/cyc * 1ns/1000000fsec * 2^shift = mult
-        *  fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
-        *  (fsec/cyc << shift)/1000000 = mult
-        *  (hpet_period << shift)/FSEC_PER_NSEC = mult
-        */
-       tmp = (u64)hpet_period << HPET_SHIFT;
-       do_div(tmp, FSEC_PER_NSEC);
-       clocksource_hpet.mult = (u32)tmp;
-       clocksource_register(&clocksource_hpet);
-
-       return hpet_timer_stop_set_go(hpet_tick);
-}
-
-int hpet_reenable(void)
-{
-       return hpet_timer_stop_set_go(hpet_tick);
-}
-
-/*
- * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing
- * it to the HPET timer of known frequency.
- */
-
-#define TICK_COUNT 100000000
-#define SMI_THRESHOLD 50000
-#define MAX_TRIES  5
-
-/*
- * Some platforms take periodic SMI interrupts with 5ms duration. Make sure none
- * occurs between the reads of the hpet & TSC.
- */
-static void __init read_hpet_tsc(int *hpet, int *tsc)
-{
-       int tsc1, tsc2, hpet1, i;
-
-       for (i = 0; i < MAX_TRIES; i++) {
-               tsc1 = get_cycles_sync();
-               hpet1 = hpet_readl(HPET_COUNTER);
-               tsc2 = get_cycles_sync();
-               if ((tsc2 - tsc1) < SMI_THRESHOLD)
-                       break;
-       }
-       *hpet = hpet1;
-       *tsc = tsc2;
-}
-
-unsigned int __init hpet_calibrate_tsc(void)
-{
-       int tsc_start, hpet_start;
-       int tsc_now, hpet_now;
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       read_hpet_tsc(&hpet_start, &tsc_start);
-
-       do {
-               local_irq_disable();
-               read_hpet_tsc(&hpet_now, &tsc_now);
-               local_irq_restore(flags);
-       } while ((tsc_now - tsc_start) < TICK_COUNT &&
-               (hpet_now - hpet_start) < TICK_COUNT);
-
-       return (tsc_now - tsc_start) * 1000000000L
-               / ((hpet_now - hpet_start) * hpet_period / 1000);
-}
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET
- * is enabled, we support RTC interrupt functionality in software.
- * RTC has 3 kinds of interrupts:
- * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock
- *    is updated
- * 2) Alarm Interrupt - generate an interrupt at a specific time of day
- * 3) Periodic Interrupt - generate periodic interrupt, with frequencies
- *    2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2)
- * (1) and (2) above are implemented using polling at a frequency of
- * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt
- * overhead. (DEFAULT_RTC_INT_FREQ)
- * For (3), we use interrupts at 64Hz or user specified periodic
- * frequency, whichever is higher.
- */
-#include <linux/rtc.h>
-
-#define DEFAULT_RTC_INT_FREQ   64
-#define RTC_NUM_INTS           1
-
-static unsigned long UIE_on;
-static unsigned long prev_update_sec;
-
-static unsigned long AIE_on;
-static struct rtc_time alarm_time;
-
-static unsigned long PIE_on;
-static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ;
-static unsigned long PIE_count;
-
-static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */
-static unsigned int hpet_t1_cmp; /* cached comparator register */
-
-int is_hpet_enabled(void)
-{
-       return hpet_address != 0;
-}
-
-/*
- * Timer 1 for RTC, we do not use periodic interrupt feature,
- * even if HPET supports periodic interrupts on Timer 1.
- * The reason being, to set up a periodic interrupt in HPET, we need to
- * stop the main counter. And if we do that everytime someone diables/enables
- * RTC, we will have adverse effect on main kernel timer running on Timer 0.
- * So, for the time being, simulate the periodic interrupt in software.
- *
- * hpet_rtc_timer_init() is called for the first time and during subsequent
- * interuppts reinit happens through hpet_rtc_timer_reinit().
- */
-int hpet_rtc_timer_init(void)
-{
-       unsigned int cfg, cnt;
-       unsigned long flags;
-
-       if (!is_hpet_enabled())
-               return 0;
-       /*
-        * Set the counter 1 and enable the interrupts.
-        */
-       if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
-               hpet_rtc_int_freq = PIE_freq;
-       else
-               hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
-
-       local_irq_save(flags);
-
-       cnt = hpet_readl(HPET_COUNTER);
-       cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);
-       hpet_writel(cnt, HPET_T1_CMP);
-       hpet_t1_cmp = cnt;
-
-       cfg = hpet_readl(HPET_T1_CFG);
-       cfg &= ~HPET_TN_PERIODIC;
-       cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
-       hpet_writel(cfg, HPET_T1_CFG);
-
-       local_irq_restore(flags);
-
-       return 1;
-}
-
-static void hpet_rtc_timer_reinit(void)
-{
-       unsigned int cfg, cnt, ticks_per_int, lost_ints;
-
-       if (unlikely(!(PIE_on | AIE_on | UIE_on))) {
-               cfg = hpet_readl(HPET_T1_CFG);
-               cfg &= ~HPET_TN_ENABLE;
-               hpet_writel(cfg, HPET_T1_CFG);
-               return;
-       }
-
-       if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
-               hpet_rtc_int_freq = PIE_freq;
-       else
-               hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
-
-       /* It is more accurate to use the comparator value than current count.*/
-       ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq;
-       hpet_t1_cmp += ticks_per_int;
-       hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
-
-       /*
-        * If the interrupt handler was delayed too long, the write above tries
-        * to schedule the next interrupt in the past and the hardware would
-        * not interrupt until the counter had wrapped around.
-        * So we have to check that the comparator wasn't set to a past time.
-        */
-       cnt = hpet_readl(HPET_COUNTER);
-       if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) {
-               lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1;
-               /* Make sure that, even with the time needed to execute
-                * this code, the next scheduled interrupt has been moved
-                * back to the future: */
-               lost_ints++;
-
-               hpet_t1_cmp += lost_ints * ticks_per_int;
-               hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
-
-               if (PIE_on)
-                       PIE_count += lost_ints;
-
-               if (printk_ratelimit())
-                       printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
-                              hpet_rtc_int_freq);
-       }
-}
-
-/*
- * The functions below are called from rtc driver.
- * Return 0 if HPET is not being used.
- * Otherwise do the necessary changes and return 1.
- */
-int hpet_mask_rtc_irq_bit(unsigned long bit_mask)
-{
-       if (!is_hpet_enabled())
-               return 0;
-
-       if (bit_mask & RTC_UIE)
-               UIE_on = 0;
-       if (bit_mask & RTC_PIE)
-               PIE_on = 0;
-       if (bit_mask & RTC_AIE)
-               AIE_on = 0;
-
-       return 1;
-}
-
-int hpet_set_rtc_irq_bit(unsigned long bit_mask)
-{
-       int timer_init_reqd = 0;
-
-       if (!is_hpet_enabled())
-               return 0;
-
-       if (!(PIE_on | AIE_on | UIE_on))
-               timer_init_reqd = 1;
-
-       if (bit_mask & RTC_UIE) {
-               UIE_on = 1;
-       }
-       if (bit_mask & RTC_PIE) {
-               PIE_on = 1;
-               PIE_count = 0;
-       }
-       if (bit_mask & RTC_AIE) {
-               AIE_on = 1;
-       }
-
-       if (timer_init_reqd)
-               hpet_rtc_timer_init();
-
-       return 1;
-}
-
-int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec)
-{
-       if (!is_hpet_enabled())
-               return 0;
-
-       alarm_time.tm_hour = hrs;
-       alarm_time.tm_min = min;
-       alarm_time.tm_sec = sec;
-
-       return 1;
-}
-
-int hpet_set_periodic_freq(unsigned long freq)
-{
-       if (!is_hpet_enabled())
-               return 0;
-
-       PIE_freq = freq;
-       PIE_count = 0;
-
-       return 1;
-}
-
-int hpet_rtc_dropped_irq(void)
-{
-       if (!is_hpet_enabled())
-               return 0;
-
-       return 1;
-}
-
-irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
-{
-       struct rtc_time curr_time;
-       unsigned long rtc_int_flag = 0;
-       int call_rtc_interrupt = 0;
-
-       hpet_rtc_timer_reinit();
-
-       if (UIE_on | AIE_on) {
-               rtc_get_rtc_time(&curr_time);
-       }
-       if (UIE_on) {
-               if (curr_time.tm_sec != prev_update_sec) {
-                       /* Set update int info, call real rtc int routine */
-                       call_rtc_interrupt = 1;
-                       rtc_int_flag = RTC_UF;
-                       prev_update_sec = curr_time.tm_sec;
-               }
-       }
-       if (PIE_on) {
-               PIE_count++;
-               if (PIE_count >= hpet_rtc_int_freq/PIE_freq) {
-                       /* Set periodic int info, call real rtc int routine */
-                       call_rtc_interrupt = 1;
-                       rtc_int_flag |= RTC_PF;
-                       PIE_count = 0;
-               }
-       }
-       if (AIE_on) {
-               if ((curr_time.tm_sec == alarm_time.tm_sec) &&
-                   (curr_time.tm_min == alarm_time.tm_min) &&
-                   (curr_time.tm_hour == alarm_time.tm_hour)) {
-                       /* Set alarm int info, call real rtc int routine */
-                       call_rtc_interrupt = 1;
-                       rtc_int_flag |= RTC_AF;
-               }
-       }
-       if (call_rtc_interrupt) {
-               rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
-               rtc_interrupt(rtc_int_flag, dev_id);
-       }
-       return IRQ_HANDLED;
-}
-#endif
-
-static int __init nohpet_setup(char *s)
-{
-       nohpet = 1;
-       return 1;
-}
-
-__setup("nohpet", nohpet_setup);
similarity index 99%
rename from arch/x86/kernel/i8253_32.c
rename to arch/x86/kernel/i8253.c
index 6d839f2..ac15e4c 100644 (file)
@@ -13,7 +13,6 @@
 #include <asm/delay.h>
 #include <asm/i8253.h>
 #include <asm/io.h>
-#include <asm/timer.h>
 
 DEFINE_SPINLOCK(i8253_lock);
 EXPORT_SYMBOL(i8253_lock);
@@ -120,6 +119,7 @@ void __init setup_pit_timer(void)
        global_clock_event = &pit_clockevent;
 }
 
+#ifndef CONFIG_X86_64
 /*
  * Since the PIT overflows every tick, its not very useful
  * to just read by itself. So use jiffies to emulate a free
@@ -204,3 +204,5 @@ static int __init init_pit_clocksource(void)
        return clocksource_register(&clocksource_pit);
 }
 arch_initcall(init_pit_clocksource);
+
+#endif
index 0499cbe..679bb33 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/sysdev.h>
 #include <linux/bitops.h>
 
-#include <asm/8253pit.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/io.h>
index 948cae6..eb72976 100644 (file)
@@ -444,46 +444,6 @@ void __init init_ISA_irqs (void)
        }
 }
 
-static void setup_timer_hardware(void)
-{
-       outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
-       udelay(10);
-       outb_p(LATCH & 0xff , 0x40);    /* LSB */
-       udelay(10);
-       outb(LATCH >> 8 , 0x40);        /* MSB */
-}
-
-static int timer_resume(struct sys_device *dev)
-{
-       setup_timer_hardware();
-       return 0;
-}
-
-void i8254_timer_resume(void)
-{
-       setup_timer_hardware();
-}
-
-static struct sysdev_class timer_sysclass = {
-       set_kset_name("timer_pit"),
-       .resume         = timer_resume,
-};
-
-static struct sys_device device_timer = {
-       .id             = 0,
-       .cls            = &timer_sysclass,
-};
-
-static int __init init_timer_sysfs(void)
-{
-       int error = sysdev_class_register(&timer_sysclass);
-       if (!error)
-               error = sysdev_register(&device_timer);
-       return error;
-}
-
-device_initcall(init_timer_sysfs);
-
 void __init init_IRQ(void)
 {
        int i;
@@ -533,12 +493,6 @@ void __init init_IRQ(void)
        set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
        set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
 
-       /*
-        * Set the clock to HZ Hz, we already have a valid
-        * vector now:
-        */
-       setup_timer_hardware();
-
        if (!acpi_ioapic)
                setup_irq(2, &irq2);
 }
diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c
new file mode 100644 (file)
index 0000000..0ab680f
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT)
+ *
+ * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ * Copyright (C) 2007, Andres Salomon <dilinger@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * The MFGPTs are documented in AMD Geode CS5536 Companion Device Data Book.
+ */
+
+/*
+ * We are using the 32Khz input clock - its the only one that has the
+ * ranges we find desirable.  The following table lists the suitable
+ * divisors and the associated hz, minimum interval
+ * and the maximum interval:
+ *
+ *  Divisor   Hz      Min Delta (S) Max Delta (S)
+ *   1        32000     .0005          2.048
+ *   2        16000      .001          4.096
+ *   4         8000      .002          8.192
+ *   8         4000      .004         16.384
+ *   16        2000      .008         32.768
+ *   32        1000      .016         65.536
+ *   64         500      .032        131.072
+ *  128         250      .064        262.144
+ *  256         125      .128        524.288
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/geode.h>
+
+#define F_AVAIL    0x01
+
+static struct mfgpt_timer_t {
+       int flags;
+       struct module *owner;
+} mfgpt_timers[MFGPT_MAX_TIMERS];
+
+/* Selected from the table above */
+
+#define MFGPT_DIVISOR 16
+#define MFGPT_SCALE  4     /* divisor = 2^(scale) */
+#define MFGPT_HZ  (32000 / MFGPT_DIVISOR)
+#define MFGPT_PERIODIC (MFGPT_HZ / HZ)
+
+#ifdef CONFIG_GEODE_MFGPT_TIMER
+static int __init mfgpt_timer_setup(void);
+#else
+#define mfgpt_timer_setup() (0)
+#endif
+
+/* Allow for disabling of MFGPTs */
+static int disable;
+static int __init mfgpt_disable(char *s)
+{
+       disable = 1;
+       return 1;
+}
+__setup("nomfgpt", mfgpt_disable);
+
+/*
+ * Check whether any MFGPTs are available for the kernel to use.  In most
+ * cases, firmware that uses AMD's VSA code will claim all timers during
+ * bootup; we certainly don't want to take them if they're already in use.
+ * In other cases (such as with VSAless OpenFirmware), the system firmware
+ * leaves timers available for us to use.
+ */
+int __init geode_mfgpt_detect(void)
+{
+       int count = 0, i;
+       u16 val;
+
+       if (disable) {
+               printk(KERN_INFO "geode-mfgpt:  Skipping MFGPT setup\n");
+               return 0;
+       }
+
+       for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
+               val = geode_mfgpt_read(i, MFGPT_REG_SETUP);
+               if (!(val & MFGPT_SETUP_SETUP)) {
+                       mfgpt_timers[i].flags = F_AVAIL;
+                       count++;
+               }
+       }
+
+       /* set up clock event device, if desired */
+       i = mfgpt_timer_setup();
+
+       return count;
+}
+
+int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable)
+{
+       u32 msr, mask, value, dummy;
+       int shift = (cmp == MFGPT_CMP1) ? 0 : 8;
+
+       if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
+               return -EIO;
+
+       /*
+        * The register maps for these are described in sections 6.17.1.x of
+        * the AMD Geode CS5536 Companion Device Data Book.
+        */
+       switch (event) {
+       case MFGPT_EVENT_RESET:
+               /*
+                * XXX: According to the docs, we cannot reset timers above
+                * 6; that is, resets for 7 and 8 will be ignored.  Is this
+                * a problem?   -dilinger
+                */
+               msr = MFGPT_NR_MSR;
+               mask = 1 << (timer + 24);
+               break;
+
+       case MFGPT_EVENT_NMI:
+               msr = MFGPT_NR_MSR;
+               mask = 1 << (timer + shift);
+               break;
+
+       case MFGPT_EVENT_IRQ:
+               msr = MFGPT_IRQ_MSR;
+               mask = 1 << (timer + shift);
+               break;
+
+       default:
+               return -EIO;
+       }
+
+       rdmsr(msr, value, dummy);
+
+       if (enable)
+               value |= mask;
+       else
+               value &= ~mask;
+
+       wrmsr(msr, value, dummy);
+       return 0;
+}
+
+int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable)
+{
+       u32 val, dummy;
+       int offset;
+
+       if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
+               return -EIO;
+
+       if (geode_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable))
+               return -EIO;
+
+       rdmsr(MSR_PIC_ZSEL_LOW, val, dummy);
+
+       offset = (timer % 4) * 4;
+
+       val &= ~((0xF << offset) | (0xF << (offset + 16)));
+
+       if (enable) {
+               val |= (irq & 0x0F) << (offset);
+               val |= (irq & 0x0F) << (offset + 16);
+       }
+
+       wrmsr(MSR_PIC_ZSEL_LOW, val, dummy);
+       return 0;
+}
+
+static int mfgpt_get(int timer, struct module *owner)
+{
+       mfgpt_timers[timer].flags &= ~F_AVAIL;
+       mfgpt_timers[timer].owner = owner;
+       printk(KERN_INFO "geode-mfgpt:  Registered timer %d\n", timer);
+       return timer;
+}
+
+int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner)
+{
+       int i;
+
+       if (!geode_get_dev_base(GEODE_DEV_MFGPT))
+               return -ENODEV;
+       if (timer >= MFGPT_MAX_TIMERS)
+               return -EIO;
+
+       if (timer < 0) {
+               /* Try to find an available timer */
+               for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
+                       if (mfgpt_timers[i].flags & F_AVAIL)
+                               return mfgpt_get(i, owner);
+
+                       if (i == 5 && domain == MFGPT_DOMAIN_WORKING)
+                               break;
+               }
+       } else {
+               /* If they requested a specific timer, try to honor that */
+               if (mfgpt_timers[timer].flags & F_AVAIL)
+                       return mfgpt_get(timer, owner);
+       }
+
+       /* No timers available - too bad */
+       return -1;
+}
+
+
+#ifdef CONFIG_GEODE_MFGPT_TIMER
+
+/*
+ * The MFPGT timers on the CS5536 provide us with suitable timers to use
+ * as clock event sources - not as good as a HPET or APIC, but certainly
+ * better then the PIT.  This isn't a general purpose MFGPT driver, but
+ * a simplified one designed specifically to act as a clock event source.
+ * For full details about the MFGPT, please consult the CS5536 data sheet.
+ */
+
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+
+static unsigned int mfgpt_tick_mode = CLOCK_EVT_MODE_SHUTDOWN;
+static u16 mfgpt_event_clock;
+
+static int irq = 7;
+static int __init mfgpt_setup(char *str)
+{
+       get_option(&str, &irq);
+       return 1;
+}
+__setup("mfgpt_irq=", mfgpt_setup);
+
+static inline void mfgpt_disable_timer(u16 clock)
+{
+       u16 val = geode_mfgpt_read(clock, MFGPT_REG_SETUP);
+       geode_mfgpt_write(clock, MFGPT_REG_SETUP, val & ~MFGPT_SETUP_CNTEN);
+}
+
+static int mfgpt_next_event(unsigned long, struct clock_event_device *);
+static void mfgpt_set_mode(enum clock_event_mode, struct clock_event_device *);
+
+static struct clock_event_device mfgpt_clockevent = {
+       .name = "mfgpt-timer",
+       .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode = mfgpt_set_mode,
+       .set_next_event = mfgpt_next_event,
+       .rating = 250,
+       .cpumask = CPU_MASK_ALL,
+       .shift = 32
+};
+
+static inline void mfgpt_start_timer(u16 clock, u16 delta)
+{
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta);
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);
+
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
+                         MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
+}
+
+static void mfgpt_set_mode(enum clock_event_mode mode,
+                          struct clock_event_device *evt)
+{
+       mfgpt_disable_timer(mfgpt_event_clock);
+
+       if (mode == CLOCK_EVT_MODE_PERIODIC)
+               mfgpt_start_timer(mfgpt_event_clock, MFGPT_PERIODIC);
+
+       mfgpt_tick_mode = mode;
+}
+
+static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt)
+{
+       mfgpt_start_timer(mfgpt_event_clock, delta);
+       return 0;
+}
+
+/* Assume (foolishly?), that this interrupt was due to our tick */
+
+static irqreturn_t mfgpt_tick(int irq, void *dev_id)
+{
+       if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN)
+               return IRQ_HANDLED;
+
+       /* Turn off the clock */
+       mfgpt_disable_timer(mfgpt_event_clock);
+
+       /* Clear the counter */
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);
+
+       /* Restart the clock in periodic mode */
+
+       if (mfgpt_tick_mode == CLOCK_EVT_MODE_PERIODIC) {
+               geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
+                                 MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
+       }
+
+       mfgpt_clockevent.event_handler(&mfgpt_clockevent);
+       return IRQ_HANDLED;
+}
+
+static struct irqaction mfgptirq  = {
+       .handler = mfgpt_tick,
+       .flags = IRQF_DISABLED | IRQF_NOBALANCING,
+       .mask = CPU_MASK_NONE,
+       .name = "mfgpt-timer"
+};
+
+static int __init mfgpt_timer_setup(void)
+{
+       int timer, ret;
+       u16 val;
+
+       timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING,
+                       THIS_MODULE);
+       if (timer < 0) {
+               printk(KERN_ERR
+                      "mfgpt-timer:  Could not allocate a MFPGT timer\n");
+               return -ENODEV;
+       }
+
+       mfgpt_event_clock = timer;
+       /* Set the clock scale and enable the event mode for CMP2 */
+       val = MFGPT_SCALE | (3 << 8);
+
+       geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);
+
+       /* Set up the IRQ on the MFGPT side */
+       if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) {
+               printk(KERN_ERR "mfgpt-timer:  Could not set up IRQ %d\n", irq);
+               return -EIO;
+       }
+
+       /* And register it with the kernel */
+       ret = setup_irq(irq, &mfgptirq);
+
+       if (ret) {
+               printk(KERN_ERR
+                      "mfgpt-timer:  Unable to set up the interrupt.\n");
+               goto err;
+       }
+
+       /* Set up the clock event */
+       mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32);
+       mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF,
+                       &mfgpt_clockevent);
+       mfgpt_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE,
+                       &mfgpt_clockevent);
+
+       printk(KERN_INFO
+              "mfgpt-timer:  registering the MFGT timer as a clock event.\n");
+       clockevents_register_device(&mfgpt_clockevent);
+
+       return 0;
+
+err:
+       geode_mfgpt_release_irq(mfgpt_event_clock, MFGPT_CMP2, irq);
+       printk(KERN_ERR
+              "mfgpt-timer:  Unable to set up the MFGPT clock source\n");
+       return -EIO;
+}
+
+#endif
index c7227e2..95d3fc2 100644 (file)
@@ -353,7 +353,8 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
         * Take the local apic timer and PIT/HPET into account. We don't
         * know which one is active, when we have highres/dyntick on
         */
-       sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_cpu(cpu).irqs[0];
+       sum = per_cpu(irq_stat, cpu).apic_timer_irqs +
+               per_cpu(irq_stat, cpu).irq0_irqs;
 
        /* if the none of the timers isn't firing, this cpu isn't doing much */
        if (!touched && last_irq_sums[cpu] == sum) {
index 0ec6d2d..e60ac0d 100644 (file)
@@ -329,7 +329,7 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
                touched = 1;
        }
 
-       sum = read_pda(apic_timer_irqs);
+       sum = read_pda(apic_timer_irqs) + read_pda(irq0_irqs);
        if (__get_cpu_var(nmi_touch)) {
                __get_cpu_var(nmi_touch) = 0;
                touched = 1;
index 9895655..6f9dbbe 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
+#include <linux/tick.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -208,6 +209,8 @@ void cpu_idle (void)
                        if (__get_cpu_var(cpu_idle_state))
                                __get_cpu_var(cpu_idle_state) = 0;
 
+                       tick_nohz_stop_sched_tick();
+
                        rmb();
                        idle = pm_idle;
                        if (!idle)
@@ -228,6 +231,7 @@ void cpu_idle (void)
                        __exit_idle();
                }
 
+               tick_nohz_restart_sched_tick();
                preempt_enable_no_resched();
                schedule();
                preempt_disable();
index 6722469..d769e20 100644 (file)
@@ -4,6 +4,8 @@
 #include <linux/pci.h>
 #include <linux/irq.h>
 
+#include <asm/hpet.h>
+
 #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
 
 static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
@@ -47,3 +49,206 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,        PCI_DEVICE_ID_INTEL_E7320_MCH,  quir
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7525_MCH,  quirk_intel_irqbalance);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_E7520_MCH,  quirk_intel_irqbalance);
 #endif
+
+#if defined(CONFIG_HPET_TIMER)
+unsigned long force_hpet_address;
+
+static enum {
+       NONE_FORCE_HPET_RESUME,
+       OLD_ICH_FORCE_HPET_RESUME,
+       ICH_FORCE_HPET_RESUME
+} force_hpet_resume_type;
+
+static void __iomem *rcba_base;
+
+static void ich_force_hpet_resume(void)
+{
+       u32 val;
+
+       if (!force_hpet_address)
+               return;
+
+       if (rcba_base == NULL)
+               BUG();
+
+       /* read the Function Disable register, dword mode only */
+       val = readl(rcba_base + 0x3404);
+       if (!(val & 0x80)) {
+               /* HPET disabled in HPTC. Trying to enable */
+               writel(val | 0x80, rcba_base + 0x3404);
+       }
+
+       val = readl(rcba_base + 0x3404);
+       if (!(val & 0x80))
+               BUG();
+       else
+               printk(KERN_DEBUG "Force enabled HPET at resume\n");
+
+       return;
+}
+
+static void ich_force_enable_hpet(struct pci_dev *dev)
+{
+       u32 val;
+       u32 uninitialized_var(rcba);
+       int err = 0;
+
+       if (hpet_address || force_hpet_address)
+               return;
+
+       pci_read_config_dword(dev, 0xF0, &rcba);
+       rcba &= 0xFFFFC000;
+       if (rcba == 0) {
+               printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n");
+               return;
+       }
+
+       /* use bits 31:14, 16 kB aligned */
+       rcba_base = ioremap_nocache(rcba, 0x4000);
+       if (rcba_base == NULL) {
+               printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n");
+               return;
+       }
+
+       /* read the Function Disable register, dword mode only */
+       val = readl(rcba_base + 0x3404);
+
+       if (val & 0x80) {
+               /* HPET is enabled in HPTC. Just not reported by BIOS */
+               val = val & 0x3;
+               force_hpet_address = 0xFED00000 | (val << 12);
+               printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+                              force_hpet_address);
+               iounmap(rcba_base);
+               return;
+       }
+
+       /* HPET disabled in HPTC. Trying to enable */
+       writel(val | 0x80, rcba_base + 0x3404);
+
+       val = readl(rcba_base + 0x3404);
+       if (!(val & 0x80)) {
+               err = 1;
+       } else {
+               val = val & 0x3;
+               force_hpet_address = 0xFED00000 | (val << 12);
+       }
+
+       if (err) {
+               force_hpet_address = 0;
+               iounmap(rcba_base);
+               printk(KERN_DEBUG "Failed to force enable HPET\n");
+       } else {
+               force_hpet_resume_type = ICH_FORCE_HPET_RESUME;
+               printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+                              force_hpet_address);
+       }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1,
+                         ich_force_enable_hpet);
+
+
+static struct pci_dev *cached_dev;
+
+static void old_ich_force_hpet_resume(void)
+{
+       u32 val;
+       u32 uninitialized_var(gen_cntl);
+
+       if (!force_hpet_address || !cached_dev)
+               return;
+
+       pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
+       gen_cntl &= (~(0x7 << 15));
+       gen_cntl |= (0x4 << 15);
+
+       pci_write_config_dword(cached_dev, 0xD0, gen_cntl);
+       pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
+       val = gen_cntl >> 15;
+       val &= 0x7;
+       if (val == 0x4)
+               printk(KERN_DEBUG "Force enabled HPET at resume\n");
+       else
+               BUG();
+}
+
+static void old_ich_force_enable_hpet(struct pci_dev *dev)
+{
+       u32 val;
+       u32 uninitialized_var(gen_cntl);
+
+       if (hpet_address || force_hpet_address)
+               return;
+
+       pci_read_config_dword(dev, 0xD0, &gen_cntl);
+       /*
+        * Bit 17 is HPET enable bit.
+        * Bit 16:15 control the HPET base address.
+        */
+       val = gen_cntl >> 15;
+       val &= 0x7;
+       if (val & 0x4) {
+               val &= 0x3;
+               force_hpet_address = 0xFED00000 | (val << 12);
+               printk(KERN_DEBUG "HPET at base address 0x%lx\n",
+                              force_hpet_address);
+               return;
+       }
+
+       /*
+        * HPET is disabled. Trying enabling at FED00000 and check
+        * whether it sticks
+        */
+       gen_cntl &= (~(0x7 << 15));
+       gen_cntl |= (0x4 << 15);
+       pci_write_config_dword(dev, 0xD0, gen_cntl);
+
+       pci_read_config_dword(dev, 0xD0, &gen_cntl);
+
+       val = gen_cntl >> 15;
+       val &= 0x7;
+       if (val & 0x4) {
+               /* HPET is enabled in HPTC. Just not reported by BIOS */
+               val &= 0x3;
+               force_hpet_address = 0xFED00000 | (val << 12);
+               printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+                              force_hpet_address);
+               cached_dev = dev;
+               force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME;
+               return;
+       }
+
+       printk(KERN_DEBUG "Failed to force enable HPET\n");
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
+                         old_ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_12,
+                         old_ich_force_enable_hpet);
+
+void force_hpet_resume(void)
+{
+       switch (force_hpet_resume_type) {
+           case ICH_FORCE_HPET_RESUME:
+               return ich_force_hpet_resume();
+
+           case OLD_ICH_FORCE_HPET_RESUME:
+               return old_ich_force_hpet_resume();
+
+           default:
+               break;
+       }
+}
+
+#endif
index af838f6..32054bf 100644 (file)
@@ -546,6 +546,37 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
 #endif
 }
 
+#define ENABLE_C1E_MASK                0x18000000
+#define CPUID_PROCESSOR_SIGNATURE      1
+#define CPUID_XFAM             0x0ff00000
+#define CPUID_XFAM_K8          0x00000000
+#define CPUID_XFAM_10H         0x00100000
+#define CPUID_XFAM_11H         0x00200000
+#define CPUID_XMOD             0x000f0000
+#define CPUID_XMOD_REV_F       0x00040000
+
+/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
+static __cpuinit int amd_apic_timer_broken(void)
+{
+       u32 lo, hi;
+       u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
+       switch (eax & CPUID_XFAM) {
+       case CPUID_XFAM_K8:
+               if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
+                       break;
+       case CPUID_XFAM_10H:
+       case CPUID_XFAM_11H:
+               rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
+               if (lo & ENABLE_C1E_MASK)
+                       return 1;
+               break;
+       default:
+               /* err on the side of caution */
+               return 1;
+       }
+       return 0;
+}
+
 static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 {
        unsigned level;
@@ -617,6 +648,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
        /* Family 10 doesn't support C states in MWAIT so don't use it */
        if (c->x86 == 0x10 && !force_mwait)
                clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
+
+       if (amd_apic_timer_broken())
+               disable_apic_timer = 1;
 }
 
 static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
index 32f5078..57ccf7c 100644 (file)
@@ -223,8 +223,6 @@ void __cpuinit smp_callin(void)
        local_irq_disable();
        Dprintk("Stack at about %p\n",&cpuid);
 
-       disable_APIC_timer();
-
        /*
         * Save our processor parameters
         */
@@ -348,8 +346,6 @@ void __cpuinit start_secondary(void)
                enable_8259A_irq(0);
        }
 
-       enable_APIC_timer();
-
        /*
         * The sibling maps must be set before turing the online map on for
         * this cpu
index 19a6c67..56dadfc 100644 (file)
@@ -157,6 +157,9 @@ EXPORT_SYMBOL(profile_pc);
  */
 irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
+       /* Keep nmi watchdog up to date */
+       per_cpu(irq_stat, smp_processor_id()).irq0_irqs++;
+
 #ifdef CONFIG_X86_IO_APIC
        if (timer_ack) {
                /*
index 6d48a4e..e0134d6 100644 (file)
 #include <linux/cpu.h>
 #include <linux/kallsyms.h>
 #include <linux/acpi.h>
+#include <linux/clockchips.h>
+
 #ifdef CONFIG_ACPI
 #include <acpi/achware.h>      /* for PM timer frequency */
 #include <acpi/acpi_bus.h>
 #endif
-#include <asm/8253pit.h>
 #include <asm/i8253.h>
 #include <asm/pgtable.h>
 #include <asm/vsyscall.h>
 #include <asm/nmi.h>
 #include <asm/vgtod.h>
 
-static char *timename = NULL;
-
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
-DEFINE_SPINLOCK(i8253_lock);
-EXPORT_SYMBOL(i8253_lock);
 
 volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
 
@@ -153,45 +150,12 @@ int update_persistent_clock(struct timespec now)
        return set_rtc_mmss(now.tv_sec);
 }
 
-void main_timer_handler(void)
+static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
 {
-/*
- * Here we are in the timer irq handler. We have irqs locally disabled (so we
- * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
- * on the other CPU, so we need a lock. We also need to lock the vsyscall
- * variables, because both do_timer() and us change them -arca+vojtech
- */
-
-       write_seqlock(&xtime_lock);
+       add_pda(irq0_irqs, 1);
 
-/*
- * Do the timer stuff.
- */
-
-       do_timer(1);
-#ifndef CONFIG_SMP
-       update_process_times(user_mode(get_irq_regs()));
-#endif
+       global_clock_event->event_handler(global_clock_event);
 
-/*
- * In the SMP case we use the local APIC timer interrupt to do the profiling,
- * except when we simulate SMP mode on a uniprocessor system, in that case we
- * have to call the local interrupt handler.
- */
-
-       if (!using_apic_timer)
-               smp_local_timer_interrupt();
-
-       write_sequnlock(&xtime_lock);
-}
-
-static irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
-       if (apic_runs_main_timer > 1)
-               return IRQ_HANDLED;
-       main_timer_handler();
-       if (using_apic_timer)
-               smp_send_timer_broadcast_ipi();
        return IRQ_HANDLED;
 }
 
@@ -292,97 +256,21 @@ static unsigned int __init tsc_calibrate_cpu_khz(void)
        return pmc_now * tsc_khz / (tsc_now - tsc_start);
 }
 
-/*
- * pit_calibrate_tsc() uses the speaker output (channel 2) of
- * the PIT. This is better than using the timer interrupt output,
- * because we can read the value of the speaker with just one inb(),
- * where we need three i/o operations for the interrupt channel.
- * We count how many ticks the TSC does in 50 ms.
- */
-
-static unsigned int __init pit_calibrate_tsc(void)
-{
-       unsigned long start, end;
-       unsigned long flags;
-
-       spin_lock_irqsave(&i8253_lock, flags);
-
-       outb((inb(0x61) & ~0x02) | 0x01, 0x61);
-
-       outb(0xb0, 0x43);
-       outb((PIT_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
-       outb((PIT_TICK_RATE / (1000 / 50)) >> 8, 0x42);
-       start = get_cycles_sync();
-       while ((inb(0x61) & 0x20) == 0);
-       end = get_cycles_sync();
-
-       spin_unlock_irqrestore(&i8253_lock, flags);
-
-       return (end - start) / 50;
-}
-
-#define PIT_MODE 0x43
-#define PIT_CH0  0x40
-
-static void __pit_init(int val, u8 mode)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&i8253_lock, flags);
-       outb_p(mode, PIT_MODE);
-       outb_p(val & 0xff, PIT_CH0);    /* LSB */
-       outb_p(val >> 8, PIT_CH0);      /* MSB */
-       spin_unlock_irqrestore(&i8253_lock, flags);
-}
-
-void __init pit_init(void)
-{
-       __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
-}
-
-void pit_stop_interrupt(void)
-{
-       __pit_init(0, 0x30); /* mode 0 */
-}
-
-void stop_timer_interrupt(void)
-{
-       char *name;
-       if (hpet_address) {
-               name = "HPET";
-               hpet_timer_stop_set_go(0);
-       } else {
-               name = "PIT";
-               pit_stop_interrupt();
-       }
-       printk(KERN_INFO "timer: %s interrupt stopped.\n", name);
-}
-
 static struct irqaction irq0 = {
-       .handler        = timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_IRQPOLL,
+       .handler        = timer_event_interrupt,
+       .flags          = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
        .mask           = CPU_MASK_NONE,
        .name           = "timer"
 };
 
 void __init time_init(void)
 {
-       if (nohpet)
-               hpet_address = 0;
+       if (!hpet_enable())
+               setup_pit_timer();
 
-       if (hpet_arch_init())
-               hpet_address = 0;
+       setup_irq(0, &irq0);
 
-       if (hpet_use_timer) {
-               /* set tick_nsec to use the proper rate for HPET */
-               tick_nsec = TICK_NSEC_HPET;
-               tsc_khz = hpet_calibrate_tsc();
-               timename = "HPET";
-       } else {
-               pit_init();
-               tsc_khz = pit_calibrate_tsc();
-               timename = "PIT";
-       }
+       tsc_calibrate();
 
        cpu_khz = tsc_khz;
        if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
@@ -398,50 +286,7 @@ void __init time_init(void)
        else
                vgetcpu_mode = VGETCPU_LSL;
 
-       set_cyc2ns_scale(tsc_khz);
        printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
                cpu_khz / 1000, cpu_khz % 1000);
        init_tsc_clocksource();
-
-       setup_irq(0, &irq0);
-}
-
-/*
- * sysfs support for the timer.
- */
-
-static int timer_suspend(struct sys_device *dev, pm_message_t state)
-{
-       return 0;
-}
-
-static int timer_resume(struct sys_device *dev)
-{
-       if (hpet_address)
-               hpet_reenable();
-       else
-               i8254_timer_resume();
-       return 0;
 }
-
-static struct sysdev_class timer_sysclass = {
-       .resume = timer_resume,
-       .suspend = timer_suspend,
-       set_kset_name("timer"),
-};
-
-/* XXX this sysfs stuff should probably go elsewhere later -john */
-static struct sys_device device_timer = {
-       .id     = 0,
-       .cls    = &timer_sysclass,
-};
-
-static int time_init_device(void)
-{
-       int error = sysdev_class_register(&timer_sysclass);
-       if (!error)
-               error = sysdev_register(&device_timer);
-       return error;
-}
-
-device_initcall(time_init_device);
index 2a59bde..9f22e54 100644 (file)
@@ -6,7 +6,9 @@
 #include <linux/time.h>
 #include <linux/acpi.h>
 #include <linux/cpufreq.h>
+#include <linux/acpi_pmtmr.h>
 
+#include <asm/hpet.h>
 #include <asm/timex.h>
 
 static int notsc __initdata = 0;
@@ -18,7 +20,7 @@ EXPORT_SYMBOL(tsc_khz);
 
 static unsigned int cyc2ns_scale __read_mostly;
 
-void set_cyc2ns_scale(unsigned long khz)
+static inline void set_cyc2ns_scale(unsigned long khz)
 {
        cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / khz;
 }
@@ -118,6 +120,95 @@ core_initcall(cpufreq_tsc);
 
 #endif
 
+#define MAX_RETRIES    5
+#define SMI_TRESHOLD   50000
+
+/*
+ * Read TSC and the reference counters. Take care of SMI disturbance
+ */
+static unsigned long __init tsc_read_refs(unsigned long *pm,
+                                         unsigned long *hpet)
+{
+       unsigned long t1, t2;
+       int i;
+
+       for (i = 0; i < MAX_RETRIES; i++) {
+               t1 = get_cycles_sync();
+               if (hpet)
+                       *hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF;
+               else
+                       *pm = acpi_pm_read_early();
+               t2 = get_cycles_sync();
+               if ((t2 - t1) < SMI_TRESHOLD)
+                       return t2;
+       }
+       return ULONG_MAX;
+}
+
+/**
+ * tsc_calibrate - calibrate the tsc on boot
+ */
+void __init tsc_calibrate(void)
+{
+       unsigned long flags, tsc1, tsc2, tr1, tr2, pm1, pm2, hpet1, hpet2;
+       int hpet = is_hpet_enabled();
+
+       local_irq_save(flags);
+
+       tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL);
+
+       outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+       outb(0xb0, 0x43);
+       outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
+       outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
+       tr1 = get_cycles_sync();
+       while ((inb(0x61) & 0x20) == 0);
+       tr2 = get_cycles_sync();
+
+       tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL);
+
+       local_irq_restore(flags);
+
+       /*
+        * Preset the result with the raw and inaccurate PIT
+        * calibration value
+        */
+       tsc_khz = (tr2 - tr1) / 50;
+
+       /* hpet or pmtimer available ? */
+       if (!hpet && !pm1 && !pm2) {
+               printk(KERN_INFO "TSC calibrated against PIT\n");
+               return;
+       }
+
+       /* Check, whether the sampling was disturbed by an SMI */
+       if (tsc1 == ULONG_MAX || tsc2 == ULONG_MAX) {
+               printk(KERN_WARNING "TSC calibration disturbed by SMI, "
+                      "using PIT calibration result\n");
+               return;
+       }
+
+       tsc2 = (tsc2 - tsc1) * 1000000L;
+
+       if (hpet) {
+               printk(KERN_INFO "TSC calibrated against HPET\n");
+               if (hpet2 < hpet1)
+                       hpet2 += 0x100000000;
+               hpet2 -= hpet1;
+               tsc1 = (hpet2 * hpet_readl(HPET_PERIOD)) / 1000000;
+       } else {
+               printk(KERN_INFO "TSC calibrated against PM_TIMER\n");
+               if (pm2 < pm1)
+                       pm2 += ACPI_PM_OVRRUN;
+               pm2 -= pm1;
+               tsc1 = (pm2 * 1000000000) / PMTMR_TICKS_PER_SEC;
+       }
+
+       tsc_khz = tsc2 / tsc1;
+       set_cyc2ns_scale(tsc_khz);
+}
+
 /*
  * Make an educated guess if the TSC is trustworthy and synchronized
  * over all CPUs.
index b1b98e6..eb80f5a 100644 (file)
@@ -36,6 +36,18 @@ config GENERIC_CMOS_UPDATE
        bool
        default y
 
+config CLOCKSOURCE_WATCHDOG
+       bool
+       default y
+
+config GENERIC_CLOCKEVENTS
+       bool
+       default y
+
+config GENERIC_CLOCKEVENTS_BROADCAST
+       bool
+       default y
+
 config ZONE_DMA32
        bool
        default y
@@ -130,6 +142,8 @@ source "init/Kconfig"
 
 menu "Processor type and features"
 
+source "kernel/time/Kconfig"
+
 choice
        prompt "Subarchitecture Type"
        default X86_PC
index 2484e0e..e108956 100644 (file)
@@ -62,6 +62,10 @@ config BLK_DEV_BSG
        protocols (e.g. Task Management Functions and SMP in Serial
        Attached SCSI).
 
+config BLOCK_COMPAT
+       bool
+       default y
+
 endif # BLOCK
 
 source block/Kconfig.iosched
index 3cfe7ce..8261081 100644 (file)
@@ -11,4 +11,4 @@ obj-$(CONFIG_IOSCHED_DEADLINE)        += deadline-iosched.o
 obj-$(CONFIG_IOSCHED_CFQ)      += cfq-iosched.o
 
 obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
-obj-$(CONFIG_COMPAT)           += compat_ioctl.o
+obj-$(CONFIG_BLOCK_COMPAT)     += compat_ioctl.o
index 1e8287b..1f6fb38 100644 (file)
@@ -276,21 +276,12 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr,
 
 static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
 {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
        unsigned long reason;
 
        reason = pr->power.timer_broadcast_on_state < INT_MAX ?
                CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
 
        clockevents_notify(reason, &pr->id);
-#else
-       cpumask_t mask = cpumask_of_cpu(pr->id);
-
-       if (pr->power.timer_broadcast_on_state < INT_MAX)
-               on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
-       else
-               on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
-#endif
 }
 
 /* Power(C) State timer broadcast control */
@@ -298,8 +289,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
                                       struct acpi_processor_cx *cx,
                                       int broadcast)
 {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-
        int state = cx - pr->power.states;
 
        if (state >= pr->power.timer_broadcast_on_state) {
@@ -309,7 +298,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
                        CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
                clockevents_notify(reason, &pr->id);
        }
-#endif
 }
 
 #else
index 4245b7f..ca4d7f0 100644 (file)
@@ -361,8 +361,7 @@ config BLK_DEV_RAM_SIZE
        default "4096"
        help
          The default value is 4096 kilobytes. Only change this if you know
-         what are you doing. If you are using IBM S/390, then set this to
-         8192.
+         what are you doing.
 
 config BLK_DEV_RAM_BLOCKSIZE
        int "Default RAM disk block size (bytes)"
index 993fa7b..721f86f 100644 (file)
@@ -56,10 +56,6 @@ config CPU_FREQ_STAT_DETAILS
 
          If in doubt, say N.
 
-# Note that it is not currently possible to set the other governors (such as ondemand)
-# as the default, since if they fail to initialise, cpufreq will be
-# left in an undefined state.
-
 choice
        prompt "Default CPUFreq governor"
        default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
@@ -85,6 +81,29 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE
          program shall be able to set the CPU dynamically without having
          to enable the userspace governor manually.
 
+config CPU_FREQ_DEFAULT_GOV_ONDEMAND
+       bool "ondemand"
+       select CPU_FREQ_GOV_ONDEMAND
+       select CPU_FREQ_GOV_PERFORMANCE
+       help
+         Use the CPUFreq governor 'ondemand' as default. This allows
+         you to get a full dynamic frequency capable system by simply
+         loading your cpufreq low-level hardware driver.
+         Be aware that not all cpufreq drivers support the ondemand
+         governor. If unsure have a look at the help section of the
+         driver. Fallback governor will be the performance governor.
+
+config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+       bool "conservative"
+       select CPU_FREQ_GOV_CONSERVATIVE
+       select CPU_FREQ_GOV_PERFORMANCE
+       help
+         Use the CPUFreq governor 'conservative' as default. This allows
+         you to get a full dynamic frequency capable system by simply
+         loading your cpufreq low-level hardware driver.
+         Be aware that not all cpufreq drivers support the conservative
+         governor. If unsure have a look at the help section of the
+         driver. Fallback governor will be the performance governor.
 endchoice
 
 config CPU_FREQ_GOV_PERFORMANCE
index 2ce3de5..5e626b1 100644 (file)
@@ -763,6 +763,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
        init_completion(&policy->kobj_unregister);
        INIT_WORK(&policy->update, handle_update);
 
+       /* Set governor before ->init, so that driver could check it */
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        /* call driver. From then on the cpufreq must be able
         * to accept all calls to ->verify and ->setpolicy for this CPU
         */
@@ -1109,12 +1111,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
        unsigned int ret_freq = 0;
 
        if (policy) {
-               if (unlikely(lock_policy_rwsem_read(cpu)))
-                       return ret_freq;
-
                ret_freq = policy->cur;
-
-               unlock_policy_rwsem_read(cpu);
                cpufreq_cpu_put(policy);
        }
 
@@ -1483,6 +1480,31 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
 {
        int ret;
 
+       /* Only must be defined when default governor is known to have latency
+          restrictions, like e.g. conservative or ondemand.
+          That this is the case is already ensured in Kconfig
+       */
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
+       struct cpufreq_governor *gov = &cpufreq_gov_performance;
+#else
+       struct cpufreq_governor *gov = NULL;
+#endif
+
+       if (policy->governor->max_transition_latency &&
+           policy->cpuinfo.transition_latency >
+           policy->governor->max_transition_latency) {
+               if (!gov)
+                       return -EINVAL;
+               else {
+                       printk(KERN_WARNING "%s governor failed, too long"
+                              " transition latency of HW, fallback"
+                              " to %s governor\n",
+                              policy->governor->name,
+                              gov->name);
+                       policy->governor = gov;
+               }
+       }
+
        if (!try_module_get(policy->governor->owner))
                return -EINVAL;
 
@@ -1703,7 +1725,7 @@ int cpufreq_update_policy(unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
 
-static int cpufreq_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
index 26f440c..4bd33ce 100644 (file)
@@ -58,7 +58,7 @@ static unsigned int                           def_sampling_rate;
 #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER   (1000)
 #define DEF_SAMPLING_DOWN_FACTOR               (1)
 #define MAX_SAMPLING_DOWN_FACTOR               (10)
-#define TRANSITION_LATENCY_LIMIT               (10 * 1000)
+#define TRANSITION_LATENCY_LIMIT               (10 * 1000 * 1000)
 
 static void do_dbs_timer(struct work_struct *work);
 
@@ -466,9 +466,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                    (!policy->cur))
                        return -EINVAL;
 
-               if (policy->cpuinfo.transition_latency >
-                               (TRANSITION_LATENCY_LIMIT * 1000))
-                       return -EINVAL;
                if (this_dbs_info->enable) /* Already enabled */
                        break;
                 
@@ -551,15 +548,17 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
        return 0;
 }
 
-static struct cpufreq_governor cpufreq_gov_dbs = {
-       .name           = "conservative",
-       .governor       = cpufreq_governor_dbs,
-       .owner          = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_conservative = {
+       .name                   = "conservative",
+       .governor               = cpufreq_governor_dbs,
+       .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+       .owner                  = THIS_MODULE,
 };
+EXPORT_SYMBOL(cpufreq_gov_conservative);
 
 static int __init cpufreq_gov_dbs_init(void)
 {
-       return cpufreq_register_governor(&cpufreq_gov_dbs);
+       return cpufreq_register_governor(&cpufreq_gov_conservative);
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
@@ -567,7 +566,7 @@ static void __exit cpufreq_gov_dbs_exit(void)
        /* Make sure that the scheduled work is indeed not running */
        flush_scheduled_work();
 
-       cpufreq_unregister_governor(&cpufreq_gov_dbs);
+       cpufreq_unregister_governor(&cpufreq_gov_conservative);
 }
 
 
index e794527..369f445 100644 (file)
@@ -47,7 +47,7 @@ static unsigned int def_sampling_rate;
                        (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
 #define MAX_SAMPLING_RATE                      (500 * def_sampling_rate)
 #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER   (1000)
-#define TRANSITION_LATENCY_LIMIT               (10 * 1000)
+#define TRANSITION_LATENCY_LIMIT               (10 * 1000 * 1000)
 
 static void do_dbs_timer(struct work_struct *work);
 
@@ -508,12 +508,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                if ((!cpu_online(cpu)) || (!policy->cur))
                        return -EINVAL;
 
-               if (policy->cpuinfo.transition_latency >
-                               (TRANSITION_LATENCY_LIMIT * 1000)) {
-                       printk(KERN_WARNING "ondemand governor failed to load "
-                              "due to too long transition latency\n");
-                       return -EINVAL;
-               }
                if (this_dbs_info->enable) /* Already enabled */
                        break;
 
@@ -585,11 +579,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
        return 0;
 }
 
-static struct cpufreq_governor cpufreq_gov_dbs = {
-       .name = "ondemand",
-       .governor = cpufreq_governor_dbs,
-       .owner = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_ondemand = {
+       .name                   = "ondemand",
+       .governor               = cpufreq_governor_dbs,
+       .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+       .owner                  = THIS_MODULE,
 };
+EXPORT_SYMBOL(cpufreq_gov_ondemand);
 
 static int __init cpufreq_gov_dbs_init(void)
 {
@@ -598,12 +594,12 @@ static int __init cpufreq_gov_dbs_init(void)
                printk(KERN_ERR "Creation of kondemand failed\n");
                return -EFAULT;
        }
-       return cpufreq_register_governor(&cpufreq_gov_dbs);
+       return cpufreq_register_governor(&cpufreq_gov_ondemand);
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
 {
-       cpufreq_unregister_governor(&cpufreq_gov_dbs);
+       cpufreq_unregister_governor(&cpufreq_gov_ondemand);
        destroy_workqueue(kondemand_wq);
 }
 
index 917b9ba..8a45d0f 100644 (file)
@@ -164,8 +164,7 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
        return -1;
 }
 
-static void
-cpufreq_stats_free_table (unsigned int cpu)
+static void __cpuexit cpufreq_stats_free_table(unsigned int cpu)
 {
        struct cpufreq_stats *stat = cpufreq_stats_table[cpu];
        struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
@@ -305,8 +304,9 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
        return 0;
 }
 
-static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
-                                       unsigned long action, void *hcpu)
+static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
+                                              unsigned long action,
+                                              void *hcpu)
 {
        unsigned int cpu = (unsigned long)hcpu;
 
@@ -323,7 +323,7 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpufreq_stat_cpu_notifier =
+static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata =
 {
        .notifier_call = cpufreq_stat_cpu_callback,
 };
@@ -356,8 +356,7 @@ __init cpufreq_stats_init(void)
 
        register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
        for_each_online_cpu(cpu) {
-               cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
-                               CPU_ONLINE, (void *)(long)cpu);
+               cpufreq_update_policy(cpu);
        }
        return 0;
 }
@@ -372,13 +371,12 @@ __exit cpufreq_stats_exit(void)
                        CPUFREQ_TRANSITION_NOTIFIER);
        unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
        for_each_online_cpu(cpu) {
-               cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
-                                               CPU_DEAD, (void *)(long)cpu);
+               cpufreq_stats_free_table(cpu);
        }
 }
 
 MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
-MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats"
+MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats "
                                "through sysfs filesystem");
 MODULE_LICENSE ("GPL");
 
index e1a4402..c19f77f 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
-#include <asm/8253pit.h>
 #include <asm/io.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
@@ -29,6 +28,7 @@ MODULE_ALIAS("platform:pcspkr");
 /* Use the global PIT lock ! */
 #include <asm/i8253.h>
 #else
+#include <asm/8253pit.h>
 static DEFINE_SPINLOCK(i8253_lock);
 #endif
 
index b04a178..f8b7978 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/isapnp.h>
 #include <linux/interrupt.h>
 
-extern const char *CardType[];
 static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
 
 #define  AVM_FRITZ_PCI         1
@@ -726,100 +725,15 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_avm __devinitdata = NULL;
-#endif
-#ifdef __ISAPNP__
-static struct pnp_card *pnp_avm_c __devinitdata = NULL;
-#endif
-
-int __devinit
-setup_avm_pcipnp(struct IsdnCard *card)
+static int __devinit avm_setup_rest(struct IsdnCardState *cs)
 {
        u_int val, ver;
-       struct IsdnCardState *cs = card->cs;
-       char tmp[64];
 
-       strcpy(tmp, avm_pci_rev);
-       printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
-       if (cs->typ != ISDN_CTYPE_FRITZPCI)
-               return (0);
-       if (card->para[1]) {
-               /* old manual method */
-               cs->hw.avm.cfg_reg = card->para[1];
-               cs->irq = card->para[0];
-               cs->subtyp = AVM_FRITZ_PNP;
-               goto ready;
-       }
-#ifdef __ISAPNP__
-       if (isapnp_present()) {
-               struct pnp_dev *pnp_avm_d = NULL;
-               if ((pnp_avm_c = pnp_find_card(
-                       ISAPNP_VENDOR('A', 'V', 'M'),
-                       ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
-                       if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
-                               ISAPNP_VENDOR('A', 'V', 'M'),
-                               ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
-                               int err;
-
-                               pnp_disable_dev(pnp_avm_d);
-                               err = pnp_activate_dev(pnp_avm_d);
-                               if (err<0) {
-                                       printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-                                               __FUNCTION__, err);
-                                       return(0);
-                               }
-                               cs->hw.avm.cfg_reg =
-                                       pnp_port_start(pnp_avm_d, 0);
-                               cs->irq = pnp_irq(pnp_avm_d, 0);
-                               if (!cs->irq) {
-                                       printk(KERN_ERR "FritzPnP:No IRQ\n");
-                                       return(0);
-                               }
-                               if (!cs->hw.avm.cfg_reg) {
-                                       printk(KERN_ERR "FritzPnP:No IO address\n");
-                                       return(0);
-                               }
-                               cs->subtyp = AVM_FRITZ_PNP;
-                               goto ready;
-                       }
-               }
-       } else {
-               printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
-       }
-#endif
-#ifdef CONFIG_PCI
-       if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
-               PCI_DEVICE_ID_AVM_A1,  dev_avm))) {
-               if (pci_enable_device(dev_avm))
-                       return(0);
-               cs->irq = dev_avm->irq;
-               if (!cs->irq) {
-                       printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
-                       return(0);
-               }
-               cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
-               if (!cs->hw.avm.cfg_reg) {
-                       printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
-                       return(0);
-               }
-               cs->subtyp = AVM_FRITZ_PCI;
-       } else {
-               printk(KERN_WARNING "FritzPCI: No PCI card found\n");
-               return(0);
-       }
-       cs->irq_flags |= IRQF_SHARED;
-#else
-       printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
-       return (0);
-#endif /* CONFIG_PCI */
-ready:
        cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
        if (!request_region(cs->hw.avm.cfg_reg, 32,
                (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
                printk(KERN_WARNING
-                      "HiSax: %s config port %x-%x already in use\n",
-                      CardType[card->typ],
+                      "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n",
                       cs->hw.avm.cfg_reg,
                       cs->hw.avm.cfg_reg + 31);
                return (0);
@@ -860,3 +774,137 @@ ready:
        ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
        return (1);
 }
+
+#ifndef __ISAPNP__
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+       return(1);      /* no-op: success */
+}
+
+#else
+
+static struct pnp_card *pnp_avm_c __devinitdata = NULL;
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+       struct pnp_dev *pnp_avm_d = NULL;
+
+       if (!isapnp_present())
+               return(1);      /* no-op: success */
+
+       if ((pnp_avm_c = pnp_find_card(
+               ISAPNP_VENDOR('A', 'V', 'M'),
+               ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
+               if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
+                       ISAPNP_VENDOR('A', 'V', 'M'),
+                       ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
+                       int err;
+
+                       pnp_disable_dev(pnp_avm_d);
+                       err = pnp_activate_dev(pnp_avm_d);
+                       if (err<0) {
+                               printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+                                       __FUNCTION__, err);
+                               return(0);
+                       }
+                       cs->hw.avm.cfg_reg =
+                               pnp_port_start(pnp_avm_d, 0);
+                       cs->irq = pnp_irq(pnp_avm_d, 0);
+                       if (!cs->irq) {
+                               printk(KERN_ERR "FritzPnP:No IRQ\n");
+                               return(0);
+                       }
+                       if (!cs->hw.avm.cfg_reg) {
+                               printk(KERN_ERR "FritzPnP:No IO address\n");
+                               return(0);
+                       }
+                       cs->subtyp = AVM_FRITZ_PNP;
+
+                       return (2);     /* goto 'ready' label */
+               }
+       }
+
+       return (1);
+}
+
+#endif /* __ISAPNP__ */
+
+#ifndef CONFIG_PCI
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+       return(1);      /* no-op: success */
+}
+
+#else
+
+static struct pci_dev *dev_avm __devinitdata = NULL;
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+       if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+               PCI_DEVICE_ID_AVM_A1, dev_avm))) {
+
+               if (pci_enable_device(dev_avm))
+                       return(0);
+
+               cs->irq = dev_avm->irq;
+               if (!cs->irq) {
+                       printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
+                       return(0);
+               }
+
+               cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
+               if (!cs->hw.avm.cfg_reg) {
+                       printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
+                       return(0);
+               }
+
+               cs->subtyp = AVM_FRITZ_PCI;
+       } else {
+               printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+               return(0);
+       }
+
+       cs->irq_flags |= IRQF_SHARED;
+
+       return (1);
+}
+
+#endif /* CONFIG_PCI */
+
+int __devinit
+setup_avm_pcipnp(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+       int rc;
+
+       strcpy(tmp, avm_pci_rev);
+       printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
+
+       if (cs->typ != ISDN_CTYPE_FRITZPCI)
+               return (0);
+
+       if (card->para[1]) {
+               /* old manual method */
+               cs->hw.avm.cfg_reg = card->para[1];
+               cs->irq = card->para[0];
+               cs->subtyp = AVM_FRITZ_PNP;
+               goto ready;
+       }
+
+       rc = avm_pnp_setup(cs);
+       if (rc < 1)
+               return (0);
+       if (rc == 2)
+               goto ready;
+
+       rc = avm_pci_setup(cs);
+       if (rc < 1)
+               return (0);
+
+ready:
+       return avm_setup_rest(cs);
+}
index 6339bb4..99ef3b4 100644 (file)
@@ -20,8 +20,6 @@
 #include <linux/pci.h>
 #include "bkm_ax.h"
 
-#ifdef CONFIG_PCI
-
 #define        ATTEMPT_PCI_REMAPPING   /* Required for PLX rev 1 */
 
 extern const char *CardType[];
@@ -279,12 +277,9 @@ static u_char pci_bus __devinitdata = 0;
 static u_char pci_device_fn __devinitdata = 0;
 static u_char pci_irq __devinitdata = 0;
 
-#endif /* CONFIG_PCI */
-
 int __devinit
 setup_sct_quadro(struct IsdnCard *card)
 {
-#ifdef CONFIG_PCI
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
        u_int found = 0;
@@ -442,7 +437,4 @@ setup_sct_quadro(struct IsdnCard *card)
                sct_quadro_subtypes[cs->subtyp],
                readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
        return (1);
-#else
-       printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
-#endif /* CONFIG_PCI */
 }
index 6eebeb4..8267450 100644 (file)
@@ -25,8 +25,6 @@
 #include <linux/pci.h>
 #include <linux/isapnp.h>
 
-extern const char *CardType[];
-
 static const char *Diva_revision = "$Revision: 1.33.2.6 $";
 
 #define byteout(addr,val) outb(val,addr)
@@ -906,225 +904,15 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-static struct pci_dev *dev_diva __devinitdata = NULL;
-static struct pci_dev *dev_diva_u __devinitdata = NULL;
-static struct pci_dev *dev_diva201 __devinitdata = NULL;
-static struct pci_dev *dev_diva202 __devinitdata = NULL;
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] __devinitdata = {
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
-         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), 
-         (unsigned long) "Diva picola" },
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
-         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), 
-         (unsigned long) "Diva picola" },
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
-         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), 
-         (unsigned long) "Diva 2.0" },
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
-         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), 
-         (unsigned long) "Diva 2.0" },
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
-         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), 
-         (unsigned long) "Diva 2.01" },
-       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
-         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), 
-         (unsigned long) "Diva 2.01" },
-       { 0, }
-};
-
-static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
-
-
-int __devinit
-setup_diva(struct IsdnCard *card)
+static int __devinit setup_diva_common(struct IsdnCardState *cs)
 {
-       int bytecnt = 8;
+       int bytecnt;
        u_char val;
-       struct IsdnCardState *cs = card->cs;
-       char tmp[64];
-
-       strcpy(tmp, Diva_revision);
-       printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
-       if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
-               return(0);
-       cs->hw.diva.status = 0;
-       if (card->para[1]) {
-               cs->hw.diva.ctrl_reg = 0;
-               cs->hw.diva.cfg_reg = card->para[1];
-               val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
-                       cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
-               printk(KERN_INFO "Diva: IPAC version %x\n", val);
-               if ((val == 1) || (val==2)) {
-                       cs->subtyp = DIVA_IPAC_ISA;
-                       cs->hw.diva.ctrl = 0;
-                       cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
-                       cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
-                       cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
-                       cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
-                       test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-               } else {
-                       cs->subtyp = DIVA_ISA;
-                       cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
-                       cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
-                       cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
-                       cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
-                       cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
-               }
-               cs->irq = card->para[0];
-       } else {
-#ifdef __ISAPNP__
-               if (isapnp_present()) {
-                       struct pnp_dev *pnp_d;
-                       while(ipid->card_vendor) {
-                               if ((pnp_c = pnp_find_card(ipid->card_vendor,
-                                       ipid->card_device, pnp_c))) {
-                                       pnp_d = NULL;
-                                       if ((pnp_d = pnp_find_dev(pnp_c,
-                                               ipid->vendor, ipid->function, pnp_d))) {
-                                               int err;
-
-                                               printk(KERN_INFO "HiSax: %s detected\n",
-                                                       (char *)ipid->driver_data);
-                                               pnp_disable_dev(pnp_d);
-                                               err = pnp_activate_dev(pnp_d);
-                                               if (err<0) {
-                                                       printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-                                                               __FUNCTION__, err);
-                                                       return(0);
-                                               }
-                                               card->para[1] = pnp_port_start(pnp_d, 0);
-                                               card->para[0] = pnp_irq(pnp_d, 0);
-                                               if (!card->para[0] || !card->para[1]) {
-                                                       printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
-                                                               card->para[0], card->para[1]);
-                                                       pnp_disable_dev(pnp_d); 
-                                                       return(0);
-                                               }
-                                               cs->hw.diva.cfg_reg  = card->para[1];
-                                               cs->irq = card->para[0];
-                                               if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
-                                                       cs->subtyp = DIVA_IPAC_ISA;
-                                                       cs->hw.diva.ctrl = 0;
-                                                       cs->hw.diva.isac =
-                                                               card->para[1] + DIVA_IPAC_DATA;
-                                                       cs->hw.diva.hscx =
-                                                               card->para[1] + DIVA_IPAC_DATA;
-                                                       cs->hw.diva.isac_adr =
-                                                               card->para[1] + DIVA_IPAC_ADR;
-                                                       cs->hw.diva.hscx_adr =
-                                                               card->para[1] + DIVA_IPAC_ADR;
-                                                       test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-                                               } else {
-                                                       cs->subtyp = DIVA_ISA;
-                                                       cs->hw.diva.ctrl =
-                                                               card->para[1] + DIVA_ISA_CTRL;
-                                                       cs->hw.diva.isac =
-                                                               card->para[1] + DIVA_ISA_ISAC_DATA;
-                                                       cs->hw.diva.hscx =
-                                                               card->para[1] + DIVA_HSCX_DATA;
-                                                       cs->hw.diva.isac_adr =
-                                                               card->para[1] + DIVA_ISA_ISAC_ADR;
-                                                       cs->hw.diva.hscx_adr =
-                                                               card->para[1] + DIVA_HSCX_ADR;
-                                               }
-                                               goto ready;
-                                       } else {
-                                               printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
-                                               return(0);
-                                       }
-                               }
-                               ipid++;
-                               pnp_c=NULL;
-                       } 
-                       if (!ipid->card_vendor) {
-                               printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
-                       }
-               }
-#endif
-#ifdef CONFIG_PCI
-               cs->subtyp = 0;
-               if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
-                       PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
-                       if (pci_enable_device(dev_diva))
-                               return(0);
-                       cs->subtyp = DIVA_PCI;
-                       cs->irq = dev_diva->irq;
-                       cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
-               } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
-                       PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
-                       if (pci_enable_device(dev_diva_u))
-                               return(0);
-                       cs->subtyp = DIVA_PCI;
-                       cs->irq = dev_diva_u->irq;
-                       cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
-               } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
-                       PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
-                       if (pci_enable_device(dev_diva201))
-                               return(0);
-                       cs->subtyp = DIVA_IPAC_PCI;
-                       cs->irq = dev_diva201->irq;
-                       cs->hw.diva.pci_cfg =
-                               (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
-                       cs->hw.diva.cfg_reg =
-                               (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
-               } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
-                       PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
-                       if (pci_enable_device(dev_diva202))
-                               return(0);
-                       cs->subtyp = DIVA_IPACX_PCI;
-                       cs->irq = dev_diva202->irq;
-                       cs->hw.diva.pci_cfg =
-                               (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
-                       cs->hw.diva.cfg_reg =
-                               (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
-               } else {
-                       printk(KERN_WARNING "Diva: No PCI card found\n");
-                       return(0);
-               }
-
-               if (!cs->irq) {
-                       printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
-                       iounmap_diva(cs);
-                       return(0);
-               }
-
-               if (!cs->hw.diva.cfg_reg) {
-                       printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
-                       iounmap_diva(cs);
-                       return(0);
-               }
-               cs->irq_flags |= IRQF_SHARED;
-#else
-               printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
-               printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
-               return (0);
-#endif /* CONFIG_PCI */
-               if ((cs->subtyp == DIVA_IPAC_PCI) ||
-                   (cs->subtyp == DIVA_IPACX_PCI)   ) {
-                       cs->hw.diva.ctrl = 0;
-                       cs->hw.diva.isac = 0;
-                       cs->hw.diva.hscx = 0;
-                       cs->hw.diva.isac_adr = 0;
-                       cs->hw.diva.hscx_adr = 0;
-                       test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-                       bytecnt = 0;
-               } else {
-                       cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
-                       cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
-                       cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
-                       cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
-                       cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
-                       bytecnt = 32;
-               }
-       }
 
-#ifdef __ISAPNP__
-ready:
-#endif
+       if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
+               bytecnt = 8;
+       else
+               bytecnt = 32;
 
        printk(KERN_INFO
                "Diva: %s card configured at %#lx IRQ %d\n",
@@ -1145,7 +933,7 @@ ready:
                if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) {
                        printk(KERN_WARNING
                               "HiSax: %s config port %lx-%lx already in use\n",
-                              CardType[card->typ],
+                              "diva",
                               cs->hw.diva.cfg_reg,
                               cs->hw.diva.cfg_reg + bytecnt);
                        iounmap_diva(cs);
@@ -1206,3 +994,290 @@ ready:
        }
        return (1);
 }
+
+#ifdef CONFIG_ISA
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       u_char val;
+
+       if (!card->para[1])
+               return (-1);    /* card not found; continue search */
+
+       cs->hw.diva.ctrl_reg = 0;
+       cs->hw.diva.cfg_reg = card->para[1];
+       val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
+               cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
+       printk(KERN_INFO "Diva: IPAC version %x\n", val);
+       if ((val == 1) || (val==2)) {
+               cs->subtyp = DIVA_IPAC_ISA;
+               cs->hw.diva.ctrl = 0;
+               cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
+               cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
+               cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
+               cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
+               test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+       } else {
+               cs->subtyp = DIVA_ISA;
+               cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
+               cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
+               cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
+               cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
+               cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+       }
+       cs->irq = card->para[0];
+
+       return (1);             /* card found */
+}
+
+#else  /* if !CONFIG_ISA */
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+       return (-1);    /* card not found; continue search */
+}
+
+#endif /* CONFIG_ISA */
+
+#ifdef __ISAPNP__
+static struct isapnp_device_id diva_ids[] __devinitdata = {
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), 
+         (unsigned long) "Diva picola" },
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), 
+         (unsigned long) "Diva picola" },
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), 
+         (unsigned long) "Diva 2.0" },
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), 
+         (unsigned long) "Diva 2.0" },
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+         ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), 
+         (unsigned long) "Diva 2.01" },
+       { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+         ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), 
+         (unsigned long) "Diva 2.01" },
+       { 0, }
+};
+
+static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
+static struct pnp_card *pnp_c __devinitdata = NULL;
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       struct pnp_dev *pnp_d;
+
+       if (!isapnp_present())
+               return (-1);    /* card not found; continue search */
+
+       while(ipid->card_vendor) {
+               if ((pnp_c = pnp_find_card(ipid->card_vendor,
+                       ipid->card_device, pnp_c))) {
+                       pnp_d = NULL;
+                       if ((pnp_d = pnp_find_dev(pnp_c,
+                               ipid->vendor, ipid->function, pnp_d))) {
+                               int err;
+
+                               printk(KERN_INFO "HiSax: %s detected\n",
+                                       (char *)ipid->driver_data);
+                               pnp_disable_dev(pnp_d);
+                               err = pnp_activate_dev(pnp_d);
+                               if (err<0) {
+                                       printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+                                               __FUNCTION__, err);
+                                       return(0);
+                               }
+                               card->para[1] = pnp_port_start(pnp_d, 0);
+                               card->para[0] = pnp_irq(pnp_d, 0);
+                               if (!card->para[0] || !card->para[1]) {
+                                       printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+                                               card->para[0], card->para[1]);
+                                       pnp_disable_dev(pnp_d); 
+                                       return(0);
+                               }
+                               cs->hw.diva.cfg_reg  = card->para[1];
+                               cs->irq = card->para[0];
+                               if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
+                                       cs->subtyp = DIVA_IPAC_ISA;
+                                       cs->hw.diva.ctrl = 0;
+                                       cs->hw.diva.isac =
+                                               card->para[1] + DIVA_IPAC_DATA;
+                                       cs->hw.diva.hscx =
+                                               card->para[1] + DIVA_IPAC_DATA;
+                                       cs->hw.diva.isac_adr =
+                                               card->para[1] + DIVA_IPAC_ADR;
+                                       cs->hw.diva.hscx_adr =
+                                               card->para[1] + DIVA_IPAC_ADR;
+                                       test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+                               } else {
+                                       cs->subtyp = DIVA_ISA;
+                                       cs->hw.diva.ctrl =
+                                               card->para[1] + DIVA_ISA_CTRL;
+                                       cs->hw.diva.isac =
+                                               card->para[1] + DIVA_ISA_ISAC_DATA;
+                                       cs->hw.diva.hscx =
+                                               card->para[1] + DIVA_HSCX_DATA;
+                                       cs->hw.diva.isac_adr =
+                                               card->para[1] + DIVA_ISA_ISAC_ADR;
+                                       cs->hw.diva.hscx_adr =
+                                               card->para[1] + DIVA_HSCX_ADR;
+                               }
+                               return (1);             /* card found */
+                       } else {
+                               printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+                               return(0);
+                       }
+               }
+               ipid++;
+               pnp_c=NULL;
+       } 
+
+       return (-1);    /* card not found; continue search */
+}
+
+#else  /* if !ISAPNP */
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+       return (-1);    /* card not found; continue search */
+}
+
+#endif /* ISAPNP */
+
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_diva __devinitdata = NULL;
+static struct pci_dev *dev_diva_u __devinitdata = NULL;
+static struct pci_dev *dev_diva201 __devinitdata = NULL;
+static struct pci_dev *dev_diva202 __devinitdata = NULL;
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+
+       cs->subtyp = 0;
+       if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+               PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
+               if (pci_enable_device(dev_diva))
+                       return(0);
+               cs->subtyp = DIVA_PCI;
+               cs->irq = dev_diva->irq;
+               cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
+       } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+               PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
+               if (pci_enable_device(dev_diva_u))
+                       return(0);
+               cs->subtyp = DIVA_PCI;
+               cs->irq = dev_diva_u->irq;
+               cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
+       } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+               PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
+               if (pci_enable_device(dev_diva201))
+                       return(0);
+               cs->subtyp = DIVA_IPAC_PCI;
+               cs->irq = dev_diva201->irq;
+               cs->hw.diva.pci_cfg =
+                       (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
+               cs->hw.diva.cfg_reg =
+                       (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
+       } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+               PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
+               if (pci_enable_device(dev_diva202))
+                       return(0);
+               cs->subtyp = DIVA_IPACX_PCI;
+               cs->irq = dev_diva202->irq;
+               cs->hw.diva.pci_cfg =
+                       (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
+               cs->hw.diva.cfg_reg =
+                       (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
+       } else {
+               return (-1);    /* card not found; continue search */
+       }
+
+       if (!cs->irq) {
+               printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+               iounmap_diva(cs);
+               return(0);
+       }
+
+       if (!cs->hw.diva.cfg_reg) {
+               printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+               iounmap_diva(cs);
+               return(0);
+       }
+       cs->irq_flags |= IRQF_SHARED;
+
+       if ((cs->subtyp == DIVA_IPAC_PCI) ||
+           (cs->subtyp == DIVA_IPACX_PCI)   ) {
+               cs->hw.diva.ctrl = 0;
+               cs->hw.diva.isac = 0;
+               cs->hw.diva.hscx = 0;
+               cs->hw.diva.isac_adr = 0;
+               cs->hw.diva.hscx_adr = 0;
+               test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+       } else {
+               cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
+               cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
+               cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
+               cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
+               cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
+       }
+
+       return (1);             /* card found */
+}
+
+#else  /* if !CONFIG_PCI */
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+       return (-1);    /* card not found; continue search */
+}
+
+#endif /* CONFIG_PCI */
+
+int __devinit
+setup_diva(struct IsdnCard *card)
+{
+       int rc, have_card = 0;
+       struct IsdnCardState *cs = card->cs;
+       char tmp[64];
+
+       strcpy(tmp, Diva_revision);
+       printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
+       if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
+               return(0);
+       cs->hw.diva.status = 0;
+
+       rc = setup_diva_isa(card);
+       if (!rc)
+               return rc;
+       if (rc > 0) {
+               have_card = 1;
+               goto ready;
+       }
+
+       rc = setup_diva_isapnp(card);
+       if (!rc)
+               return rc;
+       if (rc > 0) {
+               have_card = 1;
+               goto ready;
+       }
+
+       rc = setup_diva_pci(card);
+       if (!rc)
+               return rc;
+       if (rc > 0)
+               have_card = 1;
+
+ready:
+       if (!have_card) {
+               printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n");
+               return(0);
+       }
+
+       return setup_diva_common(card->cs);
+}
index fab3e4e..0c1351b 100644 (file)
@@ -30,8 +30,6 @@
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 
-extern const char *CardType[];
-
 static const char *Elsa_revision = "$Revision: 2.32.2.4 $";
 static const char *Elsa_Types[] =
 {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
@@ -832,8 +830,75 @@ probe_elsa(struct IsdnCardState *cs)
        return (CARD_portlist[i]);
 }
 
-static         struct pci_dev *dev_qs1000 __devinitdata = NULL;
-static         struct pci_dev *dev_qs3000 __devinitdata = NULL;
+static int __devinit
+setup_elsa_isa(struct IsdnCard *card)
+{
+       struct IsdnCardState *cs = card->cs;
+       u_char val;
+
+       cs->hw.elsa.base = card->para[0];
+       printk(KERN_INFO "Elsa: Microlink IO probing\n");
+       if (cs->hw.elsa.base) {
+               if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+                                                 cs->typ))) {
+                       printk(KERN_WARNING
+                              "Elsa: no Elsa Microlink at %#lx\n",
+                              cs->hw.elsa.base);
+                       return (0);
+               }
+       } else
+               cs->hw.elsa.base = probe_elsa(cs);
+
+       if (!cs->hw.elsa.base) {
+               printk(KERN_WARNING
+                      "No Elsa Microlink found\n");
+               return (0);
+       }
+
+       cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+       cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+       cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+       cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+       cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+       cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+       cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+       cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+       val = bytein(cs->hw.elsa.cfg);
+       if (cs->subtyp == ELSA_PC) {
+               const u_char CARD_IrqTab[8] =
+               {7, 3, 5, 9, 0, 0, 0, 0};
+               cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+       } else if (cs->subtyp == ELSA_PCC8) {
+               const u_char CARD_IrqTab[8] =
+               {7, 3, 5, 9, 0, 0, 0, 0};
+               cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];