Merge branch 'kvm-updates/2.6.32' of git://git.kernel.org/pub/scm/virt/kvm/kvm
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 5 Oct 2009 19:07:39 +0000 (12:07 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 5 Oct 2009 19:07:39 +0000 (12:07 -0700)
* 'kvm-updates/2.6.32' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: add support for change_pte mmu notifiers
  KVM: MMU: add SPTE_HOST_WRITEABLE flag to the shadow ptes
  KVM: MMU: dont hold pagecount reference for mapped sptes pages
  KVM: Prevent overflow in KVM_GET_SUPPORTED_CPUID
  KVM: VMX: flush TLB with INVEPT on cpu migration
  KVM: fix LAPIC timer period overflow
  KVM: s390: fix memsize >= 4G
  KVM: SVM: Handle tsc in svm_get_msr/svm_set_msr correctly
  KVM: SVM: Fix tsc offset adjustment when running nested

125 files changed:
Documentation/ABI/testing/sysfs-bus-pci-devices-cciss
Documentation/hwmon/ltc4215
Documentation/hwmon/ltc4245
Documentation/i2c/chips/eeprom [deleted file]
Documentation/i2c/chips/max6875 [deleted file]
Documentation/i2c/instantiating-devices
Documentation/kernel-parameters.txt
Documentation/misc-devices/eeprom [new file with mode: 0644]
Documentation/misc-devices/max6875 [new file with mode: 0644]
Documentation/w1/masters/ds2482
MAINTAINERS
Makefile
arch/m68knommu/kernel/asm-offsets.c
arch/m68knommu/kernel/entry.S
arch/m68knommu/mm/init.c
arch/m68knommu/platform/5206e/config.c
arch/m68knommu/platform/68328/entry.S
arch/m68knommu/platform/68360/entry.S
arch/m68knommu/platform/coldfire/entry.S
arch/microblaze/kernel/entry.S
arch/microblaze/kernel/hw_exception_handler.S
arch/microblaze/kernel/process.c
arch/sparc/include/asm/hardirq_32.h
arch/sparc/include/asm/irq_32.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/kernel/ktlb.S
arch/sparc/kernel/perf_event.c
arch/sparc/oprofile/init.c
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/ia32/ia32entry.S
arch/x86/kernel/early_printk.c
arch/x86/kernel/i386_ksyms_32.c
arch/x86/lib/Makefile
block/blk-barrier.c
block/blk-core.c
block/blk-merge.c
block/blk-settings.c
block/blk-sysfs.c
block/cfq-iosched.c
block/compat_ioctl.c
block/genhd.c
block/ioctl.c
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_pad.c [new file with mode: 0644]
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/proc.c
drivers/acpi/processor_core.c
drivers/acpi/scan.c
drivers/block/DAC960.c
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cpqarray.c
drivers/char/dtlk.c
drivers/char/ipmi/ipmi_devintf.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/firewire/core-cdev.c
drivers/firmware/iscsi_ibft.c
drivers/firmware/iscsi_ibft_find.c
drivers/hid/hidraw.c
drivers/hwmon/ltc4215.c
drivers/hwmon/ltc4245.c
drivers/i2c/busses/i2c-amd756.c
drivers/i2c/busses/i2c-amd8111.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-isch.c
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/busses/i2c-sis96x.c
drivers/i2c/busses/i2c-viapro.c
drivers/infiniband/core/ucm.c
drivers/infiniband/core/user_mad.c
drivers/infiniband/core/uverbs_main.c
drivers/input/evdev.c
drivers/input/input.c
drivers/input/joydev.c
drivers/input/misc/uinput.c
drivers/input/mousedev.c
drivers/isdn/divert/divert_procfs.c
drivers/leds/leds-pca9532.c
drivers/macintosh/therm_adt746x.c
drivers/macintosh/therm_pm72.c
drivers/macintosh/windfarm_lm75_sensor.c
drivers/macintosh/windfarm_max6690_sensor.c
drivers/macintosh/windfarm_smu_sat.c
drivers/md/dm.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/radio/radio-cadet.c
drivers/media/video/cpia.c
drivers/mfd/ab3100-core.c
drivers/mfd/ucb1400_core.c
drivers/misc/eeprom/max6875.c
drivers/mtd/mtd_blkdevs.c
drivers/platform/x86/sony-laptop.c
drivers/sfi/sfi_core.c
drivers/staging/dst/dcore.c
drivers/staging/iio/light/tsl2561.c
drivers/usb/gadget/inode.c
drivers/w1/masters/ds2482.c
drivers/xen/xenfs/xenbus.c
fs/anon_inodes.c
fs/bio.c
fs/coda/psdev.c
fs/partitions/check.c
fs/select.c
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/fs.h
include/linux/genhd.h
include/linux/poll.h
include/trace/events/block.h
kernel/hrtimer.c
kernel/perf_event.c
kernel/trace/blktrace.c
kernel/trace/ftrace.c
kernel/trace/kmemtrace.c
mm/swapfile.c
net/rfkill/core.c
tools/perf/Documentation/perf-timechart.txt
tools/perf/Makefile
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/util/svghelper.c

index 0a92a7c93a62067f4526fe581f4604c3eb9f5ee0..4f29e5f1ebfa5b19cd7851e6148b80219911e9c2 100644 (file)
@@ -31,3 +31,31 @@ Date:                March 2009
 Kernel Version: 2.6.30
 Contact:       iss_storagedev@hp.com
 Description:   A symbolic link to /sys/block/cciss!cXdY
+
+Where:         /sys/bus/pci/devices/<dev>/ccissX/rescan
+Date:          August 2009
+Kernel Version:        2.6.31
+Contact:       iss_storagedev@hp.com
+Description:   Kicks of a rescan of the controller to discover logical
+               drive topology changes.
+
+Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/lunid
+Date:          August 2009
+Kernel Version: 2.6.31
+Contact:       iss_storagedev@hp.com
+Description:   Displays the 8-byte LUN ID used to address logical
+               drive Y of controller X.
+
+Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/raid_level
+Date:          August 2009
+Kernel Version: 2.6.31
+Contact:       iss_storagedev@hp.com
+Description:   Displays the RAID level of logical drive Y of
+               controller X.
+
+Where:         /sys/bus/pci/devices/<dev>/ccissX/cXdY/usage_count
+Date:          August 2009
+Kernel Version: 2.6.31
+Contact:       iss_storagedev@hp.com
+Description:   Displays the usage count (number of opens) of logical drive Y
+               of controller X.
index 2e6a21eb656c556ce4e4c154a6e1229c35275938..c196a18462592f842d7637e3b443c295092cb78b 100644 (file)
@@ -22,12 +22,13 @@ Usage Notes
 -----------
 
 This driver does not probe for LTC4215 devices, due to the fact that some
-of the possible addresses are unfriendly to probing. You will need to use
-the "force" parameter to tell the driver where to find the device.
+of the possible addresses are unfriendly to probing. You will have to
+instantiate the devices explicitly.
 
 Example: the following will load the driver for an LTC4215 at address 0x44
 on I2C bus #0:
-$ modprobe ltc4215 force=0,0x44
+$ modprobe ltc4215
+$ echo ltc4215 0x44 > /sys/bus/i2c/devices/i2c-0/new_device
 
 
 Sysfs entries
index bae7a3adc5d8ff72aded4e8abbd07c30de454f59..02838a47d86210fa8bee469f595c94851594bd44 100644 (file)
@@ -23,12 +23,13 @@ Usage Notes
 -----------
 
 This driver does not probe for LTC4245 devices, due to the fact that some
-of the possible addresses are unfriendly to probing. You will need to use
-the "force" parameter to tell the driver where to find the device.
+of the possible addresses are unfriendly to probing. You will have to
+instantiate the devices explicitly.
 
 Example: the following will load the driver for an LTC4245 at address 0x23
 on I2C bus #1:
-$ modprobe ltc4245 force=1,0x23
+$ modprobe ltc4245
+$ echo ltc4245 0x23 > /sys/bus/i2c/devices/i2c-1/new_device
 
 
 Sysfs entries
diff --git a/Documentation/i2c/chips/eeprom b/Documentation/i2c/chips/eeprom
deleted file mode 100644 (file)
index f7e8104..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-Kernel driver eeprom
-====================
-
-Supported chips:
-  * Any EEPROM chip in the designated address range
-    Prefix: 'eeprom'
-    Addresses scanned: I2C 0x50 - 0x57
-    Datasheets: Publicly available from:
-                Atmel (www.atmel.com),
-                Catalyst (www.catsemi.com),
-                Fairchild (www.fairchildsemi.com),
-                Microchip (www.microchip.com),
-                Philips (www.semiconductor.philips.com),
-                Rohm (www.rohm.com),
-                ST (www.st.com),
-                Xicor (www.xicor.com),
-                and others.
-
-        Chip     Size (bits)    Address
-        24C01     1K            0x50 (shadows at 0x51 - 0x57)
-        24C01A    1K            0x50 - 0x57 (Typical device on DIMMs)
-        24C02     2K            0x50 - 0x57
-        24C04     4K            0x50, 0x52, 0x54, 0x56
-                                (additional data at 0x51, 0x53, 0x55, 0x57)
-        24C08     8K            0x50, 0x54 (additional data at 0x51, 0x52,
-                                0x53, 0x55, 0x56, 0x57)
-        24C16    16K            0x50 (additional data at 0x51 - 0x57)
-        Sony      2K            0x57
-
-        Atmel     34C02B  2K    0x50 - 0x57, SW write protect at 0x30-37
-        Catalyst  34FC02  2K    0x50 - 0x57, SW write protect at 0x30-37
-        Catalyst  34RC02  2K    0x50 - 0x57, SW write protect at 0x30-37
-        Fairchild 34W02   2K    0x50 - 0x57, SW write protect at 0x30-37
-        Microchip 24AA52  2K    0x50 - 0x57, SW write protect at 0x30-37
-        ST        M34C02  2K    0x50 - 0x57, SW write protect at 0x30-37
-
-
-Authors:
-        Frodo Looijaard <frodol@dds.nl>,
-        Philip Edelbrock <phil@netroedge.com>,
-        Jean Delvare <khali@linux-fr.org>,
-        Greg Kroah-Hartman <greg@kroah.com>,
-        IBM Corp.
-
-Description
------------
-
-This is a simple EEPROM module meant to enable reading the first 256 bytes
-of an EEPROM (on a SDRAM DIMM for example). However, it will access serial
-EEPROMs on any I2C adapter. The supported devices are generically called
-24Cxx, and are listed above; however the numbering for these
-industry-standard devices may vary by manufacturer.
-
-This module was a programming exercise to get used to the new project
-organization laid out by Frodo, but it should be at least completely
-effective for decoding the contents of EEPROMs on DIMMs.
-
-DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants.
-The other devices will not be found on a DIMM because they respond to more
-than one address.
-
-DDC Monitors may contain any device. Often a 24C01, which responds to all 8
-addresses, is found.
-
-Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the
-specification, so it is guess work and far from being complete.
-
-The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional
-software write protect register at 0x30 - 0x37 (0x20 less than the memory
-location). The chip responds to "write quick" detection at this address but
-does not respond to byte reads. If this register is present, the lower 128
-bytes of the memory array are not write protected. Any byte data write to
-this address will write protect the memory array permanently, and the
-device will no longer respond at the 0x30-37 address. The eeprom driver
-does not support this register.
-
-Lacking functionality:
-
-* Full support for larger devices (24C04, 24C08, 24C16). These are not
-typically found on a PC. These devices will appear as separate devices at
-multiple addresses.
-
-* Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512).
-These devices require two-byte address fields and are not supported.
-
-* Enable Writing. Again, no technical reason why not, but making it easy
-to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy
-to disable the DIMMs (potentially preventing the computer from booting)
-until the values are restored somehow.
-
-Use:
-
-After inserting the module (and any other required SMBus/i2c modules), you
-should have some EEPROM directories in /sys/bus/i2c/devices/* of names such
-as "0-0050". Inside each of these is a series of files, the eeprom file
-contains the binary data from EEPROM.
diff --git a/Documentation/i2c/chips/max6875 b/Documentation/i2c/chips/max6875
deleted file mode 100644 (file)
index 10ca43c..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-Kernel driver max6875
-=====================
-
-Supported chips:
-  * Maxim MAX6874, MAX6875
-    Prefix: 'max6875'
-    Addresses scanned: None (see below)
-    Datasheet:
-        http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf
-
-Author: Ben Gardner <bgardner@wabtec.com>
-
-
-Description
------------
-
-The Maxim MAX6875 is an EEPROM-programmable power-supply sequencer/supervisor.
-It provides timed outputs that can be used as a watchdog, if properly wired.
-It also provides 512 bytes of user EEPROM.
-
-At reset, the MAX6875 reads the configuration EEPROM into its configuration
-registers.  The chip then begins to operate according to the values in the
-registers.
-
-The Maxim MAX6874 is a similar, mostly compatible device, with more intputs
-and outputs:
-             vin     gpi    vout
-MAX6874        6       4       8
-MAX6875        4       3       5
-
-See the datasheet for more information.
-
-
-Sysfs entries
--------------
-
-eeprom        - 512 bytes of user-defined EEPROM space.
-
-
-General Remarks
----------------
-
-Valid addresses for the MAX6875 are 0x50 and 0x52.
-Valid addresses for the MAX6874 are 0x50, 0x52, 0x54 and 0x56.
-The driver does not probe any address, so you must force the address.
-
-Example:
-$ modprobe max6875 force=0,0x50
-
-The MAX6874/MAX6875 ignores address bit 0, so this driver attaches to multiple
-addresses.  For example, for address 0x50, it also reserves 0x51.
-The even-address instance is called 'max6875', the odd one is 'dummy'.
-
-
-Programming the chip using i2c-dev
-----------------------------------
-
-Use the i2c-dev interface to access and program the chips.
-Reads and writes are performed differently depending on the address range.
-
-The configuration registers are at addresses 0x00 - 0x45.
-Use i2c_smbus_write_byte_data() to write a register and
-i2c_smbus_read_byte_data() to read a register.
-The command is the register number.
-
-Examples:
-To write a 1 to register 0x45:
-  i2c_smbus_write_byte_data(fd, 0x45, 1);
-
-To read register 0x45:
-  value = i2c_smbus_read_byte_data(fd, 0x45);
-
-
-The configuration EEPROM is at addresses 0x8000 - 0x8045.
-The user EEPROM is at addresses 0x8100 - 0x82ff.
-
-Use i2c_smbus_write_word_data() to write a byte to EEPROM.
-
-The command is the upper byte of the address: 0x80, 0x81, or 0x82.
-The data word is the lower part of the address or'd with data << 8.
-  cmd = address >> 8;
-  val = (address & 0xff) | (data << 8);
-
-Example:
-To write 0x5a to address 0x8003:
-  i2c_smbus_write_word_data(fd, 0x80, 0x5a03);
-
-
-Reading data from the EEPROM is a little more complicated.
-Use i2c_smbus_write_byte_data() to set the read address and then
-i2c_smbus_read_byte() or i2c_smbus_read_i2c_block_data() to read the data.
-
-Example:
-To read data starting at offset 0x8100, first set the address:
-  i2c_smbus_write_byte_data(fd, 0x81, 0x00);
-
-And then read the data
-  value = i2c_smbus_read_byte(fd);
-
-  or
-
-  count = i2c_smbus_read_i2c_block_data(fd, 0x84, 16, buffer);
-
-The block read should read 16 bytes.
-0x84 is the block read command.
-
-See the datasheet for more details.
-
index c740b7b410881a72f41256220c03b83c4796d523..e89490270abad1ece6f8003b16ac815490f8de17 100644 (file)
@@ -188,7 +188,7 @@ segment, the address is sufficient to uniquely identify the device to be
 deleted.
 
 Example:
-# echo eeprom 0x50 > /sys/class/i2c-adapter/i2c-3/new_device
+# echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device
 
 While this interface should only be used when in-kernel device declaration
 can't be done, there is a variety of cases where it can be helpful:
index 6fa7292947e5c8d100d6e426013aa31aa421f115..9107b387e91fce095ee320dbeed53d5dfe5cb332 100644 (file)
@@ -671,6 +671,7 @@ and is between 256 and 4096 characters. It is defined in the file
        earlyprintk=    [X86,SH,BLACKFIN]
                        earlyprintk=vga
                        earlyprintk=serial[,ttySn[,baudrate]]
+                       earlyprintk=ttySn[,baudrate]
                        earlyprintk=dbgp[debugController#]
 
                        Append ",keep" to not disable it when the real console
diff --git a/Documentation/misc-devices/eeprom b/Documentation/misc-devices/eeprom
new file mode 100644 (file)
index 0000000..f7e8104
--- /dev/null
@@ -0,0 +1,96 @@
+Kernel driver eeprom
+====================
+
+Supported chips:
+  * Any EEPROM chip in the designated address range
+    Prefix: 'eeprom'
+    Addresses scanned: I2C 0x50 - 0x57
+    Datasheets: Publicly available from:
+                Atmel (www.atmel.com),
+                Catalyst (www.catsemi.com),
+                Fairchild (www.fairchildsemi.com),
+                Microchip (www.microchip.com),
+                Philips (www.semiconductor.philips.com),
+                Rohm (www.rohm.com),
+                ST (www.st.com),
+                Xicor (www.xicor.com),
+                and others.
+
+        Chip     Size (bits)    Address
+        24C01     1K            0x50 (shadows at 0x51 - 0x57)
+        24C01A    1K            0x50 - 0x57 (Typical device on DIMMs)
+        24C02     2K            0x50 - 0x57
+        24C04     4K            0x50, 0x52, 0x54, 0x56
+                                (additional data at 0x51, 0x53, 0x55, 0x57)
+        24C08     8K            0x50, 0x54 (additional data at 0x51, 0x52,
+                                0x53, 0x55, 0x56, 0x57)
+        24C16    16K            0x50 (additional data at 0x51 - 0x57)
+        Sony      2K            0x57
+
+        Atmel     34C02B  2K    0x50 - 0x57, SW write protect at 0x30-37
+        Catalyst  34FC02  2K    0x50 - 0x57, SW write protect at 0x30-37
+        Catalyst  34RC02  2K    0x50 - 0x57, SW write protect at 0x30-37
+        Fairchild 34W02   2K    0x50 - 0x57, SW write protect at 0x30-37
+        Microchip 24AA52  2K    0x50 - 0x57, SW write protect at 0x30-37
+        ST        M34C02  2K    0x50 - 0x57, SW write protect at 0x30-37
+
+
+Authors:
+        Frodo Looijaard <frodol@dds.nl>,
+        Philip Edelbrock <phil@netroedge.com>,
+        Jean Delvare <khali@linux-fr.org>,
+        Greg Kroah-Hartman <greg@kroah.com>,
+        IBM Corp.
+
+Description
+-----------
+
+This is a simple EEPROM module meant to enable reading the first 256 bytes
+of an EEPROM (on a SDRAM DIMM for example). However, it will access serial
+EEPROMs on any I2C adapter. The supported devices are generically called
+24Cxx, and are listed above; however the numbering for these
+industry-standard devices may vary by manufacturer.
+
+This module was a programming exercise to get used to the new project
+organization laid out by Frodo, but it should be at least completely
+effective for decoding the contents of EEPROMs on DIMMs.
+
+DIMMS will typically contain a 24C01A or 24C02, or the 34C02 variants.
+The other devices will not be found on a DIMM because they respond to more
+than one address.
+
+DDC Monitors may contain any device. Often a 24C01, which responds to all 8
+addresses, is found.
+
+Recent Sony Vaio laptops have an EEPROM at 0x57. We couldn't get the
+specification, so it is guess work and far from being complete.
+
+The Microchip 24AA52/24LCS52, ST M34C02, and others support an additional
+software write protect register at 0x30 - 0x37 (0x20 less than the memory
+location). The chip responds to "write quick" detection at this address but
+does not respond to byte reads. If this register is present, the lower 128
+bytes of the memory array are not write protected. Any byte data write to
+this address will write protect the memory array permanently, and the
+device will no longer respond at the 0x30-37 address. The eeprom driver
+does not support this register.
+
+Lacking functionality:
+
+* Full support for larger devices (24C04, 24C08, 24C16). These are not
+typically found on a PC. These devices will appear as separate devices at
+multiple addresses.
+
+* Support for really large devices (24C32, 24C64, 24C128, 24C256, 24C512).
+These devices require two-byte address fields and are not supported.
+
+* Enable Writing. Again, no technical reason why not, but making it easy
+to change the contents of the EEPROMs (on DIMMs anyway) also makes it easy
+to disable the DIMMs (potentially preventing the computer from booting)
+until the values are restored somehow.
+
+Use:
+
+After inserting the module (and any other required SMBus/i2c modules), you
+should have some EEPROM directories in /sys/bus/i2c/devices/* of names such
+as "0-0050". Inside each of these is a series of files, the eeprom file
+contains the binary data from EEPROM.
diff --git a/Documentation/misc-devices/max6875 b/Documentation/misc-devices/max6875
new file mode 100644 (file)
index 0000000..1e89ee3
--- /dev/null
@@ -0,0 +1,110 @@
+Kernel driver max6875
+=====================
+
+Supported chips:
+  * Maxim MAX6874, MAX6875
+    Prefix: 'max6875'
+    Addresses scanned: None (see below)
+    Datasheet:
+        http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf
+
+Author: Ben Gardner <bgardner@wabtec.com>
+
+
+Description
+-----------
+
+The Maxim MAX6875 is an EEPROM-programmable power-supply sequencer/supervisor.
+It provides timed outputs that can be used as a watchdog, if properly wired.
+It also provides 512 bytes of user EEPROM.
+
+At reset, the MAX6875 reads the configuration EEPROM into its configuration
+registers.  The chip then begins to operate according to the values in the
+registers.
+
+The Maxim MAX6874 is a similar, mostly compatible device, with more intputs
+and outputs:
+             vin     gpi    vout
+MAX6874        6       4       8
+MAX6875        4       3       5
+
+See the datasheet for more information.
+
+
+Sysfs entries
+-------------
+
+eeprom        - 512 bytes of user-defined EEPROM space.
+
+
+General Remarks
+---------------
+
+Valid addresses for the MAX6875 are 0x50 and 0x52.
+Valid addresses for the MAX6874 are 0x50, 0x52, 0x54 and 0x56.
+The driver does not probe any address, so you explicitly instantiate the
+devices.
+
+Example:
+$ modprobe max6875
+$ echo max6875 0x50 > /sys/bus/i2c/devices/i2c-0/new_device
+
+The MAX6874/MAX6875 ignores address bit 0, so this driver attaches to multiple
+addresses.  For example, for address 0x50, it also reserves 0x51.
+The even-address instance is called 'max6875', the odd one is 'dummy'.
+
+
+Programming the chip using i2c-dev
+----------------------------------
+
+Use the i2c-dev interface to access and program the chips.
+Reads and writes are performed differently depending on the address range.
+
+The configuration registers are at addresses 0x00 - 0x45.
+Use i2c_smbus_write_byte_data() to write a register and
+i2c_smbus_read_byte_data() to read a register.
+The command is the register number.
+
+Examples:
+To write a 1 to register 0x45:
+  i2c_smbus_write_byte_data(fd, 0x45, 1);
+
+To read register 0x45:
+  value = i2c_smbus_read_byte_data(fd, 0x45);
+
+
+The configuration EEPROM is at addresses 0x8000 - 0x8045.
+The user EEPROM is at addresses 0x8100 - 0x82ff.
+
+Use i2c_smbus_write_word_data() to write a byte to EEPROM.
+
+The command is the upper byte of the address: 0x80, 0x81, or 0x82.
+The data word is the lower part of the address or'd with data << 8.
+  cmd = address >> 8;
+  val = (address & 0xff) | (data << 8);
+
+Example:
+To write 0x5a to address 0x8003:
+  i2c_smbus_write_word_data(fd, 0x80, 0x5a03);
+
+
+Reading data from the EEPROM is a little more complicated.
+Use i2c_smbus_write_byte_data() to set the read address and then
+i2c_smbus_read_byte() or i2c_smbus_read_i2c_block_data() to read the data.
+
+Example:
+To read data starting at offset 0x8100, first set the address:
+  i2c_smbus_write_byte_data(fd, 0x81, 0x00);
+
+And then read the data
+  value = i2c_smbus_read_byte(fd);
+
+  or
+
+  count = i2c_smbus_read_i2c_block_data(fd, 0x84, 16, buffer);
+
+The block read should read 16 bytes.
+0x84 is the block read command.
+
+See the datasheet for more details.
+
index 9210d6fa50247a687e0e51e242c15e3ecbbaad28..299b91c7609f2a5d8cd439a3d71d0f2694fea1a8 100644 (file)
@@ -24,8 +24,8 @@ General Remarks
 
 Valid addresses are 0x18, 0x19, 0x1a, and 0x1b.
 However, the device cannot be detected without writing to the i2c bus, so no
-detection is done.
-You should force the device address.
+detection is done. You should instantiate the device explicitly.
 
-$ modprobe ds2482 force=0,0x18
+$ modprobe ds2482
+$ echo ds2482 0x18 > /sys/bus/i2c/devices/i2c-0/new_device
 
index 737a9b2c532d20c430b5d67a3a1dc72ea30df1a6..09a2028bab7f78786266c10fe1d2f99b0e1e263c 100644 (file)
@@ -257,6 +257,13 @@ W: http://www.lesswatts.org/projects/acpi/
 S:     Supported
 F:     drivers/acpi/fan.c
 
+ACPI PROCESSOR AGGREGATOR DRIVER
+M:     Shaohua Li <shaohua.li@intel.com>
+L:     linux-acpi@vger.kernel.org
+W:     http://www.lesswatts.org/projects/acpi/
+S:     Supported
+F:     drivers/acpi/acpi_pad.c
+
 ACPI THERMAL DRIVER
 M:     Zhang Rui <rui.zhang@intel.com>
 L:     linux-acpi@vger.kernel.org
index 00444a8e304f04b67c9de2f29ea543912fd67f5d..e50569ab5fe8b656396afd38193fc9b847fe30b4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 32
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc3
 NAME = Man-Eating Seals of Antiquity
 
 # *DOCUMENTATION*
index 594ee0e657fe0da77cbd20740c202b044e0d7ded..9a8876f715d81d73214c97079d2a601460fe6234 100644 (file)
@@ -45,25 +45,25 @@ int main(void)
        DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
 
        /* offsets into the pt_regs */
-       DEFINE(PT_D0, offsetof(struct pt_regs, d0));
-       DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0));
-       DEFINE(PT_D1, offsetof(struct pt_regs, d1));
-       DEFINE(PT_D2, offsetof(struct pt_regs, d2));
-       DEFINE(PT_D3, offsetof(struct pt_regs, d3));
-       DEFINE(PT_D4, offsetof(struct pt_regs, d4));
-       DEFINE(PT_D5, offsetof(struct pt_regs, d5));
-       DEFINE(PT_A0, offsetof(struct pt_regs, a0));
-       DEFINE(PT_A1, offsetof(struct pt_regs, a1));
-       DEFINE(PT_A2, offsetof(struct pt_regs, a2));
-       DEFINE(PT_PC, offsetof(struct pt_regs, pc));
-       DEFINE(PT_SR, offsetof(struct pt_regs, sr));
+       DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
+       DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
+       DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
+       DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
+       DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
+       DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
+       DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
+       DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
+       DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
+       DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
+       DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
+       DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
 
 #ifdef CONFIG_COLDFIRE
        /* bitfields are a bit difficult */
-       DEFINE(PT_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
+       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
 #else
        /* bitfields are a bit difficult */
-       DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
+       DEFINE(PT_OFF_VECTOR, offsetof(struct pt_regs, pc) + 4);
 #endif
 
        /* signal defines */
index f56faa5c9cd91a06e2c24e153c3fd54fa72a183e..56043ade394197ebb011fcfcd94a50df9d181179 100644 (file)
@@ -46,7 +46,7 @@
 ENTRY(buserr)
        SAVE_ALL
        moveq   #-1,%d0
-       movel   %d0,%sp@(PT_ORIG_D0)
+       movel   %d0,%sp@(PT_OFF_ORIG_D0)
        movel   %sp,%sp@-               /* stack frame pointer argument */
        jsr     buserr_c
        addql   #4,%sp
@@ -55,7 +55,7 @@ ENTRY(buserr)
 ENTRY(trap)
        SAVE_ALL
        moveq   #-1,%d0
-       movel   %d0,%sp@(PT_ORIG_D0)
+       movel   %d0,%sp@(PT_OFF_ORIG_D0)
        movel   %sp,%sp@-               /* stack frame pointer argument */
        jsr     trap_c
        addql   #4,%sp
@@ -67,7 +67,7 @@ ENTRY(trap)
 ENTRY(dbginterrupt)
        SAVE_ALL
        moveq   #-1,%d0
-       movel   %d0,%sp@(PT_ORIG_D0)
+       movel   %d0,%sp@(PT_OFF_ORIG_D0)
        movel   %sp,%sp@-               /* stack frame pointer argument */
        jsr     dbginterrupt_c
        addql   #4,%sp
index b1703c67a4f195f54203e8cbeed93c3441b8d9a8..f3236d0b522ddceaa39a9a468b7cc4f02d27b5d1 100644 (file)
@@ -162,7 +162,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
                totalram_pages++;
                pages++;
        }
-       printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages);
+       printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages * (PAGE_SIZE / 1024));
 }
 #endif
 
index 0f41ba82a3b533d1ff6a3815f59916c6d3e5f77e..942397984c66ca685bd93e1d559585ecbabf71f5 100644 (file)
@@ -17,7 +17,6 @@
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
 #include <asm/mcfdma.h>
-#include <asm/mcfuart.h>
 
 /***************************************************************************/
 
index b1aef72f3bafb23dcb5e3285be12029de801542b..9d80d2c4286668f2715d64a5026026e5f98cfae7 100644 (file)
 .globl inthandler7
 
 badsys:
-       movel   #-ENOSYS,%sp@(PT_D0)
+       movel   #-ENOSYS,%sp@(PT_OFF_D0)
        jra     ret_from_exception
 
 do_trace:
-       movel   #-ENOSYS,%sp@(PT_D0)    /* needed for strace*/
+       movel   #-ENOSYS,%sp@(PT_OFF_D0)        /* needed for strace*/
        subql   #4,%sp
        SAVE_SWITCH_STACK
        jbsr    syscall_trace
        RESTORE_SWITCH_STACK
        addql   #4,%sp
-       movel   %sp@(PT_ORIG_D0),%d1
+       movel   %sp@(PT_OFF_ORIG_D0),%d1
        movel   #-ENOSYS,%d0
        cmpl    #NR_syscalls,%d1
        jcc     1f
@@ -57,7 +57,7 @@ do_trace:
        lea     sys_call_table, %a0
        jbsr    %a0@(%d1)
 
-1:     movel   %d0,%sp@(PT_D0)         /* save the return value */
+1:     movel   %d0,%sp@(PT_OFF_D0)             /* save the return value */
        subql   #4,%sp                  /* dummy return address */
        SAVE_SWITCH_STACK
        jbsr    syscall_trace
@@ -75,7 +75,7 @@ ENTRY(system_call)
        jbsr    set_esp0
        addql   #4,%sp
 
-       movel   %sp@(PT_ORIG_D0),%d0
+       movel   %sp@(PT_OFF_ORIG_D0),%d0
 
        movel   %sp,%d1                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d1
@@ -88,10 +88,10 @@ ENTRY(system_call)
        lea     sys_call_table,%a0
        movel   %a0@(%d0), %a0
        jbsr    %a0@
-       movel   %d0,%sp@(PT_D0)         /* save the return value*/
+       movel   %d0,%sp@(PT_OFF_D0)             /* save the return value*/
 
 ret_from_exception:
-       btst    #5,%sp@(PT_SR)          /* check if returning to kernel*/
+       btst    #5,%sp@(PT_OFF_SR)              /* check if returning to kernel*/
        jeq     Luser_return            /* if so, skip resched, signals*/
 
 Lkernel_return:
@@ -133,7 +133,7 @@ Lreturn:
  */
 inthandler1:
        SAVE_ALL
-       movew   %sp@(PT_VECTOR), %d0
+       movew   %sp@(PT_OFF_VECTOR), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -144,7 +144,7 @@ inthandler1:
 
 inthandler2:
        SAVE_ALL
-       movew   %sp@(PT_VECTOR), %d0
+       movew   %sp@(PT_OFF_VECTOR), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -155,7 +155,7 @@ inthandler2:
 
 inthandler3:
        SAVE_ALL
-       movew   %sp@(PT_VECTOR), %d0
+       movew   %sp@(PT_OFF_VECTOR), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -166,7 +166,7 @@ inthandler3:
 
 inthandler4:
        SAVE_ALL
-       movew   %sp@(PT_VECTOR), %d0
+       movew   %sp@(PT_OFF_VECTOR), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -177,7 +177,7 @@ inthandler4:
 
 inthandler5:
        SAVE_ALL
-       movew   %sp@(PT_VECTOR), %d0
+       movew   %sp@(PT_OFF_VECTOR), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -188,7 +188,7 @@ inthandler5:
 
 inthandler6:
        SAVE_ALL
-       movew   %sp@(PT_VECTOR), %d0
+       movew   %sp@(PT_OFF_VECTOR), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -199,7 +199,7 @@ inthandler6:
 
 inthandler7:
        SAVE_ALL
-       movew   %sp@(PT_VECTOR), %d0
+       movew   %sp@(PT_OFF_VECTOR), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -210,7 +210,7 @@ inthandler7:
 
 inthandler:
        SAVE_ALL
-       movew   %sp@(PT_VECTOR), %d0
+       movew   %sp@(PT_OFF_VECTOR), %d0
        and     #0x3ff, %d0
 
        movel   %sp,%sp@-
@@ -224,7 +224,7 @@ ret_from_interrupt:
 2:
        RESTORE_ALL
 1:
-       moveb   %sp@(PT_SR), %d0
+       moveb   %sp@(PT_OFF_SR), %d0
        and     #7, %d0
        jhi     2b
 
index 55dfefe386427ea875bbf96b39dae967095ff514..6d3460a39cacf1383a16f2e66146c60aeecf6509 100644 (file)
 .globl inthandler
 
 badsys:
-       movel   #-ENOSYS,%sp@(PT_D0)
+       movel   #-ENOSYS,%sp@(PT_OFF_D0)
        jra     ret_from_exception
 
 do_trace:
-       movel   #-ENOSYS,%sp@(PT_D0)    /* needed for strace*/
+       movel   #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
        subql   #4,%sp
        SAVE_SWITCH_STACK
        jbsr    syscall_trace
        RESTORE_SWITCH_STACK
        addql   #4,%sp
-       movel   %sp@(PT_ORIG_D0),%d1
+       movel   %sp@(PT_OFF_ORIG_D0),%d1
        movel   #-ENOSYS,%d0
        cmpl    #NR_syscalls,%d1
        jcc     1f
@@ -53,7 +53,7 @@ do_trace:
        lea     sys_call_table, %a0
        jbsr    %a0@(%d1)
 
-1:     movel   %d0,%sp@(PT_D0)         /* save the return value */
+1:     movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
        subql   #4,%sp                  /* dummy return address */
        SAVE_SWITCH_STACK
        jbsr    syscall_trace
@@ -79,10 +79,10 @@ ENTRY(system_call)
        lea     sys_call_table,%a0
        movel   %a0@(%d0), %a0
        jbsr    %a0@
-       movel   %d0,%sp@(PT_D0)         /* save the return value*/
+       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value*/
 
 ret_from_exception:
-       btst    #5,%sp@(PT_SR)          /* check if returning to kernel*/
+       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel*/
        jeq     Luser_return            /* if so, skip resched, signals*/
 
 Lkernel_return:
@@ -124,7 +124,7 @@ Lreturn:
  */
 inthandler:
        SAVE_ALL
-       movew   %sp@(PT_VECTOR), %d0
+       movew   %sp@(PT_OFF_VECTOR), %d0
        and.l   #0x3ff, %d0
        lsr.l   #0x02,  %d0
 
@@ -139,7 +139,7 @@ ret_from_interrupt:
 2:
        RESTORE_ALL
 1:
-       moveb   %sp@(PT_SR), %d0
+       moveb   %sp@(PT_OFF_SR), %d0
        and     #7, %d0
        jhi     2b
        /* check if we need to do software interrupts */
index 3b471c0da24a0bd6232acbf98d5b7b6b0135217b..dd7d591f70eae6df0af6504428f2afbba503140d 100644 (file)
@@ -81,11 +81,11 @@ ENTRY(system_call)
 
        movel   %d3,%a0
        jbsr    %a0@
-       movel   %d0,%sp@(PT_D0)         /* save the return value */
+       movel   %d0,%sp@(PT_OFF_D0)     /* save the return value */
        jra     ret_from_exception
 1:
-       movel   #-ENOSYS,%d2            /* strace needs -ENOSYS in PT_D0 */
-       movel   %d2,PT_D0(%sp)          /* on syscall entry */
+       movel   #-ENOSYS,%d2            /* strace needs -ENOSYS in PT_OFF_D0 */
+       movel   %d2,PT_OFF_D0(%sp)      /* on syscall entry */
        subql   #4,%sp
        SAVE_SWITCH_STACK
        jbsr    syscall_trace
@@ -93,7 +93,7 @@ ENTRY(system_call)
        addql   #4,%sp
        movel   %d3,%a0
        jbsr    %a0@
-       movel   %d0,%sp@(PT_D0)         /* save the return value */
+       movel   %d0,%sp@(PT_OFF_D0)             /* save the return value */
        subql   #4,%sp                  /* dummy return address */
        SAVE_SWITCH_STACK
        jbsr    syscall_trace
@@ -104,7 +104,7 @@ ret_from_signal:
 
 ret_from_exception:
        move    #0x2700,%sr             /* disable intrs */
-       btst    #5,%sp@(PT_SR)          /* check if returning to kernel */
+       btst    #5,%sp@(PT_OFF_SR)      /* check if returning to kernel */
        jeq     Luser_return            /* if so, skip resched, signals */
 
 #ifdef CONFIG_PREEMPT
@@ -142,8 +142,8 @@ Luser_return:
 Lreturn:
        move    #0x2700,%sr             /* disable intrs */
        movel   sw_usp,%a0              /* get usp */
-       movel   %sp@(PT_PC),%a0@-       /* copy exception program counter */
-       movel   %sp@(PT_FORMATVEC),%a0@-/* copy exception format/vector/sr */
+       movel   %sp@(PT_OFF_PC),%a0@-   /* copy exception program counter */
+       movel   %sp@(PT_OFF_FORMATVEC),%a0@- /* copy exception format/vector/sr */
        moveml  %sp@,%d1-%d5/%a0-%a2
        lea     %sp@(32),%sp            /* space for 8 regs */
        movel   %sp@+,%d0
@@ -181,9 +181,9 @@ Lsignal_return:
 ENTRY(inthandler)
        SAVE_ALL
        moveq   #-1,%d0
-       movel   %d0,%sp@(PT_ORIG_D0)
+       movel   %d0,%sp@(PT_OFF_ORIG_D0)
 
-       movew   %sp@(PT_FORMATVEC),%d0  /* put exception # in d0 */
+       movew   %sp@(PT_OFF_FORMATVEC),%d0 /* put exception # in d0 */
        andl    #0x03fc,%d0             /* mask out vector only */
 
        movel   %sp,%sp@-               /* push regs arg */
@@ -203,7 +203,7 @@ ENTRY(inthandler)
 ENTRY(fasthandler)
        SAVE_LOCAL
 
-       movew   %sp@(PT_FORMATVEC),%d0
+       movew   %sp@(PT_OFF_FORMATVEC),%d0
        andl    #0x03fc,%d0             /* mask out vector only */
 
        movel   %sp,%sp@-               /* push regs arg */
index acc1f05d1e2c04665f2224d91bb9d61bb9929e48..e3ecb36dd554ebc3504e08ac369a29359e8c304f 100644 (file)
@@ -592,6 +592,8 @@ C_ENTRY(full_exception_trap):
        nop
        mfs     r7, rfsr;               /* save FSR */
        nop
+       mts     rfsr, r0;       /* Clear sticky fsr */
+       nop
        la      r12, r0, full_exception
        set_vms;
        rtbd    r12, 0;
index 6b0288ebccd6674c21c9ed0bee8a095903507412..2b86c03aa84187cb5857974fba2cb949e349ce93 100644 (file)
@@ -384,7 +384,7 @@ handle_other_ex: /* Handle Other exceptions here */
        addk    r8, r17, r0; /* Load exception address */
        bralid  r15, full_exception; /* Branch to the handler */
        nop;
-       mts     r0, rfsr;       /* Clear sticky fsr */
+       mts     rfsr, r0;       /* Clear sticky fsr */
        nop
 
        /*
index 4201c743cc9fb33e17a52ae057940345d79e2681..c592d475b3d890a50061f8f3b265c4516457d749 100644 (file)
@@ -235,7 +235,9 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
        regs->pc = pc;
        regs->r1 = usp;
        regs->pt_mode = 0;
+#ifdef CONFIG_MMU
        regs->msr |= MSR_UMS;
+#endif
 }
 
 #ifdef CONFIG_MMU
index 4f63ed8df55191517f819cacd3ec54f886a19941..162007643cdcb94faac5ceec465c095a2520be51 100644 (file)
@@ -7,17 +7,7 @@
 #ifndef __SPARC_HARDIRQ_H
 #define __SPARC_HARDIRQ_H
 
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/cache.h>
-
-/* entry.S is sensitive to the offsets of these fields */ /* XXX P3 Is it? */
-typedef struct {
-       unsigned int __softirq_pending;
-} ____cacheline_aligned irq_cpustat_t;
-
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
-
 #define HARDIRQ_BITS    8
+#include <asm-generic/hardirq.h>
 
 #endif /* __SPARC_HARDIRQ_H */
index ea43057d47633164b0100367a01f4c9f3ff67e12..cbf4801deaafc9c9bbb3cb11a3383c5e209a240d 100644 (file)
@@ -6,10 +6,10 @@
 #ifndef _SPARC_IRQ_H
 #define _SPARC_IRQ_H
 
-#include <linux/interrupt.h>
-
 #define NR_IRQS    16
 
+#include <linux/interrupt.h>
+
 #define irq_canonicalize(irq)  (irq)
 
 extern void __init init_IRQ(void);
index 0ff92fa22064f6a335233acfa39a72a6bfb88a4d..f3cb790fa2ae0771a4ac7b2b0ba7c73b14338111 100644 (file)
@@ -41,8 +41,8 @@
 #define LOW_OBP_ADDRESS                _AC(0x00000000f0000000,UL)
 #define HI_OBP_ADDRESS         _AC(0x0000000100000000,UL)
 #define VMALLOC_START          _AC(0x0000000100000000,UL)
-#define VMALLOC_END            _AC(0x0000000200000000,UL)
-#define VMEMMAP_BASE           _AC(0x0000000200000000,UL)
+#define VMALLOC_END            _AC(0x0000010000000000,UL)
+#define VMEMMAP_BASE           _AC(0x0000010000000000,UL)
 
 #define vmemmap                        ((struct page *)VMEMMAP_BASE)
 
index 3ea6e8cde8c5beba98f7460d199d8a9f128057c0..1d361477d7d639ebe871a8b36243cd42d689b54d 100644 (file)
@@ -280,8 +280,8 @@ kvmap_dtlb_nonlinear:
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
        /* Do not use the TSB for vmemmap.  */
-       mov             (VMEMMAP_BASE >> 24), %g5
-       sllx            %g5, 24, %g5
+       mov             (VMEMMAP_BASE >> 40), %g5
+       sllx            %g5, 40, %g5
        cmp             %g4,%g5
        bgeu,pn         %xcc, kvmap_vmemmap
         nop
@@ -293,8 +293,8 @@ kvmap_dtlb_tsbmiss:
        sethi           %hi(MODULES_VADDR), %g5
        cmp             %g4, %g5
        blu,pn          %xcc, kvmap_dtlb_longpath
-        mov            (VMALLOC_END >> 24), %g5
-       sllx            %g5, 24, %g5
+        mov            (VMALLOC_END >> 40), %g5
+       sllx            %g5, 40, %g5
        cmp             %g4, %g5
        bgeu,pn         %xcc, kvmap_dtlb_longpath
         nop
index 2d6a1b10c81da93a67d426fe1f1f4937e3eebc5a..04db9274389609e811ce2ba0b5a9e98cb3c57af1 100644 (file)
@@ -56,7 +56,8 @@ struct cpu_hw_events {
        struct perf_event       *events[MAX_HWEVENTS];
        unsigned long           used_mask[BITS_TO_LONGS(MAX_HWEVENTS)];
        unsigned long           active_mask[BITS_TO_LONGS(MAX_HWEVENTS)];
-       int enabled;
+       u64                     pcr;
+       int                     enabled;
 };
 DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, };
 
@@ -68,8 +69,30 @@ struct perf_event_map {
 #define PIC_LOWER      0x02
 };
 
+static unsigned long perf_event_encode(const struct perf_event_map *pmap)
+{
+       return ((unsigned long) pmap->encoding << 16) | pmap->pic_mask;
+}
+
+static void perf_event_decode(unsigned long val, u16 *enc, u8 *msk)
+{
+       *msk = val & 0xff;
+       *enc = val >> 16;
+}
+
+#define C(x) PERF_COUNT_HW_CACHE_##x
+
+#define CACHE_OP_UNSUPPORTED   0xfffe
+#define CACHE_OP_NONSENSE      0xffff
+
+typedef struct perf_event_map cache_map_t
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX];
+
 struct sparc_pmu {
        const struct perf_event_map     *(*event_map)(int);
+       const cache_map_t               *cache_map;
        int                             max_events;
        int                             upper_shift;
        int                             lower_shift;
@@ -80,21 +103,109 @@ struct sparc_pmu {
        int                             lower_nop;
 };
 
-static const struct perf_event_map ultra3i_perfmon_event_map[] = {
+static const struct perf_event_map ultra3_perfmon_event_map[] = {
        [PERF_COUNT_HW_CPU_CYCLES] = { 0x0000, PIC_UPPER | PIC_LOWER },
        [PERF_COUNT_HW_INSTRUCTIONS] = { 0x0001, PIC_UPPER | PIC_LOWER },
        [PERF_COUNT_HW_CACHE_REFERENCES] = { 0x0009, PIC_LOWER },
        [PERF_COUNT_HW_CACHE_MISSES] = { 0x0009, PIC_UPPER },
 };
 
-static const struct perf_event_map *ultra3i_event_map(int event_id)
+static const struct perf_event_map *ultra3_event_map(int event_id)
 {
-       return &ultra3i_perfmon_event_map[event_id];
+       return &ultra3_perfmon_event_map[event_id];
 }
 
-static const struct sparc_pmu ultra3i_pmu = {
-       .event_map      = ultra3i_event_map,
-       .max_events     = ARRAY_SIZE(ultra3i_perfmon_event_map),
+static const cache_map_t ultra3_cache_map = {
+[C(L1D)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { 0x09, PIC_LOWER, },
+               [C(RESULT_MISS)] = { 0x09, PIC_UPPER, },
+       },
+       [C(OP_WRITE)] = {
+               [C(RESULT_ACCESS)] = { 0x0a, PIC_LOWER },
+               [C(RESULT_MISS)] = { 0x0a, PIC_UPPER },
+       },
+       [C(OP_PREFETCH)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(L1I)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { 0x09, PIC_LOWER, },
+               [C(RESULT_MISS)] = { 0x09, PIC_UPPER, },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_NONSENSE },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_NONSENSE },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(LL)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { 0x0c, PIC_LOWER, },
+               [C(RESULT_MISS)] = { 0x0c, PIC_UPPER, },
+       },
+       [C(OP_WRITE)] = {
+               [C(RESULT_ACCESS)] = { 0x0c, PIC_LOWER },
+               [C(RESULT_MISS)] = { 0x0c, PIC_UPPER },
+       },
+       [C(OP_PREFETCH)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(DTLB)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { 0x12, PIC_UPPER, },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(ITLB)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { 0x11, PIC_UPPER, },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(BPU)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+};
+
+static const struct sparc_pmu ultra3_pmu = {
+       .event_map      = ultra3_event_map,
+       .cache_map      = &ultra3_cache_map,
+       .max_events     = ARRAY_SIZE(ultra3_perfmon_event_map),
        .upper_shift    = 11,
        .lower_shift    = 4,
        .event_mask     = 0x3f,
@@ -102,6 +213,121 @@ static const struct sparc_pmu ultra3i_pmu = {
        .lower_nop      = 0x14,
 };
 
+/* Niagara1 is very limited.  The upper PIC is hard-locked to count
+ * only instructions, so it is free running which creates all kinds of
+ * problems.  Some hardware designs make one wonder if the creator
+ * even looked at how this stuff gets used by software.
+ */
+static const struct perf_event_map niagara1_perfmon_event_map[] = {
+       [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, PIC_UPPER },
+       [PERF_COUNT_HW_INSTRUCTIONS] = { 0x00, PIC_UPPER },
+       [PERF_COUNT_HW_CACHE_REFERENCES] = { 0, PIC_NONE },
+       [PERF_COUNT_HW_CACHE_MISSES] = { 0x03, PIC_LOWER },
+};
+
+static const struct perf_event_map *niagara1_event_map(int event_id)
+{
+       return &niagara1_perfmon_event_map[event_id];
+}
+
+static const cache_map_t niagara1_cache_map = {
+[C(L1D)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { 0x03, PIC_LOWER, },
+       },
+       [C(OP_WRITE)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { 0x03, PIC_LOWER, },
+       },
+       [C(OP_PREFETCH)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(L1I)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { 0x00, PIC_UPPER },
+               [C(RESULT_MISS)] = { 0x02, PIC_LOWER, },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_NONSENSE },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_NONSENSE },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(LL)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { 0x07, PIC_LOWER, },
+       },
+       [C(OP_WRITE)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { 0x07, PIC_LOWER, },
+       },
+       [C(OP_PREFETCH)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(DTLB)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { 0x05, PIC_LOWER, },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(ITLB)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { 0x04, PIC_LOWER, },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(BPU)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+};
+
+static const struct sparc_pmu niagara1_pmu = {
+       .event_map      = niagara1_event_map,
+       .cache_map      = &niagara1_cache_map,
+       .max_events     = ARRAY_SIZE(niagara1_perfmon_event_map),
+       .upper_shift    = 0,
+       .lower_shift    = 4,
+       .event_mask     = 0x7,
+       .upper_nop      = 0x0,
+       .lower_nop      = 0x0,
+};
+
 static const struct perf_event_map niagara2_perfmon_event_map[] = {
        [PERF_COUNT_HW_CPU_CYCLES] = { 0x02ff, PIC_UPPER | PIC_LOWER },
        [PERF_COUNT_HW_INSTRUCTIONS] = { 0x02ff, PIC_UPPER | PIC_LOWER },
@@ -116,8 +342,96 @@ static const struct perf_event_map *niagara2_event_map(int event_id)
        return &niagara2_perfmon_event_map[event_id];
 }
 
+static const cache_map_t niagara2_cache_map = {
+[C(L1D)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { 0x0208, PIC_UPPER | PIC_LOWER, },
+               [C(RESULT_MISS)] = { 0x0302, PIC_UPPER | PIC_LOWER, },
+       },
+       [C(OP_WRITE)] = {
+               [C(RESULT_ACCESS)] = { 0x0210, PIC_UPPER | PIC_LOWER, },
+               [C(RESULT_MISS)] = { 0x0302, PIC_UPPER | PIC_LOWER, },
+       },
+       [C(OP_PREFETCH)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(L1I)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { 0x02ff, PIC_UPPER | PIC_LOWER, },
+               [C(RESULT_MISS)] = { 0x0301, PIC_UPPER | PIC_LOWER, },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_NONSENSE },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_NONSENSE },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(LL)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { 0x0208, PIC_UPPER | PIC_LOWER, },
+               [C(RESULT_MISS)] = { 0x0330, PIC_UPPER | PIC_LOWER, },
+       },
+       [C(OP_WRITE)] = {
+               [C(RESULT_ACCESS)] = { 0x0210, PIC_UPPER | PIC_LOWER, },
+               [C(RESULT_MISS)] = { 0x0320, PIC_UPPER | PIC_LOWER, },
+       },
+       [C(OP_PREFETCH)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(DTLB)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { 0x0b08, PIC_UPPER | PIC_LOWER, },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(ITLB)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { 0xb04, PIC_UPPER | PIC_LOWER, },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+[C(BPU)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+               [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_WRITE) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+       [ C(OP_PREFETCH) ] = {
+               [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+               [ C(RESULT_MISS)   ] = { CACHE_OP_UNSUPPORTED },
+       },
+},
+};
+
 static const struct sparc_pmu niagara2_pmu = {
        .event_map      = niagara2_event_map,
+       .cache_map      = &niagara2_cache_map,
        .max_events     = ARRAY_SIZE(niagara2_perfmon_event_map),
        .upper_shift    = 19,
        .lower_shift    = 6,
@@ -151,23 +465,30 @@ static u64 nop_for_index(int idx)
                              sparc_pmu->lower_nop, idx);
 }
 
-static inline void sparc_pmu_enable_event(struct hw_perf_event *hwc,
-                                           int idx)
+static inline void sparc_pmu_enable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx)
 {
        u64 val, mask = mask_for_index(idx);
 
-       val = pcr_ops->read();
-       pcr_ops->write((val & ~mask) | hwc->config);
+       val = cpuc->pcr;
+       val &= ~mask;
+       val |= hwc->config;
+       cpuc->pcr = val;
+
+       pcr_ops->write(cpuc->pcr);
 }
 
-static inline void sparc_pmu_disable_event(struct hw_perf_event *hwc,
-                                            int idx)
+static inline void sparc_pmu_disable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx)
 {
        u64 mask = mask_for_index(idx);
        u64 nop = nop_for_index(idx);
-       u64 val = pcr_ops->read();
+       u64 val;
 
-       pcr_ops->write((val & ~mask) | nop);
+       val = cpuc->pcr;
+       val &= ~mask;
+       val |= nop;
+       cpuc->pcr = val;
+
+       pcr_ops->write(cpuc->pcr);
 }
 
 void hw_perf_enable(void)
@@ -182,7 +503,7 @@ void hw_perf_enable(void)
        cpuc->enabled = 1;
        barrier();
 
-       val = pcr_ops->read();
+       val = cpuc->pcr;
 
        for (i = 0; i < MAX_HWEVENTS; i++) {
                struct perf_event *cp = cpuc->events[i];
@@ -194,7 +515,9 @@ void hw_perf_enable(void)
                val |= hwc->config_base;
        }
 
-       pcr_ops->write(val);
+       cpuc->pcr = val;
+
+       pcr_ops->write(cpuc->pcr);
 }
 
 void hw_perf_disable(void)
@@ -207,10 +530,12 @@ void hw_perf_disable(void)
 
        cpuc->enabled = 0;
 
-       val = pcr_ops->read();
+       val = cpuc->pcr;
        val &= ~(PCR_UTRACE | PCR_STRACE |
                 sparc_pmu->hv_bit | sparc_pmu->irq_bit);
-       pcr_ops->write(val);
+       cpuc->pcr = val;
+
+       pcr_ops->write(cpuc->pcr);
 }
 
 static u32 read_pmc(int idx)
@@ -242,7 +567,7 @@ static void write_pmc(int idx, u64 val)
 }
 
 static int sparc_perf_event_set_period(struct perf_event *event,
-                                        struct hw_perf_event *hwc, int idx)
+                                      struct hw_perf_event *hwc, int idx)
 {
        s64 left = atomic64_read(&hwc->period_left);
        s64 period = hwc->sample_period;
@@ -282,19 +607,19 @@ static int sparc_pmu_enable(struct perf_event *event)
        if (test_and_set_bit(idx, cpuc->used_mask))
                return -EAGAIN;
 
-       sparc_pmu_disable_event(hwc, idx);
+       sparc_pmu_disable_event(cpuc, hwc, idx);
 
        cpuc->events[idx] = event;
        set_bit(idx, cpuc->active_mask);
 
        sparc_perf_event_set_period(event, hwc, idx);
-       sparc_pmu_enable_event(hwc, idx);
+       sparc_pmu_enable_event(cpuc, hwc, idx);
        perf_event_update_userpage(event);
        return 0;
 }
 
 static u64 sparc_perf_event_update(struct perf_event *event,
-                                    struct hw_perf_event *hwc, int idx)
+                                  struct hw_perf_event *hwc, int idx)
 {
        int shift = 64 - 32;
        u64 prev_raw_count, new_raw_count;
@@ -324,7 +649,7 @@ static void sparc_pmu_disable(struct perf_event *event)
        int idx = hwc->idx;
 
        clear_bit(idx, cpuc->active_mask);
-       sparc_pmu_disable_event(hwc, idx);
+       sparc_pmu_disable_event(cpuc, hwc, idx);
 
        barrier();
 
@@ -338,18 +663,29 @@ static void sparc_pmu_disable(struct perf_event *event)
 static void sparc_pmu_read(struct perf_event *event)
 {
        struct hw_perf_event *hwc = &event->hw;
+
        sparc_perf_event_update(event, hwc, hwc->idx);
 }
 
 static void sparc_pmu_unthrottle(struct perf_event *event)
 {
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
-       sparc_pmu_enable_event(hwc, hwc->idx);
+
+       sparc_pmu_enable_event(cpuc, hwc, hwc->idx);
 }
 
 static atomic_t active_events = ATOMIC_INIT(0);
 static DEFINE_MUTEX(pmc_grab_mutex);
 
+static void perf_stop_nmi_watchdog(void *unused)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+       stop_nmi_watchdog(NULL);
+       cpuc->pcr = pcr_ops->read();
+}
+
 void perf_event_grab_pmc(void)
 {
        if (atomic_inc_not_zero(&active_events))
@@ -358,7 +694,7 @@ void perf_event_grab_pmc(void)
        mutex_lock(&pmc_grab_mutex);
        if (atomic_read(&active_events) == 0) {
                if (atomic_read(&nmi_active) > 0) {
-                       on_each_cpu(stop_nmi_watchdog, NULL, 1);
+                       on_each_cpu(perf_stop_nmi_watchdog, NULL, 1);
                        BUG_ON(atomic_read(&nmi_active) != 0);
                }
                atomic_inc(&active_events);
@@ -375,30 +711,160 @@ void perf_event_release_pmc(void)
        }
 }
 
+static const struct perf_event_map *sparc_map_cache_event(u64 config)
+{
+       unsigned int cache_type, cache_op, cache_result;
+       const struct perf_event_map *pmap;
+
+       if (!sparc_pmu->cache_map)
+               return ERR_PTR(-ENOENT);
+
+       cache_type = (config >>  0) & 0xff;
+       if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
+               return ERR_PTR(-EINVAL);
+
+       cache_op = (config >>  8) & 0xff;
+       if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
+               return ERR_PTR(-EINVAL);
+
+       cache_result = (config >> 16) & 0xff;
+       if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+               return ERR_PTR(-EINVAL);
+
+       pmap = &((*sparc_pmu->cache_map)[cache_type][cache_op][cache_result]);
+
+       if (pmap->encoding == CACHE_OP_UNSUPPORTED)
+               return ERR_PTR(-ENOENT);
+
+       if (pmap->encoding == CACHE_OP_NONSENSE)
+               return ERR_PTR(-EINVAL);
+
+       return pmap;
+}
+
 static void hw_perf_event_destroy(struct perf_event *event)
 {
        perf_event_release_pmc();
 }
 
+/* Make sure all events can be scheduled into the hardware at
+ * the same time.  This is simplified by the fact that we only
+ * need to support 2 simultaneous HW events.
+ */
+static int sparc_check_constraints(unsigned long *events, int n_ev)
+{
+       if (n_ev <= perf_max_events) {
+               u8 msk1, msk2;
+               u16 dummy;
+
+               if (n_ev == 1)
+                       return 0;
+               BUG_ON(n_ev != 2);
+               perf_event_decode(events[0], &dummy, &msk1);
+               perf_event_decode(events[1], &dummy, &msk2);
+
+               /* If both events can go on any counter, OK.  */
+               if (msk1 == (PIC_UPPER | PIC_LOWER) &&
+                   msk2 == (PIC_UPPER | PIC_LOWER))
+                       return 0;
+
+               /* If one event is limited to a specific counter,
+                * and the other can go on both, OK.
+                */
+               if ((msk1 == PIC_UPPER || msk1 == PIC_LOWER) &&
+                   msk2 == (PIC_UPPER | PIC_LOWER))
+                       return 0;
+               if ((msk2 == PIC_UPPER || msk2 == PIC_LOWER) &&
+                   msk1 == (PIC_UPPER | PIC_LOWER))
+                       return 0;
+
+               /* If the events are fixed to different counters, OK.  */
+               if ((msk1 == PIC_UPPER && msk2 == PIC_LOWER) ||
+                   (msk1 == PIC_LOWER && msk2 == PIC_UPPER))
+                       return 0;
+
+               /* Otherwise, there is a conflict.  */
+       }
+
+       return -1;
+}
+
+static int check_excludes(struct perf_event **evts, int n_prev, int n_new)
+{
+       int eu = 0, ek = 0, eh = 0;
+       struct perf_event *event;
+       int i, n, first;
+
+       n = n_prev + n_new;
+       if (n <= 1)
+               return 0;
+
+       first = 1;
+       for (i = 0; i < n; i++) {
+               event = evts[i];
+               if (first) {
+                       eu = event->attr.exclude_user;
+                       ek = event->attr.exclude_kernel;
+                       eh = event->attr.exclude_hv;
+                       first = 0;
+               } else if (event->attr.exclude_user != eu ||
+                          event->attr.exclude_kernel != ek ||
+                          event->attr.exclude_hv != eh) {
+                       return -EAGAIN;
+               }
+       }
+
+       return 0;
+}
+
+static int collect_events(struct perf_event *group, int max_count,
+                         struct perf_event *evts[], unsigned long *events)
+{
+       struct perf_event *event;
+       int n = 0;
+
+       if (!is_software_event(group)) {
+               if (n >= max_count)
+                       return -1;
+               evts[n] = group;
+               events[n++] = group->hw.event_base;
+       }
+       list_for_each_entry(event, &group->sibling_list, group_entry) {
+               if (!is_software_event(event) &&
+                   event->state != PERF_EVENT_STATE_OFF) {
+                       if (n >= max_count)
+                               return -1;
+                       evts[n] = event;
+                       events[n++] = event->hw.event_base;
+               }
+       }
+       return n;
+}
+
 static int __hw_perf_event_init(struct perf_event *event)
 {
        struct perf_event_attr *attr = &event->attr;
+       struct perf_event *evts[MAX_HWEVENTS];
        struct hw_perf_event *hwc = &event->hw;
+       unsigned long events[MAX_HWEVENTS];
        const struct perf_event_map *pmap;
        u64 enc;
+       int n;
 
        if (atomic_read(&nmi_active) < 0)
                return -ENODEV;
 
-       if (attr->type != PERF_TYPE_HARDWARE)
+       if (attr->type == PERF_TYPE_HARDWARE) {
+               if (attr->config >= sparc_pmu->max_events)
+                       return -EINVAL;
+               pmap = sparc_pmu->event_map(attr->config);
+       } else if (attr->type == PERF_TYPE_HW_CACHE) {
+               pmap = sparc_map_cache_event(attr->config);
+               if (IS_ERR(pmap))
+                       return PTR_ERR(pmap);
+       } else
                return -EOPNOTSUPP;
 
-       if (attr->config >= sparc_pmu->max_events)
-               return -EINVAL;
-
-       perf_event_grab_pmc();
-       event->destroy = hw_perf_event_destroy;
-
        /* We save the enable bits in the config_base.  So to
         * turn off sampling just write 'config', and to enable
         * things write 'config | config_base'.
@@ -411,15 +877,39 @@ static int __hw_perf_event_init(struct perf_event *event)
        if (!attr->exclude_hv)
                hwc->config_base |= sparc_pmu->hv_bit;
 
+       hwc->event_base = perf_event_encode(pmap);
+
+       enc = pmap->encoding;
+
+       n = 0;
+       if (event->group_leader != event) {
+               n = collect_events(event->group_leader,
+                                  perf_max_events - 1,
+                                  evts, events);
+               if (n < 0)
+                       return -EINVAL;
+       }
+       events[n] = hwc->event_base;
+       evts[n] = event;
+
+       if (check_excludes(evts, n, 1))
+               return -EINVAL;
+
+       if (sparc_check_constraints(events, n + 1))
+               return -EINVAL;
+
+       /* Try to do all error checking before this point, as unwinding
+        * state after grabbing the PMC is difficult.
+        */
+       perf_event_grab_pmc();
+       event->destroy = hw_perf_event_destroy;
+
        if (!hwc->sample_period) {
                hwc->sample_period = MAX_PERIOD;
                hwc->last_period = hwc->sample_period;
                atomic64_set(&hwc->period_left, hwc->sample_period);
        }
 
-       pmap = sparc_pmu->event_map(attr->config);
-
-       enc = pmap->encoding;
        if (pmap->pic_mask & PIC_UPPER) {
                hwc->idx = PIC_UPPER_INDEX;
                enc <<= sparc_pmu->upper_shift;
@@ -472,7 +962,7 @@ void perf_event_print_debug(void)
 }
 
 static int __kprobes perf_event_nmi_handler(struct notifier_block *self,
-                                             unsigned long cmd, void *__args)
+                                           unsigned long cmd, void *__args)
 {
        struct die_args *args = __args;
        struct perf_sample_data data;
@@ -513,7 +1003,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self,
                        continue;
 
                if (perf_event_overflow(event, 1, &data, regs))
-                       sparc_pmu_disable_event(hwc, idx);
+                       sparc_pmu_disable_event(cpuc, hwc, idx);
        }
 
        return NOTIFY_STOP;
@@ -525,8 +1015,15 @@ static __read_mostly struct notifier_block perf_event_nmi_notifier = {
 
 static bool __init supported_pmu(void)
 {
-       if (!strcmp(sparc_pmu_type, "ultra3i")) {
-               sparc_pmu = &ultra3i_pmu;
+       if (!strcmp(sparc_pmu_type, "ultra3") ||
+           !strcmp(sparc_pmu_type, "ultra3+") ||
+           !strcmp(sparc_pmu_type, "ultra3i") ||
+           !strcmp(sparc_pmu_type, "ultra4+")) {
+               sparc_pmu = &ultra3_pmu;
+               return true;
+       }
+       if (!strcmp(sparc_pmu_type, "niagara")) {
+               sparc_pmu = &niagara1_pmu;
                return true;
        }
        if (!strcmp(sparc_pmu_type, "niagara2")) {
index f97cb8b6ee5fec51b5f20d572357442e340115be..f9024bccff163f06fcca11054865b885086dc8c0 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/oprofile.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/param.h>       /* for HZ */
  
 #ifdef CONFIG_SPARC64
 #include <linux/notifier.h>
index 8da93745c08790f8e8fa431b010f3ba08fd49a9b..c876bace8fdc95a1bc9ce31abbfe68247c1ac309 100644 (file)
@@ -86,10 +86,6 @@ config STACKTRACE_SUPPORT
 config HAVE_LATENCYTOP_SUPPORT
        def_bool y
 
-config FAST_CMPXCHG_LOCAL
-       bool
-       default y
-
 config MMU
        def_bool y
 
index 527519b8a9f9997241eb5897f316cdbe855bb341..f2824fb8c79cad23ad747977e1e32ab4d6b555a1 100644 (file)
@@ -400,7 +400,7 @@ config X86_TSC
 
 config X86_CMPXCHG64
        def_bool y
-       depends on X86_PAE || X86_64
+       depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM
 
 # this should be set for all -march=.. options where the compiler
 # generates cmov.
@@ -412,6 +412,7 @@ config X86_MINIMUM_CPU_FAMILY
        int
        default "64" if X86_64
        default "6" if X86_32 && X86_P6_NOP
+       default "5" if X86_32 && X86_CMPXCHG64
        default "4" if X86_32 && (X86_XADD || X86_CMPXCHG || X86_BSWAP || X86_WP_WORKS_OK)
        default "3"
 
index 74619c4f9fda82652b37cfd3edbd6a52f6845fa7..1733f9f65e8259d74fc74fc40b466bd69dc6fa87 100644 (file)
@@ -21,8 +21,8 @@
 #define __AUDIT_ARCH_LE           0x40000000
 
 #ifndef CONFIG_AUDITSYSCALL
-#define sysexit_audit int_ret_from_sys_call
-#define sysretl_audit int_ret_from_sys_call
+#define sysexit_audit ia32_ret_from_sys_call
+#define sysretl_audit ia32_ret_from_sys_call
 #endif
 
 #define IA32_NR_syscalls ((ia32_syscall_end - ia32_sys_call_table)/8)
        .endm 
 
        /* clobbers %eax */     
-       .macro  CLEAR_RREGS _r9=rax
+       .macro  CLEAR_RREGS offset=0, _r9=rax
        xorl    %eax,%eax
-       movq    %rax,R11(%rsp)
-       movq    %rax,R10(%rsp)
-       movq    %\_r9,R9(%rsp)
-       movq    %rax,R8(%rsp)
+       movq    %rax,\offset+R11(%rsp)
+       movq    %rax,\offset+R10(%rsp)
+       movq    %\_r9,\offset+R9(%rsp)
+       movq    %rax,\offset+R8(%rsp)
        .endm
 
        /*
@@ -172,6 +172,10 @@ sysexit_from_sys_call:
        movl    RIP-R11(%rsp),%edx              /* User %eip */
        CFI_REGISTER rip,rdx
        RESTORE_ARGS 1,24,1,1,1,1
+       xorq    %r8,%r8
+       xorq    %r9,%r9
+       xorq    %r10,%r10
+       xorq    %r11,%r11
        popfq
        CFI_ADJUST_CFA_OFFSET -8
        /*CFI_RESTORE rflags*/
@@ -202,7 +206,7 @@ sysexit_from_sys_call:
 
        .macro auditsys_exit exit,ebpsave=RBP
        testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),TI_flags(%r10)
-       jnz int_ret_from_sys_call
+       jnz ia32_ret_from_sys_call
        TRACE_IRQS_ON
        sti
        movl %eax,%esi          /* second arg, syscall return value */
@@ -218,8 +222,9 @@ sysexit_from_sys_call:
        cli
        TRACE_IRQS_OFF
        testl %edi,TI_flags(%r10)
-       jnz int_with_check
-       jmp \exit
+       jz \exit
+       CLEAR_RREGS -ARGOFFSET
+       jmp int_with_check
        .endm
 
 sysenter_auditsys:
@@ -329,6 +334,9 @@ sysretl_from_sys_call:
        CFI_REGISTER rip,rcx
        movl EFLAGS-ARGOFFSET(%rsp),%r11d       
        /*CFI_REGISTER rflags,r11*/
+       xorq    %r10,%r10
+       xorq    %r9,%r9
+       xorq    %r8,%r8
        TRACE_IRQS_ON
        movl RSP-ARGOFFSET(%rsp),%esp
        CFI_RESTORE rsp
@@ -353,7 +361,7 @@ cstar_tracesys:
 #endif
        xchgl %r9d,%ebp
        SAVE_REST
-       CLEAR_RREGS r9
+       CLEAR_RREGS 0, r9
        movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
        movq %rsp,%rdi        /* &pt_regs -> arg1 */
        call syscall_trace_enter
@@ -425,6 +433,8 @@ ia32_do_call:
        call *ia32_sys_call_table(,%rax,8) # xxx: rip relative
 ia32_sysret:
        movq %rax,RAX-ARGOFFSET(%rsp)
+ia32_ret_from_sys_call:
+       CLEAR_RREGS -ARGOFFSET
        jmp int_ret_from_sys_call 
 
 ia32_tracesys:                  
@@ -442,8 +452,8 @@ END(ia32_syscall)
 
 ia32_badsys:
        movq $0,ORIG_RAX-ARGOFFSET(%rsp)
-       movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
-       jmp int_ret_from_sys_call
+       movq $-ENOSYS,%rax
+       jmp ia32_sysret
 
 quiet_ni_syscall:
        movq $-ENOSYS,%rax
index 41fd965c80c6d41caefd801ee16948d23214d905..b9c830c12b4ac1de45d137a736be6de7fbd19fb4 100644 (file)
@@ -206,8 +206,11 @@ static int __init setup_early_printk(char *buf)
 
        while (*buf != '\0') {
                if (!strncmp(buf, "serial", 6)) {
-                       early_serial_init(buf + 6);
+                       buf += 6;
+                       early_serial_init(buf);
                        early_console_register(&early_serial_console, keep);
+                       if (!strncmp(buf, ",ttyS", 5))
+                               buf += 5;
                }
                if (!strncmp(buf, "ttyS", 4)) {
                        early_serial_init(buf + 4);
index 1736c5a725aafe21959f4903d721788d1cc0354c..9c3bd4a2050e802a62ff13dfc52e855e641a802b 100644 (file)
@@ -15,8 +15,10 @@ EXPORT_SYMBOL(mcount);
  * the export, but dont use it from C code, it is used
  * by assembly code and is not using C calling convention!
  */
+#ifndef CONFIG_X86_CMPXCHG64
 extern void cmpxchg8b_emu(void);
 EXPORT_SYMBOL(cmpxchg8b_emu);
+#endif
 
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy_generic);
index 3e549b8ec8c9da4ebf3c02db2289196abc0a5b1b..85f5db95c60f03718f292080587f7faa337ef570 100644 (file)
@@ -15,8 +15,10 @@ ifeq ($(CONFIG_X86_32),y)
         obj-y += atomic64_32.o
         lib-y += checksum_32.o
         lib-y += strstr_32.o
-        lib-y += semaphore_32.o string_32.o cmpxchg8b_emu.o
-
+        lib-y += semaphore_32.o string_32.o
+ifneq ($(CONFIG_X86_CMPXCHG64),y)
+        lib-y += cmpxchg8b_emu.o
+endif
         lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o
 else
         obj-y += io_64.o iomap_copy_64.o
index 6593ab39cfe9223b106d3b5a897937e58176e6b1..8873b9b439ffdb0bf695b0077f84bb28c1046a38 100644 (file)
@@ -350,6 +350,7 @@ static void blkdev_discard_end_io(struct bio *bio, int err)
 
        if (bio->bi_private)
                complete(bio->bi_private);
+       __free_page(bio_page(bio));
 
        bio_put(bio);
 }
@@ -372,30 +373,50 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
        struct request_queue *q = bdev_get_queue(bdev);
        int type = flags & DISCARD_FL_BARRIER ?
                DISCARD_BARRIER : DISCARD_NOBARRIER;
+       struct bio *bio;
+       struct page *page;
        int ret = 0;
 
        if (!q)
                return -ENXIO;
 
-       if (!q->prepare_discard_fn)
+       if (!blk_queue_discard(q))
                return -EOPNOTSUPP;
 
        while (nr_sects && !ret) {
-               struct bio *bio = bio_alloc(gfp_mask, 0);
-               if (!bio)
-                       return -ENOMEM;
+               unsigned int sector_size = q->limits.logical_block_size;
+               unsigned int max_discard_sectors =
+                       min(q->limits.max_discard_sectors, UINT_MAX >> 9);
 
+               bio = bio_alloc(gfp_mask, 1);
+               if (!bio)
+                       goto out;
+               bio->bi_sector = sector;
                bio->bi_end_io = blkdev_discard_end_io;
                bio->bi_bdev = bdev;
                if (flags & DISCARD_FL_WAIT)
                        bio->bi_private = &wait;
 
-               bio->bi_sector = sector;
+               /*
+                * Add a zeroed one-sector payload as that's what
+                * our current implementations need.  If we'll ever need
+                * more the interface will need revisiting.
+                */
+               page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+               if (!page)
+                       goto out_free_bio;
+               if (bio_add_pc_page(q, bio, page, sector_size, 0) < sector_size)
+                       goto out_free_page;
 
-               if (nr_sects > queue_max_hw_sectors(q)) {
-                       bio->bi_size = queue_max_hw_sectors(q) << 9;
-                       nr_sects -= queue_max_hw_sectors(q);
-                       sector += queue_max_hw_sectors(q);
+               /*
+                * And override the bio size - the way discard works we
+                * touch many more blocks on disk than the actual payload
+                * length.
+                */
+               if (nr_sects > max_discard_sectors) {
+                       bio->bi_size = max_discard_sectors << 9;
+                       nr_sects -= max_discard_sectors;
+                       sector += max_discard_sectors;
                } else {
                        bio->bi_size = nr_sects << 9;
                        nr_sects = 0;
@@ -414,5 +435,11 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
                bio_put(bio);
        }
        return ret;
+out_free_page:
+       __free_page(page);
+out_free_bio:
+       bio_put(bio);
+out:
+       return -ENOMEM;
 }
 EXPORT_SYMBOL(blkdev_issue_discard);
index 8135228e4b2907e15f8a8ff5199de3fa8e5f40cd..81f34311659a21cc172d3ce3dde996643941e5eb 100644 (file)
@@ -34,6 +34,7 @@
 #include "blk.h"
 
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_remap);
+EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete);
 
 static int __make_request(struct request_queue *q, struct bio *bio);
@@ -69,7 +70,7 @@ static void drive_stat_acct(struct request *rq, int new_io)
                part_stat_inc(cpu, part, merges[rw]);
        else {
                part_round_stats(cpu, part);
-               part_inc_in_flight(part, rw);
+               part_inc_in_flight(part);
        }
 
        part_stat_unlock();
@@ -1031,7 +1032,7 @@ static void part_round_stats_single(int cpu, struct hd_struct *part,
 
        if (part->in_flight) {
                __part_stat_add(cpu, part, time_in_queue,
-                               part_in_flight(part) * (now - part->stamp));
+                               part->in_flight * (now - part->stamp));
                __part_stat_add(cpu, part, io_ticks, (now - part->stamp));
        }
        part->stamp = now;
@@ -1124,7 +1125,6 @@ void init_request_from_bio(struct request *req, struct bio *bio)
                req->cmd_flags |= REQ_DISCARD;
                if (bio_rw_flagged(bio, BIO_RW_BARRIER))
                        req->cmd_flags |= REQ_SOFTBARRIER;
-               req->q->prepare_discard_fn(req->q, req);
        } else if (unlikely(bio_rw_flagged(bio, BIO_RW_BARRIER)))
                req->cmd_flags |= REQ_HARDBARRIER;
 
@@ -1437,7 +1437,8 @@ static inline void __generic_make_request(struct bio *bio)
                        goto end_io;
                }
 
-               if (unlikely(nr_sectors > queue_max_hw_sectors(q))) {
+               if (unlikely(!bio_rw_flagged(bio, BIO_RW_DISCARD) &&
+                            nr_sectors > queue_max_hw_sectors(q))) {
                        printk(KERN_ERR "bio too big device %s (%u > %u)\n",
                               bdevname(bio->bi_bdev, b),
                               bio_sectors(bio),
@@ -1470,7 +1471,7 @@ static inline void __generic_make_request(struct bio *bio)
                        goto end_io;
 
                if (bio_rw_flagged(bio, BIO_RW_DISCARD) &&
-                   !q->prepare_discard_fn) {
+                   !blk_queue_discard(q)) {
                        err = -EOPNOTSUPP;
                        goto end_io;
                }
@@ -1738,7 +1739,7 @@ static void blk_account_io_done(struct request *req)
                part_stat_inc(cpu, part, ios[rw]);
                part_stat_add(cpu, part, ticks[rw], duration);
                part_round_stats(cpu, part);
-               part_dec_in_flight(part, rw);
+               part_dec_in_flight(part);
 
                part_stat_unlock();
        }
@@ -2491,6 +2492,14 @@ int kblockd_schedule_work(struct request_queue *q, struct work_struct *work)
 }
 EXPORT_SYMBOL(kblockd_schedule_work);
 
+int kblockd_schedule_delayed_work(struct request_queue *q,
+                                 struct delayed_work *work,
+                                 unsigned long delay)
+{
+       return queue_delayed_work(kblockd_workqueue, work, delay);
+}
+EXPORT_SYMBOL(kblockd_schedule_delayed_work);
+
 int __init blk_dev_init(void)
 {
        BUILD_BUG_ON(__REQ_NR_BITS > 8 *
index 99cb5cf1f447fa8759d73f06bf64fe4b20eec580..b0de8574fdc84e40e1bdf87dea4eb1af98769bb4 100644 (file)
@@ -351,7 +351,7 @@ static void blk_account_io_merge(struct request *req)
                part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
 
                part_round_stats(cpu, part);
-               part_dec_in_flight(part, rq_data_dir(req));
+               part_dec_in_flight(part);
 
                part_stat_unlock();
        }
index 83413ff837397a88bf8e5a8bbc1cb9652c0dd50f..e0695bca702777d7455e9d4266590be47977443e 100644 (file)
@@ -33,23 +33,6 @@ void blk_queue_prep_rq(struct request_queue *q, prep_rq_fn *pfn)
 }
 EXPORT_SYMBOL(blk_queue_prep_rq);
 
-/**
- * blk_queue_set_discard - set a discard_sectors function for queue
- * @q:         queue
- * @dfn:       prepare_discard function
- *
- * It's possible for a queue to register a discard callback which is used
- * to transform a discard request into the appropriate type for the
- * hardware. If none is registered, then discard requests are failed
- * with %EOPNOTSUPP.
- *
- */
-void blk_queue_set_discard(struct request_queue *q, prepare_discard_fn *dfn)
-{
-       q->prepare_discard_fn = dfn;
-}
-EXPORT_SYMBOL(blk_queue_set_discard);
-
 /**
  * blk_queue_merge_bvec - set a merge_bvec function for queue
  * @q:         queue
@@ -111,7 +94,9 @@ void blk_set_default_limits(struct queue_limits *lim)
        lim->max_hw_segments = MAX_HW_SEGMENTS;
        lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
        lim->max_segment_size = MAX_SEGMENT_SIZE;
-       lim->max_sectors = lim->max_hw_sectors = SAFE_MAX_SECTORS;
+       lim->max_sectors = BLK_DEF_MAX_SECTORS;
+       lim->max_hw_sectors = INT_MAX;
+       lim->max_discard_sectors = SAFE_MAX_SECTORS;
        lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
        lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT);
        lim->alignment_offset = 0;
@@ -164,6 +149,7 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
        q->unplug_timer.data = (unsigned long)q;
 
        blk_set_default_limits(&q->limits);
+       blk_queue_max_sectors(q, SAFE_MAX_SECTORS);
 
        /*
         * If the caller didn't supply a lock, fall back to our embedded
@@ -253,6 +239,18 @@ void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_sectors)
 }
 EXPORT_SYMBOL(blk_queue_max_hw_sectors);
 
+/**
+ * blk_queue_max_discard_sectors - set max sectors for a single discard
+ * @q:  the request queue for the device
+ * @max_discard: maximum number of sectors to discard
+ **/
+void blk_queue_max_discard_sectors(struct request_queue *q,
+               unsigned int max_discard_sectors)
+{
+       q->limits.max_discard_sectors = max_discard_sectors;
+}
+EXPORT_SYMBOL(blk_queue_max_discard_sectors);
+
 /**
  * blk_queue_max_phys_segments - set max phys segments for a request for this queue
  * @q:  the request queue for the device
index b78c9c3e26705f45fb1e90ac116dc8bb96c8122b..8a6d81afb284ebbf7111653393b6594d91924491 100644 (file)
@@ -452,6 +452,7 @@ int blk_register_queue(struct gendisk *disk)
        if (ret) {
                kobject_uevent(&q->kobj, KOBJ_REMOVE);
                kobject_del(&q->kobj);
+               blk_trace_remove_sysfs(disk_to_dev(disk));
                return ret;
        }
 
@@ -465,11 +466,11 @@ void blk_unregister_queue(struct gendisk *disk)
        if (WARN_ON(!q))
                return;
 
-       if (q->request_fn) {
+       if (q->request_fn)
                elv_unregister_queue(q);
 
-               kobject_uevent(&q->kobj, KOBJ_REMOVE);
-               kobject_del(&q->kobj);
-               kobject_put(&disk_to_dev(disk)->kobj);
-       }
+       kobject_uevent(&q->kobj, KOBJ_REMOVE);
+       kobject_del(&q->kobj);
+       blk_trace_remove_sysfs(disk_to_dev(disk));
+       kobject_put(&disk_to_dev(disk)->kobj);
 }
index 1ca813b16e7840cf10086d79b7e2bb7b0c07005e..9c4b679908f41cf034cdddc79a9bff8bcb1f4e85 100644 (file)
@@ -150,7 +150,7 @@ struct cfq_data {
         * idle window management
         */
        struct timer_list idle_slice_timer;
-       struct work_struct unplug_work;
+       struct delayed_work unplug_work;
 
        struct cfq_queue *active_queue;
        struct cfq_io_context *active_cic;
@@ -173,6 +173,7 @@ struct cfq_data {
        unsigned int cfq_slice[2];
        unsigned int cfq_slice_async_rq;
        unsigned int cfq_slice_idle;
+       unsigned int cfq_latency;
 
        struct list_head cic_list;
 
@@ -180,6 +181,8 @@ struct cfq_data {
         * Fallback dummy cfqq for extreme OOM conditions
         */
        struct cfq_queue oom_cfqq;
+
+       unsigned long last_end_sync_rq;
 };
 
 enum cfqq_state_flags {
@@ -265,11 +268,13 @@ static inline int cfq_bio_sync(struct bio *bio)
  * scheduler run of queue, if there are requests pending and no one in the
  * driver that will restart queueing
  */
-static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
+static inline void cfq_schedule_dispatch(struct cfq_data *cfqd,
+                                        unsigned long delay)
 {
        if (cfqd->busy_queues) {
                cfq_log(cfqd, "schedule dispatch");
-               kblockd_schedule_work(cfqd->queue, &cfqd->unplug_work);
+               kblockd_schedule_delayed_work(cfqd->queue, &cfqd->unplug_work,
+                                               delay);
        }
 }
 
@@ -1326,12 +1331,30 @@ static int cfq_dispatch_requests(struct request_queue *q, int force)
                        return 0;
 
                /*
-                * we are the only queue, allow up to 4 times of 'quantum'
+                * Sole queue user, allow bigger slice
                 */
-               if (cfqq->dispatched >= 4 * max_dispatch)
-                       return 0;
+               max_dispatch *= 4;
+       }
+
+       /*
+        * Async queues must wait a bit before being allowed dispatch.
+        * We also ramp up the dispatch depth gradually for async IO,
+        * based on the last sync IO we serviced
+        */
+       if (!cfq_cfqq_sync(cfqq) && cfqd->cfq_latency) {
+               unsigned long last_sync = jiffies - cfqd->last_end_sync_rq;
+               unsigned int depth;
+
+               depth = last_sync / cfqd->cfq_slice[1];
+               if (!depth && !cfqq->dispatched)
+                       depth = 1;
+               if (depth < max_dispatch)
+                       max_dispatch = depth;
        }
 
+       if (cfqq->dispatched >= max_dispatch)
+               return 0;
+
        /*
         * Dispatch a request from this cfqq
         */
@@ -1376,7 +1399,7 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
 
        if (unlikely(cfqd->active_queue == cfqq)) {
                __cfq_slice_expired(cfqd, cfqq, 0);
-               cfq_schedule_dispatch(cfqd);
+               cfq_schedule_dispatch(cfqd, 0);
        }
 
        kmem_cache_free(cfq_pool, cfqq);
@@ -1471,7 +1494,7 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 {
        if (unlikely(cfqq == cfqd->active_queue)) {
                __cfq_slice_expired(cfqd, cfqq, 0);
-               cfq_schedule_dispatch(cfqd);
+               cfq_schedule_dispatch(cfqd, 0);
        }
 
        cfq_put_queue(cfqq);
@@ -1951,7 +1974,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        enable_idle = old_idle = cfq_cfqq_idle_window(cfqq);
 
        if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle ||
-           (cfqd->hw_tag && CIC_SEEKY(cic)))
+           (!cfqd->cfq_latency && cfqd->hw_tag && CIC_SEEKY(cic)))
                enable_idle = 0;
        else if (sample_valid(cic->ttime_samples)) {
                if (cic->ttime_mean > cfqd->cfq_slice_idle)
@@ -2157,8 +2180,10 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
        if (cfq_cfqq_sync(cfqq))
                cfqd->sync_flight--;
 
-       if (sync)
+       if (sync) {
                RQ_CIC(rq)->last_end_request = now;
+               cfqd->last_end_sync_rq = now;
+       }
 
        /*
         * If this is the active queue, check if it needs to be expired,
@@ -2186,7 +2211,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
        }
 
        if (!rq_in_driver(cfqd))
-               cfq_schedule_dispatch(cfqd);
+               cfq_schedule_dispatch(cfqd, 0);
 }
 
 /*
@@ -2316,7 +2341,7 @@ queue_fail:
        if (cic)
                put_io_context(cic->ioc);
 
-       cfq_schedule_dispatch(cfqd);
+       cfq_schedule_dispatch(cfqd, 0);
        spin_unlock_irqrestore(q->queue_lock, flags);
        cfq_log(cfqd, "set_request fail");
        return 1;
@@ -2325,7 +2350,7 @@ queue_fail:
 static void cfq_kick_queue(struct work_struct *work)
 {
        struct cfq_data *cfqd =
-               container_of(work, struct cfq_data, unplug_work);
+               container_of(work, struct cfq_data, unplug_work.work);
        struct request_queue *q = cfqd->queue;
 
        spin_lock_irq(q->queue_lock);
@@ -2379,7 +2404,7 @@ static void cfq_idle_slice_timer(unsigned long data)
 expire:
        cfq_slice_expired(cfqd, timed_out);
 out_kick:
-       cfq_schedule_dispatch(cfqd);
+       cfq_schedule_dispatch(cfqd, 0);
 out_cont:
        spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
 }
@@ -2387,7 +2412,7 @@ out_cont:
 static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
 {
        del_timer_sync(&cfqd->idle_slice_timer);
-       cancel_work_sync(&cfqd->unplug_work);
+       cancel_delayed_work_sync(&cfqd->unplug_work);
 }
 
 static void cfq_put_async_queues(struct cfq_data *cfqd)
@@ -2469,7 +2494,7 @@ static void *cfq_init_queue(struct request_queue *q)
        cfqd->idle_slice_timer.function = cfq_idle_slice_timer;
        cfqd->idle_slice_timer.data = (unsigned long) cfqd;
 
-       INIT_WORK(&cfqd->unplug_work, cfq_kick_queue);
+       INIT_DELAYED_WORK(&cfqd->unplug_work, cfq_kick_queue);
 
        cfqd->cfq_quantum = cfq_quantum;
        cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0];
@@ -2480,8 +2505,9 @@ static void *cfq_init_queue(struct request_queue *q)
        cfqd->cfq_slice[1] = cfq_slice_sync;
        cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
        cfqd->cfq_slice_idle = cfq_slice_idle;
+       cfqd->cfq_latency = 1;
        cfqd->hw_tag = 1;
-
+       cfqd->last_end_sync_rq = jiffies;
        return cfqd;
 }
 
@@ -2549,6 +2575,7 @@ SHOW_FUNCTION(cfq_slice_idle_show, cfqd->cfq_slice_idle, 1);
 SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1);
 SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1);
 SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0);
+SHOW_FUNCTION(cfq_low_latency_show, cfqd->cfq_latency, 0);
 #undef SHOW_FUNCTION
 
 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV)                        \
@@ -2580,6 +2607,7 @@ STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1);
 STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1);
 STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1,
                UINT_MAX, 0);
+STORE_FUNCTION(cfq_low_latency_store, &cfqd->cfq_latency, 0, 1, 0);
 #undef STORE_FUNCTION
 
 #define CFQ_ATTR(name) \
@@ -2595,6 +2623,7 @@ static struct elv_fs_entry cfq_attrs[] = {
        CFQ_ATTR(slice_async),
        CFQ_ATTR(slice_async_rq),
        CFQ_ATTR(slice_idle),
+       CFQ_ATTR(low_latency),
        __ATTR_NULL
 };
 
index 7865a34e0faaaba07cb9e4946dca6406b303bef1..9bd086c1a4d591b59eea0e684debac6e6b8e52d9 100644 (file)
@@ -21,6 +21,11 @@ static int compat_put_int(unsigned long arg, int val)
        return put_user(val, (compat_int_t __user *)compat_ptr(arg));
 }
 
+static int compat_put_uint(unsigned long arg, unsigned int val)
+{
+       return put_user(val, (compat_uint_t __user *)compat_ptr(arg));
+}
+
 static int compat_put_long(unsigned long arg, long val)
 {
        return put_user(val, (compat_long_t __user *)compat_ptr(arg));
@@ -734,6 +739,14 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        switch (cmd) {
        case HDIO_GETGEO:
                return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
+       case BLKPBSZGET:
+               return compat_put_uint(arg, bdev_physical_block_size(bdev));
+       case BLKIOMIN:
+               return compat_put_uint(arg, bdev_io_min(bdev));
+       case BLKIOOPT:
+               return compat_put_uint(arg, bdev_io_opt(bdev));
+       case BLKALIGNOFF:
+               return compat_put_int(arg, bdev_alignment_offset(bdev));
        case BLKFLSBUF:
        case BLKROSET:
        case BLKDISCARD:
index 517e4332cb37481dcad965e8f9986f029b42e64a..5a0861da324d76f975e2cb281f1fcc4e88f98606 100644 (file)
@@ -869,7 +869,6 @@ static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
 static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL);
 static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
 static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
-static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 static struct device_attribute dev_attr_fail =
        __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
@@ -889,7 +888,6 @@ static struct attribute *disk_attrs[] = {
        &dev_attr_alignment_offset.attr,
        &dev_attr_capability.attr,
        &dev_attr_stat.attr,
-       &dev_attr_inflight.attr,
 #ifdef CONFIG_FAIL_MAKE_REQUEST
        &dev_attr_fail.attr,
 #endif
@@ -1055,7 +1053,7 @@ static int diskstats_show(struct seq_file *seqf, void *v)
                           part_stat_read(hd, merges[1]),
                           (unsigned long long)part_stat_read(hd, sectors[1]),
                           jiffies_to_msecs(part_stat_read(hd, ticks[1])),
-                          part_in_flight(hd),
+                          hd->in_flight,
                           jiffies_to_msecs(part_stat_read(hd, io_ticks)),
                           jiffies_to_msecs(part_stat_read(hd, time_in_queue))
                        );
index d3e6b5827a3425de1871ec4dfa9f5ca04e8744f4..1f4d1de12b0957c9e8a2897f1aa89d5b96f170a5 100644 (file)
@@ -138,6 +138,11 @@ static int put_int(unsigned long arg, int val)
        return put_user(val, (int __user *)arg);
 }
 
+static int put_uint(unsigned long arg, unsigned int val)
+{
+       return put_user(val, (unsigned int __user *)arg);
+}
+
 static int put_long(unsigned long arg, long val)
 {
        return put_user(val, (long __user *)arg);
@@ -263,10 +268,18 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
                return put_long(arg, (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
        case BLKROGET:
                return put_int(arg, bdev_read_only(bdev) != 0);
-       case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */
+       case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */
                return put_int(arg, block_size(bdev));
-       case BLKSSZGET: /* get block device hardware sector size */
+       case BLKSSZGET: /* get block device logical block size */
                return put_int(arg, bdev_logical_block_size(bdev));
+       case BLKPBSZGET: /* get block device physical block size */
+               return put_uint(arg, bdev_physical_block_size(bdev));
+       case BLKIOMIN:
+               return put_uint(arg, bdev_io_min(bdev));
+       case BLKIOOPT:
+               return put_uint(arg, bdev_io_opt(bdev));
+       case BLKALIGNOFF:
+               return put_int(arg, bdev_alignment_offset(bdev));
        case BLKSECTGET:
                return put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev)));
        case BLKRASET:
index dd8729d674e56ef2dfcdc7a7fa320f399b4542c6..0ed42d8870c7cdde61dfa686475a4b45edd469e4 100644 (file)
@@ -211,6 +211,18 @@ config ACPI_HOTPLUG_CPU
        select ACPI_CONTAINER
        default y
 
+config ACPI_PROCESSOR_AGGREGATOR
+       tristate "Processor Aggregator"
+       depends on ACPI_PROCESSOR
+       depends on EXPERIMENTAL
+       depends on X86
+       help
+         ACPI 4.0 defines processor Aggregator, which enables OS to perform
+         specfic processor configuration and control that applies to all
+         processors in the platform. Currently only logical processor idling
+         is defined, which is to reduce power consumption. This driver
+         support the new device.
+
 config ACPI_THERMAL
        tristate "Thermal Zone"
        depends on ACPI_PROCESSOR
index 82cd49dc603b6a5712a380eddbb54237a33a4ec2..7702118509a0a6e848bee454a983f0ec42e9522b 100644 (file)
@@ -62,3 +62,5 @@ obj-$(CONFIG_ACPI_POWER_METER)        += power_meter.o
 processor-y                    := processor_core.o processor_throttling.o
 processor-y                    += processor_idle.o processor_thermal.o
 processor-$(CONFIG_CPU_FREQ)   += processor_perflib.o
+
+obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
new file mode 100644 (file)
index 0000000..0d2cdb8
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * acpi_pad.c ACPI Processor Aggregator Driver
+ *
+ * Copyright (c) 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/cpu.h>
+#include <linux/clockchips.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_PROCESSOR_AGGREGATOR_CLASS        "processor_aggregator"
+#define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
+#define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
+static DEFINE_MUTEX(isolated_cpus_lock);
+
+#define MWAIT_SUBSTATE_MASK    (0xf)
+#define MWAIT_CSTATE_MASK      (0xf)
+#define MWAIT_SUBSTATE_SIZE    (4)
+#define CPUID_MWAIT_LEAF (5)
+#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
+#define CPUID5_ECX_INTERRUPT_BREAK     (0x2)
+static unsigned long power_saving_mwait_eax;
+static void power_saving_mwait_init(void)
+{
+       unsigned int eax, ebx, ecx, edx;
+       unsigned int highest_cstate = 0;
+       unsigned int highest_subcstate = 0;
+       int i;
+
+       if (!boot_cpu_has(X86_FEATURE_MWAIT))
+               return;
+       if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
+               return;
+
+       cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
+
+       if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
+           !(ecx & CPUID5_ECX_INTERRUPT_BREAK))
+               return;
+
+       edx >>= MWAIT_SUBSTATE_SIZE;
+       for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
+               if (edx & MWAIT_SUBSTATE_MASK) {
+                       highest_cstate = i;
+                       highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
+               }
+       }
+       power_saving_mwait_eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
+               (highest_subcstate - 1);
+
+       for_each_online_cpu(i)
+               clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &i);
+
+#if defined(CONFIG_GENERIC_TIME) && defined(CONFIG_X86)
+       switch (boot_cpu_data.x86_vendor) {
+       case X86_VENDOR_AMD:
+       case X86_VENDOR_INTEL:
+               /*
+                * AMD Fam10h TSC will tick in all
+                * C/P/S0/S1 states when this bit is set.
+                */
+               if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+                       return;
+
+               /*FALL THROUGH*/
+       default:
+               /* TSC could halt in idle, so notify users */
+               mark_tsc_unstable("TSC halts in idle");
+       }
+#endif
+}
+
+static unsigned long cpu_weight[NR_CPUS];
+static int tsk_in_cpu[NR_CPUS] = {[0 ... NR_CPUS-1] = -1};
+static DECLARE_BITMAP(pad_busy_cpus_bits, NR_CPUS);
+static void round_robin_cpu(unsigned int tsk_index)
+{
+       struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
+       cpumask_var_t tmp;
+       int cpu;
+       unsigned long min_weight = -1, preferred_cpu;
+
+       if (!alloc_cpumask_var(&tmp, GFP_KERNEL))
+               return;
+
+       mutex_lock(&isolated_cpus_lock);
+       cpumask_clear(tmp);
+       for_each_cpu(cpu, pad_busy_cpus)
+               cpumask_or(tmp, tmp, topology_thread_cpumask(cpu));
+       cpumask_andnot(tmp, cpu_online_mask, tmp);
+       /* avoid HT sibilings if possible */
+       if (cpumask_empty(tmp))
+               cpumask_andnot(tmp, cpu_online_mask, pad_busy_cpus);
+       if (cpumask_empty(tmp)) {
+               mutex_unlock(&isolated_cpus_lock);
+               return;
+       }
+       for_each_cpu(cpu, tmp) {
+               if (cpu_weight[cpu] < min_weight) {
+                       min_weight = cpu_weight[cpu];
+                       preferred_cpu = cpu;
+               }
+       }
+
+       if (tsk_in_cpu[tsk_index] != -1)
+               cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
+       tsk_in_cpu[tsk_index] = preferred_cpu;
+       cpumask_set_cpu(preferred_cpu, pad_busy_cpus);
+       cpu_weight[preferred_cpu]++;
+       mutex_unlock(&isolated_cpus_lock);
+
+       set_cpus_allowed_ptr(current, cpumask_of(preferred_cpu));
+}
+
+static void exit_round_robin(unsigned int tsk_index)
+{
+       struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
+       cpumask_clear_cpu(tsk_in_cpu[tsk_index], pad_busy_cpus);
+       tsk_in_cpu[tsk_index] = -1;
+}
+
+static unsigned int idle_pct = 5; /* percentage */
+static unsigned int round_robin_time = 10; /* second */
+static int power_saving_thread(void *data)
+{
+       struct sched_param param = {.sched_priority = 1};
+       int do_sleep;
+       unsigned int tsk_index = (unsigned long)data;
+       u64 last_jiffies = 0;
+
+       sched_setscheduler(current, SCHED_RR, &param);
+
+       while (!kthread_should_stop()) {
+               int cpu;
+               u64 expire_time;
+
+               try_to_freeze();
+
+               /* round robin to cpus */
+               if (last_jiffies + round_robin_time * HZ < jiffies) {
+                       last_jiffies = jiffies;
+                       round_robin_cpu(tsk_index);
+               }
+
+               do_sleep = 0;
+
+               current_thread_info()->status &= ~TS_POLLING;
+               /*
+                * TS_POLLING-cleared state must be visible before we test
+                * NEED_RESCHED:
+                */
+               smp_mb();
+
+               expire_time = jiffies + HZ * (100 - idle_pct) / 100;
+
+               while (!need_resched()) {
+                       local_irq_disable();
+                       cpu = smp_processor_id();
+                       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
+                               &cpu);
+                       stop_critical_timings();
+
+                       __monitor((void *)&current_thread_info()->flags, 0, 0);
+                       smp_mb();
+                       if (!need_resched())
+                               __mwait(power_saving_mwait_eax, 1);
+
+                       start_critical_timings();
+                       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
+                               &cpu);
+                       local_irq_enable();
+
+                       if (jiffies > expire_time) {
+                               do_sleep = 1;
+                               break;
+                       }
+               }
+
+               current_thread_info()->status |= TS_POLLING;
+
+               /*
+                * current sched_rt has threshold for rt task running time.
+                * When a rt task uses 95% CPU time, the rt thread will be
+                * scheduled out for 5% CPU time to not starve other tasks. But
+                * the mechanism only works when all CPUs have RT task running,
+                * as if one CPU hasn't RT task, RT task from other CPUs will
+                * borrow CPU time from this CPU and cause RT task use > 95%
+                * CPU time. To make 'avoid staration' work, takes a nap here.
+                */
+               if (do_sleep)
+                       schedule_timeout_killable(HZ * idle_pct / 100);
+       }
+
+       exit_round_robin(tsk_index);
+       return 0;
+}
+
+static struct task_struct *ps_tsks[NR_CPUS];
+static unsigned int ps_tsk_num;
+static int create_power_saving_task(void)
+{
+       ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread,
+               (void *)(unsigned long)ps_tsk_num,
+               "power_saving/%d", ps_tsk_num);
+       if (ps_tsks[ps_tsk_num]) {
+               ps_tsk_num++;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static void destroy_power_saving_task(void)
+{
+       if (ps_tsk_num > 0) {
+               ps_tsk_num--;
+               kthread_stop(ps_tsks[ps_tsk_num]);
+       }
+}
+
+static void set_power_saving_task_num(unsigned int num)
+{
+       if (num > ps_tsk_num) {
+               while (ps_tsk_num < num) {
+                       if (create_power_saving_task())
+                               return;
+               }
+       } else if (num < ps_tsk_num) {
+               while (ps_tsk_num > num)
+                       destroy_power_saving_task();
+       }
+}
+
+static int acpi_pad_idle_cpus(unsigned int num_cpus)
+{
+       get_online_cpus();
+
+       num_cpus = min_t(unsigned int, num_cpus, num_online_cpus());
+       set_power_saving_task_num(num_cpus);
+
+       put_online_cpus();
+       return 0;
+}
+
+static uint32_t acpi_pad_idle_cpus_num(void)
+{
+       return ps_tsk_num;
+}
+
+static ssize_t acpi_pad_rrtime_store(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       unsigned long num;
+       if (strict_strtoul(buf, 0, &num))
+               return -EINVAL;
+       if (num < 1 || num >= 100)
+               return -EINVAL;
+       mutex_lock(&isolated_cpus_lock);
+       round_robin_time = num;
+       mutex_unlock(&isolated_cpus_lock);
+       return count;
+}
+
+static ssize_t acpi_pad_rrtime_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       return scnprintf(buf, PAGE_SIZE, "%d", round_robin_time);
+}
+static DEVICE_ATTR(rrtime, S_IRUGO|S_IWUSR,
+       acpi_pad_rrtime_show,
+       acpi_pad_rrtime_store);
+
+static ssize_t acpi_pad_idlepct_store(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       unsigned long num;
+       if (strict_strtoul(buf, 0, &num))
+               return -EINVAL;
+       if (num < 1 || num >= 100)
+               return -EINVAL;
+       mutex_lock(&isolated_cpus_lock);
+       idle_pct = num;
+       mutex_unlock(&isolated_cpus_lock);
+       return count;
+}
+
+static ssize_t acpi_pad_idlepct_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       return scnprintf(buf, PAGE_SIZE, "%d", idle_pct);
+}
+static DEVICE_ATTR(idlepct, S_IRUGO|S_IWUSR,
+       acpi_pad_idlepct_show,
+       acpi_pad_idlepct_store);
+
+static ssize_t acpi_pad_idlecpus_store(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       unsigned long num;
+       if (strict_strtoul(buf, 0, &num))
+               return -EINVAL;
+       mutex_lock(&isolated_cpus_lock);
+       acpi_pad_idle_cpus(num);
+       mutex_unlock(&isolated_cpus_lock);
+       return count;
+}
+
+static ssize_t acpi_pad_idlecpus_show(struct device *dev,
+       struct device_attribute *attr, char *buf)
+{
+       return cpumask_scnprintf(buf, PAGE_SIZE,
+               to_cpumask(pad_busy_cpus_bits));
+}
+static DEVICE_ATTR(idlecpus, S_IRUGO|S_IWUSR,
+       acpi_pad_idlecpus_show,
+       acpi_pad_idlecpus_store);
+
+static int acpi_pad_add_sysfs(struct acpi_device *device)
+{
+       int result;
+
+       result = device_create_file(&device->dev, &dev_attr_idlecpus);
+       if (result)
+               return -ENODEV;
+       result = device_create_file(&device->dev, &dev_attr_idlepct);
+       if (result) {
+               device_remove_file(&device->dev, &dev_attr_idlecpus);
+               return -ENODEV;
+       }
+       result = device_create_file(&device->dev, &dev_attr_rrtime);
+       if (result) {
+               device_remove_file(&device->dev, &dev_attr_idlecpus);
+               device_remove_file(&device->dev, &dev_attr_idlepct);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void acpi_pad_remove_sysfs(struct acpi_device *device)
+{
+       device_remove_file(&device->dev, &dev_attr_idlecpus);
+       device_remove_file(&device->dev, &dev_attr_idlepct);
+       device_remove_file(&device->dev, &dev_attr_rrtime);
+}
+
+/* Query firmware how many CPUs should be idle */
+static int acpi_pad_pur(acpi_handle handle, int *num_cpus)
+{
+       struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+       acpi_status status;
+       union acpi_object *package;
+       int rev, num, ret = -EINVAL;
+
+       status = acpi_evaluate_object(handle, "_PUR", NULL, &buffer);
+       if (ACPI_FAILURE(status))
+               return -EINVAL;
+       package = buffer.pointer;
+       if (package->type != ACPI_TYPE_PACKAGE || package->package.count != 2)
+               goto out;
+       rev = package->package.elements[0].integer.value;
+       num = package->package.elements[1].integer.value;
+       if (rev != 1)
+               goto out;
+       *num_cpus = num;
+       ret = 0;
+out:
+       kfree(buffer.pointer);
+       return ret;
+}
+
+/* Notify firmware how many CPUs are idle */
+static void acpi_pad_ost(acpi_handle handle, int stat,
+       uint32_t idle_cpus)
+{
+       union acpi_object params[3] = {
+               {.type = ACPI_TYPE_INTEGER,},
+               {.type = ACPI_TYPE_INTEGER,},
+               {.type = ACPI_TYPE_BUFFER,},
+       };
+       struct acpi_object_list arg_list = {3, params};
+
+       params[0].integer.value = ACPI_PROCESSOR_AGGREGATOR_NOTIFY;
+       params[1].integer.value =  stat;
+       params[2].buffer.length = 4;
+       params[2].buffer.pointer = (void *)&idle_cpus;
+       acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
+}
+
+static void acpi_pad_handle_notify(acpi_handle handle)
+{
+       int num_cpus, ret;
+       uint32_t idle_cpus;
+
+       mutex_lock(&isolated_cpus_lock);
+       if (acpi_pad_pur(handle, &num_cpus)) {
+               mutex_unlock(&isolated_cpus_lock);
+               return;
+       }
+       ret = acpi_pad_idle_cpus(num_cpus);
+       idle_cpus = acpi_pad_idle_cpus_num();
+       if (!ret)
+               acpi_pad_ost(handle, 0, idle_cpus);
+       else
+               acpi_pad_ost(handle, 1, 0);
+       mutex_unlock(&isolated_cpus_lock);
+}
+
+static void acpi_pad_notify(acpi_handle handle, u32 event,
+       void *data)
+{
+       struct acpi_device *device = data;
+
+       switch (event) {
+       case ACPI_PROCESSOR_AGGREGATOR_NOTIFY:
+               acpi_pad_handle_notify(handle);
+               acpi_bus_generate_proc_event(device, event, 0);
+               acpi_bus_generate_netlink_event(device->pnp.device_class,
+                       dev_name(&device->dev), event, 0);
+               break;
+       default:
+               printk(KERN_WARNING"Unsupported event [0x%x]\n", event);
+               break;
+       }
+}
+
+static int acpi_pad_add(struct acpi_device *device)
+{
+       acpi_status status;
+
+       strcpy(acpi_device_name(device), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
+       strcpy(acpi_device_class(device), ACPI_PROCESSOR_AGGREGATOR_CLASS);
+
+       if (acpi_pad_add_sysfs(device))
+               return -ENODEV;
+
+       status = acpi_install_notify_handler(device->handle,
+               ACPI_DEVICE_NOTIFY, acpi_pad_notify, device);
+       if (ACPI_FAILURE(status)) {
+               acpi_pad_remove_sysfs(device);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int acpi_pad_remove(struct acpi_device *device,
+       int type)
+{
+       mutex_lock(&isolated_cpus_lock);
+       acpi_pad_idle_cpus(0);
+       mutex_unlock(&isolated_cpus_lock);
+
+       acpi_remove_notify_handler(device->handle,
+               ACPI_DEVICE_NOTIFY, acpi_pad_notify);
+       acpi_pad_remove_sysfs(device);
+       return 0;
+}
+
+static const struct acpi_device_id pad_device_ids[] = {
+       {"ACPI000C", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, pad_device_ids);
+
+static struct acpi_driver acpi_pad_driver = {
+       .name = "processor_aggregator",
+       .class = ACPI_PROCESSOR_AGGREGATOR_CLASS,
+       .ids = pad_device_ids,
+       .ops = {
+               .add = acpi_pad_add,
+               .remove = acpi_pad_remove,
+       },
+};
+
+static int __init acpi_pad_init(void)
+{
+       power_saving_mwait_init();
+       if (power_saving_mwait_eax == 0)
+               return -EINVAL;
+
+       return acpi_bus_register_driver(&acpi_pad_driver);
+}
+
+static void __exit acpi_pad_exit(void)
+{
+       acpi_bus_unregister_driver(&acpi_pad_driver);
+}
+
+module_init(acpi_pad_init);
+module_exit(acpi_pad_exit);
+MODULE_AUTHOR("Shaohua Li<shaohua.li@intel.com>");
+MODULE_DESCRIPTION("ACPI Processor Aggregator Driver");
+MODULE_LICENSE("GPL");
index 3a2cfefc71ab1ab5da484b47bd9bd7f28aee988a..7338b6a3e049aa061d00bf13b469ffb086d5276a 100644 (file)
@@ -67,7 +67,7 @@ struct dock_station {
        struct list_head dependent_devices;
        struct list_head hotplug_devices;
 
-       struct list_head sibiling;
+       struct list_head sibling;
        struct platform_device *dock_device;
 };
 static LIST_HEAD(dock_stations);
@@ -275,7 +275,7 @@ int is_dock_device(acpi_handle handle)
 
        if (is_dock(handle))
                return 1;
-       list_for_each_entry(dock_station, &dock_stations, sibiling) {
+       list_for_each_entry(dock_station, &dock_stations, sibling) {
                if (find_dock_dependent_device(dock_station, handle))
                        return 1;
        }
@@ -619,7 +619,7 @@ register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
         * make sure this handle is for a device dependent on the dock,
         * this would include the dock station itself
         */
-       list_for_each_entry(dock_station, &dock_stations, sibiling) {
+       list_for_each_entry(dock_station, &dock_stations, sibling) {
                /*
                 * An ATA bay can be in a dock and itself can be ejected
                 * seperately, so there are two 'dock stations' which need the
@@ -651,7 +651,7 @@ void unregister_hotplug_dock_device(acpi_handle handle)
        if (!dock_station_count)
                return;
 
-       list_for_each_entry(dock_station, &dock_stations, sibiling) {
+       list_for_each_entry(dock_station, &dock_stations, sibling) {
                dd = find_dock_dependent_device(dock_station, handle);
                if (dd)
                        dock_del_hotplug_device(dock_station, dd);
@@ -787,7 +787,7 @@ static int acpi_dock_notifier_call(struct notifier_block *this,
        if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
           && event != ACPI_NOTIFY_EJECT_REQUEST)
                return 0;
-       list_for_each_entry(dock_station, &dock_stations, sibiling) {
+       list_for_each_entry(dock_station, &dock_stations, sibling) {
                if (dock_station->handle == handle) {
                        struct dock_data *dock_data;
 
@@ -958,7 +958,7 @@ static int dock_add(acpi_handle handle)
        dock_station->last_dock_time = jiffies - HZ;
        INIT_LIST_HEAD(&dock_station->dependent_devices);
        INIT_LIST_HEAD(&dock_station->hotplug_devices);
-       INIT_LIST_HEAD(&dock_station->sibiling);
+       INIT_LIST_HEAD(&dock_station->sibling);
        spin_lock_init(&dock_station->dd_lock);
        mutex_init(&dock_station->hp_lock);
        ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
@@ -1044,7 +1044,7 @@ static int dock_add(acpi_handle handle)
        add_dock_dependent_device(dock_station, dd);
 
        dock_station_count++;
-       list_add(&dock_station->sibiling, &dock_stations);
+       list_add(&dock_station->sibling, &dock_stations);
        return 0;
 
 dock_add_err_unregister:
@@ -1149,7 +1149,7 @@ static void __exit dock_exit(void)
        struct dock_station *tmp;
 
        unregister_acpi_bus_notifier(&dock_acpi_notifier);
-       list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibiling)
+       list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling)
                dock_remove(dock_station);
 }
 
index f70796081c4c0ad93c0e5c751cc2297b81dea9f4..baef28c1e63090c8b10c5e661257390c52f275b7 100644 (file)
@@ -119,6 +119,8 @@ static struct acpi_ec {
 } *boot_ec, *first_ec;
 
 static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
+static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
+static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
 
 /* --------------------------------------------------------------------------
                              Transaction Management
@@ -232,10 +234,8 @@ static int ec_poll(struct acpi_ec *ec)
                        }
                        advance_transaction(ec, acpi_ec_read_status(ec));
                } while (time_before(jiffies, delay));
-               if (!ec->curr->irq_count ||
-                   (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF))
+               if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
                        break;
-               /* try restart command if we get any false interrupts */
                pr_debug(PREFIX "controller reset, restart transaction\n");
                spin_lock_irqsave(&ec->curr_lock, flags);
                start_transaction(ec);
@@ -899,6 +899,44 @@ static const struct acpi_device_id ec_device_ids[] = {
        {"", 0},
 };
 
+/* Some BIOS do not survive early DSDT scan, skip it */
+static int ec_skip_dsdt_scan(const struct dmi_system_id *id)
+{
+       EC_FLAGS_SKIP_DSDT_SCAN = 1;
+       return 0;
+}
+
+/* ASUStek often supplies us with broken ECDT, validate it */
+static int ec_validate_ecdt(const struct dmi_system_id *id)
+{
+       EC_FLAGS_VALIDATE_ECDT = 1;
+       return 0;
+}
+
+/* MSI EC needs special treatment, enable it */
+static int ec_flag_msi(const struct dmi_system_id *id)
+{
+       EC_FLAGS_MSI = 1;
+       EC_FLAGS_VALIDATE_ECDT = 1;
+       return 0;
+}
+
+static struct dmi_system_id __initdata ec_dmi_table[] = {
+       {
+       ec_skip_dsdt_scan, "Compal JFL92", {
+       DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
+       DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL},
+       {
+       ec_flag_msi, "MSI hardware", {
+       DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star"),
+       DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star") }, NULL},
+       {
+       ec_validate_ecdt, "ASUS hardware", {
+       DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
+       {},
+};
+
+
 int __init acpi_ec_ecdt_probe(void)
 {
        acpi_status status;
@@ -911,11 +949,7 @@ int __init acpi_ec_ecdt_probe(void)
        /*
         * Generate a boot ec context
         */
-       if (dmi_name_in_vendors("Micro-Star") ||
-           dmi_name_in_vendors("Notebook")) {
-               pr_info(PREFIX "Enabling special treatment for EC from MSI.\n");
-               EC_FLAGS_MSI = 1;
-       }
+       dmi_check_system(ec_dmi_table);
        status = acpi_get_table(ACPI_SIG_ECDT, 1,
                                (struct acpi_table_header **)&ecdt_ptr);
        if (ACPI_SUCCESS(status)) {
@@ -926,7 +960,7 @@ int __init acpi_ec_ecdt_probe(void)
                boot_ec->handle = ACPI_ROOT_OBJECT;
                acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
                /* Don't trust ECDT, which comes from ASUSTek */
-               if (!dmi_name_in_vendors("ASUS") && EC_FLAGS_MSI == 0)
+               if (!EC_FLAGS_VALIDATE_ECDT)
                        goto install;
                saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
                if (!saved_ec)
@@ -934,6 +968,10 @@ int __init acpi_ec_ecdt_probe(void)
                memcpy(saved_ec, boot_ec, sizeof(struct acpi_ec));
        /* fall through */
        }
+
+       if (EC_FLAGS_SKIP_DSDT_SCAN)
+               return -ENODEV;
+
        /* This workaround is needed only on some broken machines,
         * which require early EC, but fail to provide ECDT */
        printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
index d0d550d22a6d43a14ccecec6658e9fb2773d6b70..f8b6f555ba52ba328d43efca6c5926831a663d06 100644 (file)
@@ -398,6 +398,8 @@ acpi_system_write_wakeup_device(struct file *file,
 
        if (len > 4)
                len = 4;
+       if (len < 0)
+               return -EFAULT;
 
        if (copy_from_user(strbuf, buffer, len))
                return -EFAULT;
index c2d4d6e0936469a8ef5e80a11dd36a99d7be761e..c567b46dfa0f78a83bc1e0d0feb77e79516cfb42 100644 (file)
@@ -863,13 +863,6 @@ static int acpi_processor_add(struct acpi_device *device)
                goto err_remove_sysfs;
        }
 
-       if (pr->flags.throttling) {
-               printk(KERN_INFO PREFIX "%s [%s] (supports",
-                      acpi_device_name(device), acpi_device_bid(device));
-               printk(" %d throttling states", pr->throttling.state_count);
-               printk(")\n");
-       }
-
        return 0;
 
 err_remove_sysfs:
index 468921bed22f4e33f9012592fe906c3ca9ba3a1d..14a7481c97d71bdc2abd18e3c695cf72e8a9aee5 100644 (file)
@@ -1052,6 +1052,8 @@ static void acpi_device_set_id(struct acpi_device *device)
                        device->flags.bus_address = 1;
                }
 
+               kfree(info);
+
                /*
                 * Some devices don't reliably have _HIDs & _CIDs, so add
                 * synthetic HIDs to make sure drivers can find them.
@@ -1325,13 +1327,8 @@ static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
                         struct acpi_device **child)
 {
        acpi_status status;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        void *device = NULL;
 
-       acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-       printk(KERN_INFO PREFIX "Enumerating devices from [%s]\n",
-              (char *) buffer.pointer);
-
        status = acpi_bus_check_add(handle, 0, ops, &device);
        if (ACPI_SUCCESS(status))
                acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
index 6fa7b0fdbdfd172f2e10f27bc82660c9201f3234..eb4fa19439444097875d8492ceb6996569e40d45 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/reboot.h>
 #include <linux/spinlock.h>
 #include <linux/timer.h>
@@ -6422,16 +6423,10 @@ static bool DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller,
   return true;
 }
 
-
-/*
-  DAC960_ProcReadStatus implements reading /proc/rd/status.
-*/
-
-static int DAC960_ProcReadStatus(char *Page, char **Start, off_t Offset,
-                                int Count, int *EOF, void *Data)
+static int dac960_proc_show(struct seq_file *m, void *v)
 {
   unsigned char *StatusMessage = "OK\n";
-  int ControllerNumber, BytesAvailable;
+  int ControllerNumber;
   for (ControllerNumber = 0;
        ControllerNumber < DAC960_ControllerCount;
        ControllerNumber++)
@@ -6444,52 +6439,49 @@ static int DAC960_ProcReadStatus(char *Page, char **Start, off_t Offset,
          break;
        }
     }
-  BytesAvailable = strlen(StatusMessage) - Offset;
-  if (Count >= BytesAvailable)
-    {
-      Count = BytesAvailable;
-      *EOF = true;
-    }
-  if (Count <= 0) return 0;
-  *Start = Page;
-  memcpy(Page, &StatusMessage[Offset], Count);
-  return Count;
+  seq_puts(m, StatusMessage);
+  return 0;
 }
 
+static int dac960_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dac960_proc_show, NULL);
+}
 
-/*
-  DAC960_ProcReadInitialStatus implements reading /proc/rd/cN/initial_status.
-*/
+static const struct file_operations dac960_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = dac960_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
-static int DAC960_ProcReadInitialStatus(char *Page, char **Start, off_t Offset,
-                                       int Count, int *EOF, void *Data)
+static int dac960_initial_status_proc_show(struct seq_file *m, void *v)
 {
-  DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
-  int BytesAvailable = Controller->InitialStatusLength - Offset;
-  if (Count >= BytesAvailable)
-    {
-      Count = BytesAvailable;
-      *EOF = true;
-    }
-  if (Count <= 0) return 0;
-  *Start = Page;
-  memcpy(Page, &Controller->CombinedStatusBuffer[Offset], Count);
-  return Count;
+       DAC960_Controller_T *Controller = (DAC960_Controller_T *)m->private;
+       seq_printf(m, "%.*s", Controller->InitialStatusLength, Controller->CombinedStatusBuffer);
+       return 0;
 }
 
+static int dac960_initial_status_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dac960_initial_status_proc_show, PDE(inode)->data);
+}
 
-/*
-  DAC960_ProcReadCurrentStatus implements reading /proc/rd/cN/current_status.
-*/
+static const struct file_operations dac960_initial_status_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = dac960_initial_status_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
-static int DAC960_ProcReadCurrentStatus(char *Page, char **Start, off_t Offset,
-                                       int Count, int *EOF, void *Data)
+static int dac960_current_status_proc_show(struct seq_file *m, void *v)
 {
-  DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) m->private;
   unsigned char *StatusMessage =
     "No Rebuild or Consistency Check in Progress\n";
   int ProgressMessageLength = strlen(StatusMessage);
-  int BytesAvailable;
   if (jiffies != Controller->LastCurrentStatusTime)
     {
       Controller->CurrentStatusLength = 0;
@@ -6513,49 +6505,41 @@ static int DAC960_ProcReadCurrentStatus(char *Page, char **Start, off_t Offset,
        }
       Controller->LastCurrentStatusTime = jiffies;
     }
-  BytesAvailable = Controller->CurrentStatusLength - Offset;
-  if (Count >= BytesAvailable)
-    {
-      Count = BytesAvailable;
-      *EOF = true;
-    }
-  if (Count <= 0) return 0;
-  *Start = Page;
-  memcpy(Page, &Controller->CurrentStatusBuffer[Offset], Count);
-  return Count;
+       seq_printf(m, "%.*s", Controller->CurrentStatusLength, Controller->CurrentStatusBuffer);
+       return 0;
 }
 
+static int dac960_current_status_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dac960_current_status_proc_show, PDE(inode)->data);
+}
 
-/*
-  DAC960_ProcReadUserCommand implements reading /proc/rd/cN/user_command.
-*/
+static const struct file_operations dac960_current_status_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = dac960_current_status_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 
-static int DAC960_ProcReadUserCommand(char *Page, char **Start, off_t Offset,
-                                     int Count, int *EOF, void *Data)
+static int dac960_user_command_proc_show(struct seq_file *m, void *v)
 {
-  DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
-  int BytesAvailable = Controller->UserStatusLength - Offset;
-  if (Count >= BytesAvailable)
-    {
-      Count = BytesAvailable;
-      *EOF = true;
-    }
-  if (Count <= 0) return 0;
-  *Start = Page;
-  memcpy(Page, &Controller->UserStatusBuffer[Offset], Count);
-  return Count;
-}
+       DAC960_Controller_T *Controller = (DAC960_Controller_T *)m->private;
 
+       seq_printf(m, "%.*s", Controller->UserStatusLength, Controller->UserStatusBuffer);
+       return 0;
+}
 
-/*
-  DAC960_ProcWriteUserCommand implements writing /proc/rd/cN/user_command.
-*/
+static int dac960_user_command_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dac960_user_command_proc_show, PDE(inode)->data);
+}
 
-static int DAC960_ProcWriteUserCommand(struct file *file,
+static ssize_t dac960_user_command_proc_write(struct file *file,
                                       const char __user *Buffer,
-                                      unsigned long Count, void *Data)
+                                      size_t Count, loff_t *pos)
 {
-  DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) PDE(file->f_path.dentry->d_inode)->data;
   unsigned char CommandBuffer[80];
   int Length;
   if (Count > sizeof(CommandBuffer)-1) return -EINVAL;
@@ -6572,6 +6556,14 @@ static int DAC960_ProcWriteUserCommand(struct file *file,
            ? Count : -EBUSY);
 }
 
+static const struct file_operations dac960_user_command_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = dac960_user_command_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = dac960_user_command_proc_write,
+};
 
 /*
   DAC960_CreateProcEntries creates the /proc/rd/... entries for the
@@ -6586,23 +6578,17 @@ static void DAC960_CreateProcEntries(DAC960_Controller_T *Controller)
 
        if (DAC960_ProcDirectoryEntry == NULL) {
                DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL);
-               StatusProcEntry = create_proc_read_entry("status", 0,
+               StatusProcEntry = proc_create("status", 0,
                                           DAC960_ProcDirectoryEntry,
-                                          DAC960_ProcReadStatus, NULL);
+                                          &dac960_proc_fops);
        }
 
       sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
       ControllerProcEntry = proc_mkdir(Controller->ControllerName,
                                       DAC960_ProcDirectoryEntry);
-      create_proc_read_entry("initial_status", 0, ControllerProcEntry,
-                            DAC960_ProcReadInitialStatus, Controller);
-      create_proc_read_entry("current_status", 0, ControllerProcEntry,
-                            DAC960_ProcReadCurrentStatus, Controller);
-      UserCommandProcEntry =
-       create_proc_read_entry("user_command", S_IWUSR | S_IRUSR,
-                              ControllerProcEntry, DAC960_ProcReadUserCommand,
-                              Controller);
-      UserCommandProcEntry->write_proc = DAC960_ProcWriteUserCommand;
+      proc_create_data("initial_status", 0, ControllerProcEntry, &dac960_initial_status_proc_fops, Controller);
+      proc_create_data("current_status", 0, ControllerProcEntry, &dac960_current_status_proc_fops, Controller);
+      UserCommandProcEntry = proc_create_data("user_command", S_IWUSR | S_IRUSR, ControllerProcEntry, &dac960_user_command_proc_fops, Controller);
       Controller->ControllerProcEntry = ControllerProcEntry;
 }
 
index 1ece0b47b581e1fc108a8d023c3a7ffac802aae7..fb5be2d95d52c57a8ac8aab4f0375579a8852de6 100644 (file)
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/init.h>
+#include <linux/jiffies.h>
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
 #include <linux/compat.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -155,6 +157,10 @@ static struct board_type products[] = {
 
 static ctlr_info_t *hba[MAX_CTLR];
 
+static struct task_struct *cciss_scan_thread;
+static DEFINE_MUTEX(scan_mutex);
+static LIST_HEAD(scan_q);
+
 static void do_cciss_request(struct request_queue *q);
 static irqreturn_t do_cciss_intr(int irq, void *dev_id);
 static int cciss_open(struct block_device *bdev, fmode_t mode);
@@ -164,9 +170,9 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
 static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
 static int cciss_revalidate(struct gendisk *disk);
-static int rebuild_lun_table(ctlr_info_t *h, int first_time);
+static int rebuild_lun_table(ctlr_info_t *h, int first_time, int via_ioctl);
 static int deregister_disk(ctlr_info_t *h, int drv_index,
-                          int clear_all);
+                          int clear_all, int via_ioctl);
 
 static void cciss_read_capacity(int ctlr, int logvol, int withirq,
                        sector_t *total_size, unsigned int *block_size);
@@ -189,8 +195,13 @@ static int sendcmd_withirq_core(ctlr_info_t *h, CommandList_struct *c,
 static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c);
 
 static void fail_all_cmds(unsigned long ctlr);
+static int add_to_scan_list(struct ctlr_info *h);
 static int scan_thread(void *data);
 static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c);
+static void cciss_hba_release(struct device *dev);
+static void cciss_device_release(struct device *dev);
+static void cciss_free_gendisk(ctlr_info_t *h, int drv_index);
+static void cciss_free_drive_info(ctlr_info_t *h, int drv_index);
 
 #ifdef CONFIG_PROC_FS
 static void cciss_procinit(int i);
@@ -245,7 +256,10 @@ static inline void removeQ(CommandList_struct *c)
 
 #include "cciss_scsi.c"                /* For SCSI tape support */
 
-#define RAID_UNKNOWN 6
+static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
+       "UNKNOWN"
+};
+#define RAID_UNKNOWN (sizeof(raid_label) / sizeof(raid_label[0])-1)
 
 #ifdef CONFIG_PROC_FS
 
@@ -255,9 +269,6 @@ static inline void removeQ(CommandList_struct *c)
 #define ENG_GIG 1000000000
 #define ENG_GIG_FACTOR (ENG_GIG/512)
 #define ENGAGE_SCSI    "engage scsi"
-static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
-       "UNKNOWN"
-};
 
 static struct proc_dir_entry *proc_cciss;
 
@@ -318,7 +329,7 @@ static int cciss_seq_show(struct seq_file *seq, void *v)
        ctlr_info_t *h = seq->private;
        unsigned ctlr = h->ctlr;
        loff_t *pos = v;
-       drive_info_struct *drv = &h->drv[*pos];
+       drive_info_struct *drv = h->drv[*pos];
 
        if (*pos > h->highest_lun)
                return 0;
@@ -331,7 +342,7 @@ static int cciss_seq_show(struct seq_file *seq, void *v)
        vol_sz_frac *= 100;
        sector_div(vol_sz_frac, ENG_GIG_FACTOR);
 
-       if (drv->raid_level > 5)
+       if (drv->raid_level < 0 || drv->raid_level > RAID_UNKNOWN)
                drv->raid_level = RAID_UNKNOWN;
        seq_printf(seq, "cciss/c%dd%d:"
                        "\t%4u.%02uGB\tRAID %s\n",
@@ -454,9 +465,19 @@ static void __devinit cciss_procinit(int i)
 #define to_hba(n) container_of(n, struct ctlr_info, dev)
 #define to_drv(n) container_of(n, drive_info_struct, dev)
 
-static struct device_type cciss_host_type = {
-       .name           = "cciss_host",
-};
+static ssize_t host_store_rescan(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct ctlr_info *h = to_hba(dev);
+
+       add_to_scan_list(h);
+       wake_up_process(cciss_scan_thread);
+       wait_for_completion_interruptible(&h->scan_wait);
+
+       return count;
+}
+DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
 
 static ssize_t dev_show_unique_id(struct device *dev,
                                 struct device_attribute *attr,
@@ -560,11 +581,101 @@ static ssize_t dev_show_rev(struct device *dev,
 }
 DEVICE_ATTR(rev, S_IRUGO, dev_show_rev, NULL);
 
+static ssize_t cciss_show_lunid(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       drive_info_struct *drv = to_drv(dev);
+       struct ctlr_info *h = to_hba(drv->dev.parent);
+       unsigned long flags;
+       unsigned char lunid[8];
+
+       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       if (h->busy_configuring) {
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               return -EBUSY;
+       }
+       if (!drv->heads) {
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               return -ENOTTY;
+       }
+       memcpy(lunid, drv->LunID, sizeof(lunid));
+       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       return snprintf(buf, 20, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+               lunid[0], lunid[1], lunid[2], lunid[3],
+               lunid[4], lunid[5], lunid[6], lunid[7]);
+}
+DEVICE_ATTR(lunid, S_IRUGO, cciss_show_lunid, NULL);
+
+static ssize_t cciss_show_raid_level(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       drive_info_struct *drv = to_drv(dev);
+       struct ctlr_info *h = to_hba(drv->dev.parent);
+       int raid;
+       unsigned long flags;
+
+       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       if (h->busy_configuring) {
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               return -EBUSY;
+       }
+       raid = drv->raid_level;
+       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       if (raid < 0 || raid > RAID_UNKNOWN)
+               raid = RAID_UNKNOWN;
+
+       return snprintf(buf, strlen(raid_label[raid]) + 7, "RAID %s\n",
+                       raid_label[raid]);
+}
+DEVICE_ATTR(raid_level, S_IRUGO, cciss_show_raid_level, NULL);
+
+static ssize_t cciss_show_usage_count(struct device *dev,
+                                     struct device_attribute *attr, char *buf)
+{
+       drive_info_struct *drv = to_drv(dev);
+       struct ctlr_info *h = to_hba(drv->dev.parent);
+       unsigned long flags;
+       int count;
+
+       spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
+       if (h->busy_configuring) {
+               spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+               return -EBUSY;
+       }
+       count = drv->usage_count;
+       spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+       return snprintf(buf, 20, "%d\n", count);
+}
+DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL);
+
+static struct attribute *cciss_host_attrs[] = {
+       &dev_attr_rescan.attr,
+       NULL
+};
+
+static struct attribute_group cciss_host_attr_group = {
+       .attrs = cciss_host_attrs,
+};
+
+static const struct attribute_group *cciss_host_attr_groups[] = {
+       &cciss_host_attr_group,
+       NULL
+};
+
+static struct device_type cciss_host_type = {
+       .name           = "cciss_host",
+       .groups         = cciss_host_attr_groups,
+       .release        = cciss_hba_release,
+};
+
 static struct attribute *cciss_dev_attrs[] = {
        &dev_attr_unique_id.attr,
        &dev_attr_model.attr,
        &dev_attr_vendor.attr,
        &dev_attr_rev.attr,
+       &dev_attr_lunid.attr,
+       &dev_attr_raid_level.attr,
+       &dev_attr_usage_count.attr,
        NULL
 };
 
@@ -580,12 +691,24 @@ static const struct attribute_group *cciss_dev_attr_groups[] = {
 static struct device_type cciss_dev_type = {
        .name           = "cciss_device",
        .groups         = cciss_dev_attr_groups,
+       .release        = cciss_device_release,
 };
 
 static struct bus_type cciss_bus_type = {
        .name           = "cciss",
 };
 
+/*
+ * cciss_hba_release is called when the reference count
+ * of h->dev goes to zero.
+ */
+static void cciss_hba_release(struct device *dev)
+{
+       /*
+        * nothing to do, but need this to avoid a warning
+        * about not having a release handler from lib/kref.c.
+        */
+}
 
 /*
  * Initialize sysfs entry for each controller.  This sets up and registers
@@ -609,6 +732,16 @@ static int cciss_create_hba_sysfs_entry(struct ctlr_info *h)
 static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h)
 {
        device_del(&h->dev);
+       put_device(&h->dev); /* final put. */
+}
+
+/* cciss_device_release is called when the reference count
+ * of h->drv[x]dev goes to zero.
+ */
+static void cciss_device_release(struct device *dev)
+{
+       drive_info_struct *drv = to_drv(dev);
+       kfree(drv);
 }
 
 /*
@@ -617,24 +750,39 @@ static void cciss_destroy_hba_sysfs_entry(struct ctlr_info *h)
  * /sys/bus/pci/devices/<dev/ccis#/. We also create a link from
  * /sys/block/cciss!c#d# to this entry.
  */
-static int cciss_create_ld_sysfs_entry(struct ctlr_info *h,
-                                      drive_info_struct *drv,
+static long cciss_create_ld_sysfs_entry(struct ctlr_info *h,
                                       int drv_index)
 {
-       device_initialize(&drv->dev);
-       drv->dev.type = &cciss_dev_type;
-       drv->dev.bus = &cciss_bus_type;
-       dev_set_name(&drv->dev, "c%dd%d", h->ctlr, drv_index);
-       drv->dev.parent = &h->dev;
-       return device_add(&drv->dev);
+       struct device *dev;
+
+       if (h->drv[drv_index]->device_initialized)
+               return 0;
+
+       dev = &h->drv[drv_index]->dev;
+       device_initialize(dev);
+       dev->type = &cciss_dev_type;
+       dev->bus = &cciss_bus_type;
+       dev_set_name(dev, "c%dd%d", h->ctlr, drv_index);
+       dev->parent = &h->dev;
+       h->drv[drv_index]->device_initialized = 1;
+       return device_add(dev);
 }
 
 /*
  * Remove sysfs entries for a logical drive.
  */
-static void cciss_destroy_ld_sysfs_entry(drive_info_struct *drv)
+static void cciss_destroy_ld_sysfs_entry(struct ctlr_info *h, int drv_index,
+       int ctlr_exiting)
 {
-       device_del(&drv->dev);
+       struct device *dev = &h->drv[drv_index]->dev;
+
+       /* special case for c*d0, we only destroy it on controller exit */
+       if (drv_index == 0 && !ctlr_exiting)
+               return;
+
+       device_del(dev);
+       put_device(dev); /* the "final" put. */
+       h->drv[drv_index] = NULL;
 }
 
 /*
@@ -751,7 +899,7 @@ static int cciss_open(struct block_device *bdev, fmode_t mode)
        printk(KERN_DEBUG "cciss_open %s\n", bdev->bd_disk->disk_name);
 #endif                         /* CCISS_DEBUG */
 
-       if (host->busy_initializing || drv->busy_configuring)
+       if (drv->busy_configuring)
                return -EBUSY;
        /*
         * Root is allowed to open raw volume zero even if it's not configured
@@ -767,7 +915,8 @@ static int cciss_open(struct block_device *bdev, fmode_t mode)
                        if (MINOR(bdev->bd_dev) & 0x0f) {
                                return -ENXIO;
                                /* if it is, make sure we have a LUN ID */
-                       } else if (drv->LunID == 0) {
+                       } else if (memcmp(drv->LunID, CTLR_LUNID,
+                               sizeof(drv->LunID))) {
                                return -ENXIO;
                        }
                }
@@ -1132,12 +1281,13 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
        case CCISS_DEREGDISK:
        case CCISS_REGNEWD:
        case CCISS_REVALIDVOLS:
-               return rebuild_lun_table(host, 0);
+               return rebuild_lun_table(host, 0, 1);
 
        case CCISS_GETLUNINFO:{
                        LogvolInfo_struct luninfo;
 
-                       luninfo.LunID = drv->LunID;
+                       memcpy(&luninfo.LunID, drv->LunID,
+                               sizeof(luninfo.LunID));
                        luninfo.num_opens = drv->usage_count;
                        luninfo.num_parts = 0;
                        if (copy_to_user(argp, &luninfo,
@@ -1475,7 +1625,10 @@ static void cciss_check_queues(ctlr_info_t *h)
                /* make sure the disk has been added and the drive is real
                 * because this can be called from the middle of init_one.
                 */
-               if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
+               if (!h->drv[curr_queue])
+                       continue;
+               if (!(h->drv[curr_queue]->queue) ||
+                       !(h->drv[curr_queue]->heads))
                        continue;
                blk_start_queue(h->gendisk[curr_queue]->queue);
 
@@ -1532,13 +1685,11 @@ static void cciss_softirq_done(struct request *rq)
        spin_unlock_irqrestore(&h->lock, flags);
 }
 
-static void log_unit_to_scsi3addr(ctlr_info_t *h, unsigned char scsi3addr[],
-       uint32_t log_unit)
+static inline void log_unit_to_scsi3addr(ctlr_info_t *h,
+       unsigned char scsi3addr[], uint32_t log_unit)
 {
-       log_unit = h->drv[log_unit].LunID & 0x03fff;
-       memset(&scsi3addr[4], 0, 4);
-       memcpy(&scsi3addr[0], &log_unit, 4);
-       scsi3addr[3] |= 0x40;
+       memcpy(scsi3addr, h->drv[log_unit]->LunID,
+               sizeof(h->drv[log_unit]->LunID));
 }
 
 /* This function gets the SCSI vendor, model, and revision of a logical drive
@@ -1615,16 +1766,23 @@ static void cciss_get_serial_no(int ctlr, int logvol, int withirq,
        return;
 }
 
-static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
+/*
+ * cciss_add_disk sets up the block device queue for a logical drive
+ */
+static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
                                int drv_index)
 {
        disk->queue = blk_init_queue(do_cciss_request, &h->lock);
+       if (!disk->queue)
+               goto init_queue_failure;
        sprintf(disk->disk_name, "cciss/c%dd%d", h->ctlr, drv_index);
        disk->major = h->major;
        disk->first_minor = drv_index << NWD_SHIFT;
        disk->fops = &cciss_fops;
-       disk->private_data = &h->drv[drv_index];
-       disk->driverfs_dev = &h->drv[drv_index].dev;
+       if (cciss_create_ld_sysfs_entry(h, drv_index))
+               goto cleanup_queue;
+       disk->private_data = h->drv[drv_index];
+       disk->driverfs_dev = &h->drv[drv_index]->dev;
 
        /* Set up queue information */
        blk_queue_bounce_limit(disk->queue, h->pdev->dma_mask);
@@ -1642,14 +1800,21 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
        disk->queue->queuedata = h;
 
        blk_queue_logical_block_size(disk->queue,
-                                    h->drv[drv_index].block_size);
+                                    h->drv[drv_index]->block_size);
 
        /* Make sure all queue data is written out before */
-       /* setting h->drv[drv_index].queue, as setting this */
+       /* setting h->drv[drv_index]->queue, as setting this */
        /* allows the interrupt handler to start the queue */
        wmb();
-       h->drv[drv_index].queue = disk->queue;
+       h->drv[drv_index]->queue = disk->queue;
        add_disk(disk);
+       return 0;
+
+cleanup_queue:
+       blk_cleanup_queue(disk->queue);
+       disk->queue = NULL;
+init_queue_failure:
+       return -1;
 }
 
 /* This function will check the usage_count of the drive to be updated/added.
@@ -1662,7 +1827,8 @@ static void cciss_add_disk(ctlr_info_t *h, struct gendisk *disk,
  * is also the controller node.  Any changes to disk 0 will show up on
  * the next reboot.
  */
-static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
+static void cciss_update_drive_info(int ctlr, int drv_index, int first_time,
+       int via_ioctl)
 {
        ctlr_info_t *h = hba[ctlr];
        struct gendisk *disk;
@@ -1672,21 +1838,13 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
        unsigned long flags = 0;
        int ret = 0;
        drive_info_struct *drvinfo;
-       int was_only_controller_node;
 
        /* Get information about the disk and modify the driver structure */
        inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
-       drvinfo = kmalloc(sizeof(*drvinfo), GFP_KERNEL);
+       drvinfo = kzalloc(sizeof(*drvinfo), GFP_KERNEL);
        if (inq_buff == NULL || drvinfo == NULL)
                goto mem_msg;
 
-       /* See if we're trying to update the "controller node"
-        * this will happen the when the first logical drive gets
-        * created by ACU.
-        */
-       was_only_controller_node = (drv_index == 0 &&
-                               h->drv[0].raid_level == -1);
-
        /* testing to see if 16-byte CDBs are already being used */
        if (h->cciss_read == CCISS_READ_16) {
                cciss_read_capacity_16(h->ctlr, drv_index, 1,
@@ -1719,16 +1877,19 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
                                drvinfo->model, drvinfo->rev);
        cciss_get_serial_no(ctlr, drv_index, 1, drvinfo->serial_no,
                        sizeof(drvinfo->serial_no));
+       /* Save the lunid in case we deregister the disk, below. */
+       memcpy(drvinfo->LunID, h->drv[drv_index]->LunID,
+               sizeof(drvinfo->LunID));
 
        /* Is it the same disk we already know, and nothing's changed? */
-       if (h->drv[drv_index].raid_level != -1 &&
+       if (h->drv[drv_index]->raid_level != -1 &&
                ((memcmp(drvinfo->serial_no,
-                               h->drv[drv_index].serial_no, 16) == 0) &&
-               drvinfo->block_size == h->drv[drv_index].block_size &&
-               drvinfo->nr_blocks == h->drv[drv_index].nr_blocks &&
-               drvinfo->heads == h->drv[drv_index].heads &&
-               drvinfo->sectors == h->drv[drv_index].sectors &&
-               drvinfo->cylinders == h->drv[drv_index].cylinders))
+                               h->drv[drv_index]->serial_no, 16) == 0) &&
+               drvinfo->block_size == h->drv[drv_index]->block_size &&
+               drvinfo->nr_blocks == h->drv[drv_index]->nr_blocks &&
+               drvinfo->heads == h->drv[drv_index]->heads &&
+               drvinfo->sectors == h->drv[drv_index]->sectors &&
+               drvinfo->cylinders == h->drv[drv_index]->cylinders))
                        /* The disk is unchanged, nothing to update */
                        goto freeret;
 
@@ -1738,18 +1899,17 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
         * If the disk already exists then deregister it before proceeding
         * (unless it's the first disk (for the controller node).
         */
-       if (h->drv[drv_index].raid_level != -1 && drv_index != 0) {
+       if (h->drv[drv_index]->raid_level != -1 && drv_index != 0) {
                printk(KERN_WARNING "disk %d has changed.\n", drv_index);
                spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
-               h->drv[drv_index].busy_configuring = 1;
+               h->drv[drv_index]->busy_configuring = 1;
                spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
 
-               /* deregister_disk sets h->drv[drv_index].queue = NULL
+               /* deregister_disk sets h->drv[drv_index]->queue = NULL
                 * which keeps the interrupt handler from starting
                 * the queue.
                 */
-               ret = deregister_disk(h, drv_index, 0);
-               h->drv[drv_index].busy_configuring = 0;
+               ret = deregister_disk(h, drv_index, 0, via_ioctl);
        }
 
        /* If the disk is in use return */
@@ -1757,22 +1917,31 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
                goto freeret;
 
        /* Save the new information from cciss_geometry_inquiry
-        * and serial number inquiry.
+        * and serial number inquiry.  If the disk was deregistered
+        * above, then h->drv[drv_index] will be NULL.
         */
-       h->drv[drv_index].block_size = drvinfo->block_size;
-       h->drv[drv_index].nr_blocks = drvinfo->nr_blocks;
-       h->drv[drv_index].heads = drvinfo->heads;
-       h->drv[drv_index].sectors = drvinfo->sectors;
-       h->drv[drv_index].cylinders = drvinfo->cylinders;
-       h->drv[drv_index].raid_level = drvinfo->raid_level;
-       memcpy(h->drv[drv_index].serial_no, drvinfo->serial_no, 16);
-       memcpy(h->drv[drv_index].vendor, drvinfo->vendor, VENDOR_LEN + 1);
-       memcpy(h->drv[drv_index].model, drvinfo->model, MODEL_LEN + 1);
-       memcpy(h->drv[drv_index].rev, drvinfo->rev, REV_LEN + 1);
+       if (h->drv[drv_index] == NULL) {
+               drvinfo->device_initialized = 0;
+               h->drv[drv_index] = drvinfo;
+               drvinfo = NULL; /* so it won't be freed below. */
+       } else {
+               /* special case for cxd0 */
+               h->drv[drv_index]->block_size = drvinfo->block_size;
+               h->drv[drv_index]->nr_blocks = drvinfo->nr_blocks;
+               h->drv[drv_index]->heads = drvinfo->heads;
+               h->drv[drv_index]->sectors = drvinfo->sectors;
+               h->drv[drv_index]->cylinders = drvinfo->cylinders;
+               h->drv[drv_index]->raid_level = drvinfo->raid_level;
+               memcpy(h->drv[drv_index]->serial_no, drvinfo->serial_no, 16);
+               memcpy(h->drv[drv_index]->vendor, drvinfo->vendor,
+                       VENDOR_LEN + 1);
+               memcpy(h->drv[drv_index]->model, drvinfo->model, MODEL_LEN + 1);
+               memcpy(h->drv[drv_index]->rev, drvinfo->rev, REV_LEN + 1);
+       }
 
        ++h->num_luns;
        disk = h->gendisk[drv_index];
-       set_capacity(disk, h->drv[drv_index].nr_blocks);
+       set_capacity(disk, h->drv[drv_index]->nr_blocks);
 
        /* If it's not disk 0 (drv_index != 0)
         * or if it was disk 0, but there was previously
@@ -1780,8 +1949,15 @@ static void cciss_update_drive_info(int ctlr, int drv_index, int first_time)
         * (raid_leve == -1) then we want to update the
         * logical drive's information.
         */
-       if (drv_index || first_time)
-               cciss_add_disk(h, disk, drv_index);
+       if (drv_index || first_time) {
+               if (cciss_add_disk(h, disk, drv_index) != 0) {
+                       cciss_free_gendisk(h, drv_index);
+                       cciss_free_drive_info(h, drv_index);
+                       printk(KERN_WARNING "cciss:%d could not update "
+                               "disk %d\n", h->ctlr, drv_index);
+                       --h->num_luns;
+               }
+       }
 
 freeret:
        kfree(inq_buff);
@@ -1793,28 +1969,70 @@ mem_msg:
 }
 
 /* This function will find the first index of the controllers drive array
- * that has a -1 for the raid_level and will return that index.  This is
- * where new drives will be added.  If the index to be returned is greater
- * than the highest_lun index for the controller then highest_lun is set
- * to this new index.  If there are no available indexes then -1 is returned.
- * "controller_node" is used to know if this is a real logical drive, or just
- * the controller node, which determines if this counts towards highest_lun.
+ * that has a null drv pointer and allocate the drive info struct and
+ * will return that index   This is where new drives will be added.
+ * If the index to be returned is greater than the highest_lun index for
+ * the controller then highest_lun is set * to this new index.
+ * If there are no available indexes or if tha allocation fails, then -1
+ * is returned.  * "controller_node" is used to know if this is a real
+ * logical drive, or just the controller node, which determines if this
+ * counts towards highest_lun.
  */
-static int cciss_find_free_drive_index(int ctlr, int controller_node)
+static int cciss_alloc_drive_info(ctlr_info_t *h, int controller_node)
 {
        int i;
+       drive_info_struct *drv;
 
+       /* Search for an empty slot for our drive info */
        for (i = 0; i < CISS_MAX_LUN; i++) {
-               if (hba[ctlr]->drv[i].raid_level == -1) {
-                       if (i > hba[ctlr]->highest_lun)
-                               if (!controller_node)
-                                       hba[ctlr]->highest_lun = i;
+
+               /* if not cxd0 case, and it's occupied, skip it. */
+               if (h->drv[i] && i != 0)
+                       continue;
+               /*
+                * If it's cxd0 case, and drv is alloc'ed already, and a
+                * disk is configured there, skip it.
+                */
+               if (i == 0 && h->drv[i] && h->drv[i]->raid_level != -1)
+                       continue;
+
+               /*
+                * We've found an empty slot.  Update highest_lun
+                * provided this isn't just the fake cxd0 controller node.
+                */
+               if (i > h->highest_lun && !controller_node)
+                       h->highest_lun = i;
+
+               /* If adding a real disk at cxd0, and it's already alloc'ed */
+               if (i == 0 && h->drv[i] != NULL)
                        return i;
-               }
+
+               /*
+                * Found an empty slot, not already alloc'ed.  Allocate it.
+                * Mark it with raid_level == -1, so we know it's new later on.
+                */
+               drv = kzalloc(sizeof(*drv), GFP_KERNEL);
+               if (!drv)
+                       return -1;
+               drv->raid_level = -1; /* so we know it's new */
+               h->drv[i] = drv;
+               return i;
        }
        return -1;
 }
 
+static void cciss_free_drive_info(ctlr_info_t *h, int drv_index)
+{
+       kfree(h->drv[drv_index]);
+       h->drv[drv_index] = NULL;
+}
+
+static void cciss_free_gendisk(ctlr_info_t *h, int drv_index)
+{
+       put_disk(h->gendisk[drv_index]);
+       h->gendisk[drv_index] = NULL;
+}
+
 /* cciss_add_gendisk finds a free hba[]->drv structure
  * and allocates a gendisk if needed, and sets the lunid
  * in the drvinfo structure.   It returns the index into
@@ -1824,13 +2042,15 @@ static int cciss_find_free_drive_index(int ctlr, int controller_node)
  * a means to talk to the controller in case no logical
  * drives have yet been configured.
  */
-static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node)
+static int cciss_add_gendisk(ctlr_info_t *h, unsigned char lunid[],
+       int controller_node)
 {
        int drv_index;
 
-       drv_index = cciss_find_free_drive_index(h->ctlr, controller_node);
+       drv_index = cciss_alloc_drive_info(h, controller_node);
        if (drv_index == -1)
                return -1;
+
        /*Check if the gendisk needs to be allocated */
        if (!h->gendisk[drv_index]) {
                h->gendisk[drv_index] =
@@ -1839,23 +2059,24 @@ static int cciss_add_gendisk(ctlr_info_t *h, __u32 lunid, int controller_node)
                        printk(KERN_ERR "cciss%d: could not "
                                "allocate a new disk %d\n",
                                h->ctlr, drv_index);
-                       return -1;
+                       goto err_free_drive_info;
                }
        }
-       h->drv[drv_index].LunID = lunid;
-       if (cciss_create_ld_sysfs_entry(h, &h->drv[drv_index], drv_index))
+       memcpy(h->drv[drv_index]->LunID, lunid,
+               sizeof(h->drv[drv_index]->LunID));
+       if (cciss_create_ld_sysfs_entry(h, drv_index))
                goto err_free_disk;
-
        /* Don't need to mark this busy because nobody */
        /* else knows about this disk yet to contend */
        /* for access to it. */
-       h->drv[drv_index].busy_configuring = 0;
+       h->drv[drv_index]->busy_configuring = 0;
        wmb();
        return drv_index;
 
 err_free_disk:
-       put_disk(h->gendisk[drv_index]);
-       h->gendisk[drv_index] = NULL;
+       cciss_free_gendisk(h, drv_index);
+err_free_drive_info:
+       cciss_free_drive_info(h, drv_index);
        return -1;
 }
 
@@ -1872,21 +2093,25 @@ static void cciss_add_controller_node(ctlr_info_t *h)
        if (h->gendisk[0] != NULL) /* already did this? Then bail. */
                return;
 
-       drv_index = cciss_add_gendisk(h, 0, 1);
-       if (drv_index == -1) {
-               printk(KERN_WARNING "cciss%d: could not "
-                       "add disk 0.\n", h->ctlr);
-               return;
-       }
-       h->drv[drv_index].block_size = 512;
-       h->drv[drv_index].nr_blocks = 0;
-       h->drv[drv_index].heads = 0;
-       h->drv[drv_index].sectors = 0;
-       h->drv[drv_index].cylinders = 0;
-       h->drv[drv_index].raid_level = -1;
-       memset(h->drv[drv_index].serial_no, 0, 16);
+       drv_index = cciss_add_gendisk(h, CTLR_LUNID, 1);
+       if (drv_index == -1)
+               goto error;
+       h->drv[drv_index]->block_size = 512;
+       h->drv[drv_index]->nr_blocks = 0;
+       h->drv[drv_index]->heads = 0;
+       h->drv[drv_index]->sectors = 0;
+       h->drv[drv_index]->cylinders = 0;
+       h->drv[drv_index]->raid_level = -1;
+       memset(h->drv[drv_index]->serial_no, 0, 16);
        disk = h->gendisk[drv_index];
-       cciss_add_disk(h, disk, drv_index);
+       if (cciss_add_disk(h, disk, drv_index) == 0)
+               return;
+       cciss_free_gendisk(h, drv_index);
+       cciss_free_drive_info(h, drv_index);
+error:
+       printk(KERN_WARNING "cciss%d: could not "
+               "add disk 0.\n", h->ctlr);
+       return;
 }
 
 /* This function will add and remove logical drives from the Logical
@@ -1897,7 +2122,8 @@ static void cciss_add_controller_node(ctlr_info_t *h)
  * INPUT
  * h           = The controller to perform the operations on
  */
-static int rebuild_lun_table(ctlr_info_t *h, int first_time)
+static int rebuild_lun_table(ctlr_info_t *h, int first_time,
+       int via_ioctl)
 {
        int ctlr = h->ctlr;
        int num_luns;
@@ -1907,7 +2133,7 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
        int i;
        int drv_found;
        int drv_index = 0;
-       __u32 lunid = 0;
+       unsigned char lunid[8] = CTLR_LUNID;
        unsigned long flags;
 
        if (!capable(CAP_SYS_RAWIO))
@@ -1960,13 +2186,13 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
                drv_found = 0;
 
                /* skip holes in the array from already deleted drives */
-               if (h->drv[i].raid_level == -1)
+               if (h->drv[i] == NULL)
                        continue;
 
                for (j = 0; j < num_luns; j++) {
-                       memcpy(&lunid, &ld_buff->LUN[j][0], 4);
-                       lunid = le32_to_cpu(lunid);
-                       if (h->drv[i].LunID == lunid) {
+                       memcpy(lunid, &ld_buff->LUN[j][0], sizeof(lunid));
+                       if (memcmp(h->drv[i]->LunID, lunid,
+                               sizeof(lunid)) == 0) {
                                drv_found = 1;
                                break;
                        }
@@ -1974,11 +2200,11 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
                if (!drv_found) {
                        /* Deregister it from the OS, it's gone. */
                        spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
-                       h->drv[i].busy_configuring = 1;
+                       h->drv[i]->busy_configuring = 1;
                        spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
-                       return_code = deregister_disk(h, i, 1);
-                       cciss_destroy_ld_sysfs_entry(&h->drv[i]);
-                       h->drv[i].busy_configuring = 0;
+                       return_code = deregister_disk(h, i, 1, via_ioctl);
+                       if (h->drv[i] != NULL)
+                               h->drv[i]->busy_configuring = 0;
                }
        }
 
@@ -1992,17 +2218,16 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
 
                drv_found = 0;
 
-               memcpy(&lunid, &ld_buff->LUN[i][0], 4);
-               lunid = le32_to_cpu(lunid);
-
+               memcpy(lunid, &ld_buff->LUN[i][0], sizeof(lunid));
                /* Find if the LUN is already in the drive array
                 * of the driver.  If so then update its info
                 * if not in use.  If it does not exist then find
                 * the first free index and add it.
                 */
                for (j = 0; j <= h->highest_lun; j++) {
-                       if (h->drv[j].raid_level != -1 &&
-                               h->drv[j].LunID == lunid) {
+                       if (h->drv[j] != NULL &&
+                               memcmp(h->drv[j]->LunID, lunid,
+                                       sizeof(h->drv[j]->LunID)) == 0) {
                                drv_index = j;
                                drv_found = 1;
                                break;
@@ -2015,7 +2240,8 @@ static int rebuild_lun_table(ctlr_info_t *h, int first_time)
                        if (drv_index == -1)
                                goto freeret;
                }
-               cciss_update_drive_info(ctlr, drv_index, first_time);
+               cciss_update_drive_info(ctlr, drv_index, first_time,
+                       via_ioctl);
        }               /* end for */
 
 freeret:
@@ -2032,6 +2258,25 @@ mem_msg:
        goto freeret;
 }
 
+static void cciss_clear_drive_info(drive_info_struct *drive_info)
+{
+       /* zero out the disk size info */
+       drive_info->nr_blocks = 0;
+       drive_info->block_size = 0;
+       drive_info->heads = 0;
+       drive_info->sectors = 0;
+       drive_info->cylinders = 0;
+       drive_info->raid_level = -1;
+       memset(drive_info->serial_no, 0, sizeof(drive_info->serial_no));
+       memset(drive_info->model, 0, sizeof(drive_info->model));
+       memset(drive_info->rev, 0, sizeof(drive_info->rev));
+       memset(drive_info->vendor, 0, sizeof(drive_info->vendor));
+       /*
+        * don't clear the LUNID though, we need to remember which
+        * one this one is.
+        */
+}
+
 /* This function will deregister the disk and it's queue from the
  * kernel.  It must be called with the controller lock held and the
  * drv structures busy_configuring flag set.  It's parameters are:
@@ -2046,43 +2291,48 @@ mem_msg:
  *             the disk in preparation for re-adding it.  In this case
  *             the highest_lun should be left unchanged and the LunID
  *             should not be cleared.
+ * via_ioctl
+ *    This indicates whether we've reached this path via ioctl.
+ *    This affects the maximum usage count allowed for c0d0 to be messed with.
+ *    If this path is reached via ioctl(), then the max_usage_count will
+ *    be 1, as the process calling ioctl() has got to have the device open.
+ *    If we get here via sysfs, then the max usage count will be zero.
 */
 static int deregister_disk(ctlr_info_t *h, int drv_index,
-                          int clear_all)
+                          int clear_all, int via_ioctl)
 {
        int i;
        struct gendisk *disk;
        drive_info_struct *drv;
+       int recalculate_highest_lun;
 
        if (!capable(CAP_SYS_RAWIO))
                return -EPERM;
 
-       drv = &h->drv[drv_index];
+       drv = h->drv[drv_index];
        disk = h->gendisk[drv_index];
 
        /* make sure logical volume is NOT is use */
        if (clear_all || (h->gendisk[0] == disk)) {
-               if (drv->usage_count > 1)
+               if (drv->usage_count > via_ioctl)
                        return -EBUSY;
        } else if (drv->usage_count > 0)
                return -EBUSY;
 
+       recalculate_highest_lun = (drv == h->drv[h->highest_lun]);
+
        /* invalidate the devices and deregister the disk.  If it is disk
         * zero do not deregister it but just zero out it's values.  This
         * allows us to delete disk zero but keep the controller registered.
         */
        if (h->gendisk[0] != disk) {
                struct request_queue *q = disk->queue;
-               if (disk->flags & GENHD_FL_UP)
+               if (disk->flags & GENHD_FL_UP) {
+                       cciss_destroy_ld_sysfs_entry(h, drv_index, 0);
                        del_gendisk(disk);
-               if (q) {
-                       blk_cleanup_queue(q);
-                       /* Set drv->queue to NULL so that we do not try
-                        * to call blk_start_queue on this queue in the
-                        * interrupt handler
-                        */
-                       drv->queue = NULL;
                }
+               if (q)
+                       blk_cleanup_queue(q);
                /* If clear_all is set then we are deleting the logical
                 * drive, not just refreshing its info.  For drives
                 * other than disk 0 we will call put_disk.  We do not
@@ -2105,34 +2355,20 @@ static int deregister_disk(ctlr_info_t *h, int drv_index,
                }
        } else {
                set_capacity(disk, 0);
+               cciss_clear_drive_info(drv);
        }
 
        --h->num_luns;
-       /* zero out the disk size info */
-       drv->nr_blocks = 0;
-       drv->block_size = 0;
-       drv->heads = 0;
-       drv->sectors = 0;
-       drv->cylinders = 0;
-       drv->raid_level = -1;   /* This can be used as a flag variable to
-                                * indicate that this element of the drive
-                                * array is free.
-                                */
-
-       if (clear_all) {
-               /* check to see if it was the last disk */
-               if (drv == h->drv + h->highest_lun) {
-                       /* if so, find the new hightest lun */
-                       int i, newhighest = -1;
-                       for (i = 0; i <= h->highest_lun; i++) {
-                               /* if the disk has size > 0, it is available */
-                               if (h->drv[i].heads)
-                                       newhighest = i;
-                       }
-                       h->highest_lun = newhighest;
-               }
 
-               drv->LunID = 0;
+       /* if it was the last disk, find the new hightest lun */
+       if (clear_all && recalculate_highest_lun) {
+               int i, newhighest = -1;
+               for (i = 0; i <= h->highest_lun; i++) {
+                       /* if the disk has size > 0, it is available */
+                       if (h->drv[i] && h->drv[i]->heads)
+                               newhighest = i;
+               }
+               h->highest_lun = newhighest;
        }
        return 0;
 }
@@ -2479,8 +2715,6 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
        } else {                /* Get geometry failed */
                printk(KERN_WARNING "cciss: reading geometry failed\n");
        }
-       printk(KERN_INFO "      heads=%d, sectors=%d, cylinders=%d\n\n",
-              drv->heads, drv->sectors, drv->cylinders);
 }
 
 static void
@@ -2514,9 +2748,6 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
                *total_size = 0;
                *block_size = BLOCK_SIZE;
        }
-       if (*total_size != 0)
-               printk(KERN_INFO "      blocks= %llu block_size= %d\n",
-               (unsigned long long)*total_size+1, *block_size);
        kfree(buf);
 }
 
@@ -2568,7 +2799,8 @@ static int cciss_revalidate(struct gendisk *disk)
        InquiryData_struct *inq_buff = NULL;
 
        for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
-               if (h->drv[logvol].LunID == drv->LunID) {
+               if (memcmp(h->drv[logvol]->LunID, drv->LunID,
+                       sizeof(drv->LunID)) == 0) {
                        FOUND = 1;
                        break;
                }
@@ -3053,8 +3285,7 @@ static void do_cciss_request(struct request_queue *q)
        /* The first 2 bits are reserved for controller error reporting. */
        c->Header.Tag.lower = (c->cmdindex << 3);
        c->Header.Tag.lower |= 0x04;    /* flag for direct lookup. */
-       c->Header.LUN.LogDev.VolId = drv->LunID;
-       c->Header.LUN.LogDev.Mode = 1;
+       memcpy(&c->Header.LUN, drv->LunID, sizeof(drv->LunID));
        c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
        c->Request.Type.Type = TYPE_CMD;        // It is a command.
        c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -3232,20 +3463,121 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+/**
+ * add_to_scan_list() - add controller to rescan queue
+ * @h:               Pointer to the controller.
+ *
+ * Adds the controller to the rescan queue if not already on the queue.
+ *
+ * returns 1 if added to the queue, 0 if skipped (could be on the
+ * queue already, or the controller could be initializing or shutting
+ * down).
+ **/
+static int add_to_scan_list(struct ctlr_info *h)
+{
+       struct ctlr_info *test_h;
+       int found = 0;
+       int ret = 0;
+
+       if (h->busy_initializing)
+               return 0;
+
+       if (!mutex_trylock(&h->busy_shutting_down))
+               return 0;
+
+       mutex_lock(&scan_mutex);
+       list_for_each_entry(test_h, &scan_q, scan_list) {
+               if (test_h == h) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found && !h->busy_scanning) {
+               INIT_COMPLETION(h->scan_wait);
+               list_add_tail(&h->scan_list, &scan_q);
+               ret = 1;
+       }
+       mutex_unlock(&scan_mutex);
+       mutex_unlock(&h->busy_shutting_down);
+
+       return ret;
+}
+
+/**
+ * remove_from_scan_list() - remove controller from rescan queue
+ * @h:                    Pointer to the controller.
+ *
+ * Removes the controller from the rescan queue if present. Blocks if
+ * the controller is currently conducting a rescan.
+ **/
+static void remove_from_scan_list(struct ctlr_info *h)
+{
+       struct ctlr_info *test_h, *tmp_h;
+       int scanning = 0;
+
+       mutex_lock(&scan_mutex);
+       list_for_each_entry_safe(test_h, tmp_h, &scan_q, scan_list) {
+               if (test_h == h) {
+                       list_del(&h->scan_list);
+                       complete_all(&h->scan_wait);
+                       mutex_unlock(&scan_mutex);
+                       return;
+               }
+       }
+       if (&h->busy_scanning)
+               scanning = 0;
+       mutex_unlock(&scan_mutex);
+
+       if (scanning)
+               wait_for_completion(&h->scan_wait);
+}
+
+/**
+ * scan_thread() - kernel thread used to rescan controllers
+ * @data:       Ignored.
+ *
+ * A kernel thread used scan for drive topology changes on
+ * controllers. The thread processes only one controller at a time
+ * using a queue.  Controllers are added to the queue using
+ * add_to_scan_list() and removed from the queue either after done
+ * processing or using remove_from_scan_list().
+ *
+ * returns 0.
+ **/
 static int scan_thread(void *data)
 {
-       ctlr_info_t *h = data;
-       int rc;
-       DECLARE_COMPLETION_ONSTACK(wait);
-       h->rescan_wait = &wait;
+       struct ctlr_info *h;
 
-       for (;;) {
-               rc = wait_for_completion_interruptible(&wait);
+       while (1) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
                if (kthread_should_stop())
                        break;
-               if (!rc)
-                       rebuild_lun_table(h, 0);
+
+               while (1) {
+                       mutex_lock(&scan_mutex);
+                       if (list_empty(&scan_q)) {
+                               mutex_unlock(&scan_mutex);
+                               break;
+                       }
+
+                       h = list_entry(scan_q.next,
+                                      struct ctlr_info,
+                                      scan_list);
+                       list_del(&h->scan_list);
+                       h->busy_scanning = 1;
+                       mutex_unlock(&scan_mutex);
+
+                       if (h) {
+                               rebuild_lun_table(h, 0, 0);
+                               complete_all(&h->scan_wait);
+                               mutex_lock(&scan_mutex);
+                               h->busy_scanning = 0;
+                               mutex_unlock(&scan_mutex);
+                       }
+               }
        }
+
        return 0;
 }
 
@@ -3268,8 +3600,8 @@ static int check_for_unit_attention(ctlr_info_t *h, CommandList_struct *c)
        case REPORT_LUNS_CHANGED:
                printk(KERN_WARNING "cciss%d: report LUN data "
                        "changed\n", h->ctlr);
-               if (h->rescan_wait)
-                       complete(h->rescan_wait);
+               add_to_scan_list(h);
+               wake_up_process(cciss_scan_thread);
                return 1;
        break;
        case POWER_OR_RESET:
@@ -3489,7 +3821,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
                if (scratchpad == CCISS_FIRMWARE_READY)
                        break;
                set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(HZ / 10);      /* wait 100ms */
+               schedule_timeout(msecs_to_jiffies(100));        /* wait 100ms */
        }
        if (scratchpad != CCISS_FIRMWARE_READY) {
                printk(KERN_WARNING "cciss: Board not ready.  Timed out.\n");
@@ -3615,7 +3947,7 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
                        break;
                /* delay and try again */
                set_current_state(TASK_INTERRUPTIBLE);
-               schedule_timeout(10);
+               schedule_timeout(msecs_to_jiffies(1));
        }
 
 #ifdef CCISS_DEBUG
@@ -3669,15 +4001,16 @@ Enomem:
        return -1;
 }
 
-static void free_hba(int i)
+static void free_hba(int n)
 {
-       ctlr_info_t *p = hba[i];
-       int n;
+       ctlr_info_t *h = hba[n];
+       int i;
 
-       hba[i] = NULL;
-       for (n = 0; n < CISS_MAX_LUN; n++)
-               put_disk(p->gendisk[n]);
-       kfree(p);
+       hba[n] = NULL;
+       for (i = 0; i < h->highest_lun + 1; i++)
+               if (h->gendisk[i] != NULL)
+                       put_disk(h->gendisk[i]);
+       kfree(h);
 }
 
 /* Send a message CDB to the firmware. */
@@ -3918,6 +4251,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        hba[i]->busy_initializing = 1;
        INIT_HLIST_HEAD(&hba[i]->cmpQ);
        INIT_HLIST_HEAD(&hba[i]->reqQ);
+       mutex_init(&hba[i]->busy_shutting_down);
 
        if (cciss_pci_init(hba[i], pdev) != 0)
                goto clean0;
@@ -3926,6 +4260,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        hba[i]->ctlr = i;
        hba[i]->pdev = pdev;
 
+       init_completion(&hba[i]->scan_wait);
+
        if (cciss_create_hba_sysfs_entry(hba[i]))
                goto clean0;
 
@@ -4001,8 +4337,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        hba[i]->num_luns = 0;
        hba[i]->highest_lun = -1;
        for (j = 0; j < CISS_MAX_LUN; j++) {
-               hba[i]->drv[j].raid_level = -1;
-               hba[i]->drv[j].queue = NULL;
+               hba[i]->drv[j] = NULL;
                hba[i]->gendisk[j] = NULL;
        }
 
@@ -4035,14 +4370,8 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 
        hba[i]->cciss_max_sectors = 2048;
 
+       rebuild_lun_table(hba[i], 1, 0);
        hba[i]->busy_initializing = 0;
-
-       rebuild_lun_table(hba[i], 1);
-       hba[i]->cciss_scan_thread = kthread_run(scan_thread, hba[i],
-                               "cciss_scan%02d", i);
-       if (IS_ERR(hba[i]->cciss_scan_thread))
-               return PTR_ERR(hba[i]->cciss_scan_thread);
-
        return 1;
 
 clean4:
@@ -4063,12 +4392,7 @@ clean1:
        cciss_destroy_hba_sysfs_entry(hba[i]);
 clean0:
        hba[i]->busy_initializing = 0;
-       /* cleanup any queues that may have been initialized */
-       for (j=0; j <= hba[i]->highest_lun; j++){
-               drive_info_struct *drv = &(hba[i]->drv[j]);
-               if (drv->queue)
-                       blk_cleanup_queue(drv->queue);
-       }
+
        /*
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
@@ -4125,8 +4449,9 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
                return;
        }
 
-       kthread_stop(hba[i]->cciss_scan_thread);
+       mutex_lock(&hba[i]->busy_shutting_down);
 
+       remove_from_scan_list(hba[i]);
        remove_proc_entry(hba[i]->devname, proc_cciss);
        unregister_blkdev(hba[i]->major, hba[i]->devname);
 
@@ -4136,8 +4461,10 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
                if (disk) {
                        struct request_queue *q = disk->queue;
 
-                       if (disk->flags & GENHD_FL_UP)
+                       if (disk->flags & GENHD_FL_UP) {
+                               cciss_destroy_ld_sysfs_entry(hba[i], j, 1);
                                del_gendisk(disk);
+                       }
                        if (q)
                                blk_cleanup_queue(q);
                }
@@ -4170,6 +4497,7 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
        pci_release_regions(pdev);
        pci_set_drvdata(pdev, NULL);
        cciss_destroy_hba_sysfs_entry(hba[i]);
+       mutex_unlock(&hba[i]->busy_shutting_down);
        free_hba(i);
 }
 
@@ -4202,15 +4530,25 @@ static int __init cciss_init(void)
        if (err)
                return err;
 
+       /* Start the scan thread */
+       cciss_scan_thread = kthread_run(scan_thread, NULL, "cciss_scan");
+       if (IS_ERR(cciss_scan_thread)) {
+               err = PTR_ERR(cciss_scan_thread);
+               goto err_bus_unregister;
+       }
+
        /* Register for our PCI devices */
        err = pci_register_driver(&cciss_pci_driver);
        if (err)
-               goto err_bus_register;
+               goto err_thread_stop;
 
-       return 0;
+       return err;
 
-err_bus_register:
+err_thread_stop:
+       kthread_stop(cciss_scan_thread);
+err_bus_unregister:
        bus_unregister(&cciss_bus_type);
+
        return err;
 }
 
@@ -4227,6 +4565,7 @@ static void __exit cciss_cleanup(void)
                        cciss_remove_one(hba[i]->pdev);
                }
        }
+       kthread_stop(cciss_scan_thread);
        remove_proc_entry("driver/cciss", NULL);
        bus_unregister(&cciss_bus_type);
 }
index 06a5db25b298ebf400c99ac1c8fa200e208d10ae..31524cf42c77360645424a9c85e68a9651ba8422 100644 (file)
@@ -2,6 +2,7 @@
 #define CCISS_H
 
 #include <linux/genhd.h>
+#include <linux/mutex.h>
 
 #include "cciss_cmd.h"
 
@@ -29,7 +30,7 @@ struct access_method {
 };
 typedef struct _drive_info_struct
 {
-       __u32   LunID;  
+       unsigned char LunID[8];
        int     usage_count;
        struct request_queue *queue;
        sector_t nr_blocks;
@@ -51,6 +52,7 @@ typedef struct _drive_info_struct
        char vendor[VENDOR_LEN + 1]; /* SCSI vendor string */
        char model[MODEL_LEN + 1];   /* SCSI model string */
        char rev[REV_LEN + 1];       /* SCSI revision string */
+       char device_initialized;     /* indicates whether dev is initialized */
 } drive_info_struct;
 
 struct ctlr_info 
@@ -86,7 +88,7 @@ struct ctlr_info
        BYTE    cciss_read_capacity;
 
        // information about each logical volume
-       drive_info_struct drv[CISS_MAX_LUN];
+       drive_info_struct *drv[CISS_MAX_LUN];
 
        struct access_method access;
 
@@ -108,6 +110,8 @@ struct ctlr_info
        int                     nr_frees; 
        int                     busy_configuring;
        int                     busy_initializing;
+       int                     busy_scanning;
+       struct mutex            busy_shutting_down;
 
        /* This element holds the zero based queue number of the last
         * queue to be started.  It is used for fairness.
@@ -122,8 +126,8 @@ struct ctlr_info
        /* and saved for later processing */
 #endif
        unsigned char alive;
-       struct completion *rescan_wait;
-       struct task_struct *cciss_scan_thread;
+       struct list_head scan_list;
+       struct completion scan_wait;
        struct device dev;
 };
 
index b82d438e2607cc2c430e4b170470ac29e47c3fb2..6422651ec364197ed9418f4a3bafb966208a8417 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/blkpg.h>
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
@@ -177,7 +178,6 @@ static int cpqarray_register_ctlr(int ctlr, struct pci_dev *pdev);
 
 #ifdef CONFIG_PROC_FS
 static void ida_procinit(int i);
-static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
 #else
 static void ida_procinit(int i) {}
 #endif
@@ -206,6 +206,7 @@ static const struct block_device_operations ida_fops  = {
 #ifdef CONFIG_PROC_FS
 
 static struct proc_dir_entry *proc_array;
+static const struct file_operations ida_proc_fops;
 
 /*
  * Get us a file in /proc/array that says something about each controller.
@@ -218,19 +219,16 @@ static void __init ida_procinit(int i)
                if (!proc_array) return;
        }
 
-       create_proc_read_entry(hba[i]->devname, 0, proc_array,
-                              ida_proc_get_info, hba[i]);
+       proc_create_data(hba[i]->devname, 0, proc_array, &ida_proc_fops, hba[i]);
 }
 
 /*
  * Report information about this controller.
  */
-static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+static int ida_proc_show(struct seq_file *m, void *v)
 {
-       off_t pos = 0;
-       off_t len = 0;
-       int size, i, ctlr;
-       ctlr_info_t *h = (ctlr_info_t*)data;
+       int i, ctlr;
+       ctlr_info_t *h = (ctlr_info_t*)m->private;
        drv_info_t *drv;
 #ifdef CPQ_PROC_PRINT_QUEUES
        cmdlist_t *c;
@@ -238,7 +236,7 @@ static int ida_proc_get_info(char *buffer, char **start, off_t offset, int lengt
 #endif
 
        ctlr = h->ctlr;
-       size = sprintf(buffer, "%s:  Compaq %s Controller\n"
+       seq_printf(m, "%s:  Compaq %s Controller\n"
                "       Board ID: 0x%08lx\n"
                "       Firmware Revision: %c%c%c%c\n"
                "       Controller Sig: 0x%08lx\n"
@@ -258,55 +256,54 @@ static int ida_proc_get_info(char *buffer, char **start, off_t offset, int lengt
                h->log_drives, h->phys_drives,
                h->Qdepth, h->maxQsinceinit);
 
-       pos += size; len += size;
-       
-       size = sprintf(buffer+len, "Logical Drive Info:\n");
-       pos += size; len += size;
+       seq_puts(m, "Logical Drive Info:\n");
 
        for(i=0; i<h->log_drives; i++) {
                drv = &h->drv[i];
-               size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
+               seq_printf(m, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
                                ctlr, i, drv->blk_size, drv->nr_blks);
-               pos += size; len += size;
        }
 
 #ifdef CPQ_PROC_PRINT_QUEUES
        spin_lock_irqsave(IDA_LOCK(h->ctlr), flags); 
-       size = sprintf(buffer+len, "\nCurrent Queues:\n");
-       pos += size; len += size;
+       seq_puts(m, "\nCurrent Queues:\n");
 
        c = h->reqQ;
-       size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
+       seq_printf(m, "reqQ = %p", c);
        if (c) c=c->next;
        while(c && c != h->reqQ) {
-               size = sprintf(buffer+len, "->%p", c);
-               pos += size; len += size;
+               seq_printf(m, "->%p", c);
                c=c->next;
        }
 
        c = h->cmpQ;
-       size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
+       seq_printf(m, "\ncmpQ = %p", c);
        if (c) c=c->next;
        while(c && c != h->cmpQ) {
-               size = sprintf(buffer+len, "->%p", c);
-               pos += size; len += size;
+               seq_printf(m, "->%p", c);
                c=c->next;
        }
 
-       size = sprintf(buffer+len, "\n"); pos += size; len += size;
+       seq_putc(m, '\n');
        spin_unlock_irqrestore(IDA_LOCK(h->ctlr), flags); 
 #endif
-       size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n",
+       seq_printf(m, "nr_allocs = %d\nnr_frees = %d\n",
                        h->nr_allocs, h->nr_frees);
-       pos += size; len += size;
-
-       *eof = 1;
-       *start = buffer+offset;
-       len -= offset;
-       if (len>length)
-               len = length;
-       return len;
+       return 0;
+}
+
+static int ida_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ida_proc_show, PDE(inode)->data);
 }
+
+static const struct file_operations ida_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ida_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
 #endif /* CONFIG_PROC_FS */
 
 module_param_array(eisa, int, NULL, 0);
index 52e06589821d8ed53edef8bf96e02e0a95a9d430..045c930e6320c89e9ac2f28fadee74e1c3607790 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/errno.h>       /* for -EBUSY */
 #include <linux/ioport.h>      /* for request_region */
 #include <linux/delay.h>       /* for loops_per_jiffy */
+#include <linux/sched.h>
 #include <linux/smp_lock.h>    /* cycle_kernel_lock() */
 #include <asm/io.h>            /* for inb_p, outb_p, inb, outb, etc. */
 #include <asm/uaccess.h>       /* for get_user, etc. */
index 41fc11dc921c70260e89551f111a8f73d97a3b10..65545de3dbf4ded375e55467fcaf5a8360000dfd 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/errno.h>
 #include <asm/system.h>
 #include <linux/poll.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/ipmi.h>
index 09050797c76a26546ca5fa2d4ed3e165cc9455b9..ec5e3f8df648ba1e719836a9b8349246005ba685 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/errno.h>
 #include <asm/system.h>
 #include <linux/poll.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
index ced186d7e9a9d16552fcf3d73a95203303a8251a..5089331544ed5336e682fdec039be94068314102 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/mutex.h>
 #include <linux/poll.h>
 #include <linux/preempt.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/time.h>
 #include <linux/uaccess.h>
index 420a96e7f2dbb1a31d299f70daa07f22e8b95db3..051d1ebbd2876b68db9df2209161b13da7e8d7bb 100644 (file)
@@ -939,7 +939,7 @@ static int __init ibft_init(void)
 
        if (ibft_addr) {
                printk(KERN_INFO "iBFT detected at 0x%llx.\n",
-                      (u64)virt_to_phys((void *)ibft_addr));
+                      (u64)isa_virt_to_bus(ibft_addr));
 
                rc = ibft_check_device();
                if (rc)
index d53fbbfefa3ee2893ece684f2a5cb25eddf77b04..dfb15c06c88ff8482de2b03164679633748848b7 100644 (file)
@@ -65,10 +65,10 @@ void __init reserve_ibft_region(void)
                 * so skip that area */
                if (pos == VGA_MEM)
                        pos += VGA_SIZE;
-               virt = phys_to_virt(pos);
+               virt = isa_bus_to_virt(pos);
                if (memcmp(virt, IBFT_SIGN, IBFT_SIGN_LEN) == 0) {
                        unsigned long *addr =
-                           (unsigned long *)phys_to_virt(pos + 4);
+                           (unsigned long *)isa_bus_to_virt(pos + 4);
                        len = *addr;
                        /* if the length of the table extends past 1M,
                         * the table cannot be valid. */
index 0c6639ea03dd1748076dd8742035f1f154603cd9..ba05275e5104f7d30771254b82e3f35a48017bfa 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/major.h>
 #include <linux/hid.h>
 #include <linux/mutex.h>
+#include <linux/sched.h>
 #include <linux/smp_lock.h>
 
 #include <linux/hidraw.h>
index 6c9a04136e0aefb9a1b4430146b1453ed9acbe3f..00d975eb5b83dcc86ddd8d5f5b6846c9d370f6e6 100644 (file)
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 
-static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/* Insmod parameters */
-I2C_CLIENT_INSMOD_1(ltc4215);
-
 /* Here are names of the chip's registers (a.k.a. commands) */
 enum ltc4215_cmd {
        LTC4215_CONTROL                 = 0x00, /* rw */
@@ -246,9 +241,13 @@ static const struct attribute_group ltc4215_group = {
 static int ltc4215_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
+       struct i2c_adapter *adapter = client->adapter;
        struct ltc4215_data *data;
        int ret;
 
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data) {
                ret = -ENOMEM;
@@ -294,56 +293,20 @@ static int ltc4215_remove(struct i2c_client *client)
        return 0;
 }
 
-static int ltc4215_detect(struct i2c_client *client,
-                         int kind,
-                         struct i2c_board_info *info)
-{
-       struct i2c_adapter *adapter = client->adapter;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -ENODEV;
-
-       if (kind < 0) {         /* probed detection - check the chip type */
-               s32 v;          /* 8 bits from the chip, or -ERRNO */
-
-               /*
-                * Register 0x01 bit b7 is reserved, expect 0
-                * Register 0x03 bit b6 and b7 are reserved, expect 0
-                */
-               v = i2c_smbus_read_byte_data(client, LTC4215_ALERT);
-               if (v < 0 || (v & (1 << 7)) != 0)
-                       return -ENODEV;
-
-               v = i2c_smbus_read_byte_data(client, LTC4215_FAULT);
-               if (v < 0 || (v & ((1 << 6) | (1 << 7))) != 0)
-                               return -ENODEV;
-       }
-
-       strlcpy(info->type, "ltc4215", I2C_NAME_SIZE);
-       dev_info(&adapter->dev, "ltc4215 %s at address 0x%02x\n",
-                       kind < 0 ? "probed" : "forced",
-                       client->addr);
-
-       return 0;
-}
-
 static const struct i2c_device_id ltc4215_id[] = {
-       { "ltc4215", ltc4215 },
+       { "ltc4215", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ltc4215_id);
 
 /* This is the driver that will be inserted */
 static struct i2c_driver ltc4215_driver = {
-       .class          = I2C_CLASS_HWMON,
        .driver = {
                .name   = "ltc4215",
        },
        .probe          = ltc4215_probe,
        .remove         = ltc4215_remove,
        .id_table       = ltc4215_id,
-       .detect         = ltc4215_detect,
-       .address_data   = &addr_data,
 };
 
 static int __init ltc4215_init(void)
index e389643336126897d9abd8adf08cfe3464425712..65c232a9d0c5a917b533e2aeac34c2c13aa4fba5 100644 (file)
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 
-/* Valid addresses are 0x20 - 0x3f
- *
- * For now, we do not probe, since some of these addresses
- * are known to be unfriendly to probing */
-static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/* Insmod parameters */
-I2C_CLIENT_INSMOD_1(ltc4245);
-
 /* Here are names of the chip's registers (a.k.a. commands) */
 enum ltc4245_cmd {
        LTC4245_STATUS                  = 0x00, /* readonly */
@@ -369,9 +360,13 @@ static const struct attribute_group ltc4245_group = {
 static int ltc4245_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
+       struct i2c_adapter *adapter = client->adapter;
        struct ltc4245_data *data;
        int ret;
 
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data) {
                ret = -ENOMEM;
@@ -418,136 +413,20 @@ static int ltc4245_remove(struct i2c_client *client)
        return 0;
 }
 
-/* Check that some bits in a control register appear at all possible
- * locations without changing value
- *
- * @client: the i2c client to use
- * @reg: the register to read
- * @bits: the bits to check (0xff checks all bits,
- *                           0x03 checks only the last two bits)
- *
- * return -ERRNO if the register read failed
- * return -ENODEV if the register value doesn't stay constant at all
- * possible addresses
- *
- * return 0 for success
- */
-static int ltc4245_check_control_reg(struct i2c_client *client, u8 reg, u8 bits)
-{
-       int i;
-       s32 v, voff1, voff2;
-
-       /* Read register and check for error */
-       v = i2c_smbus_read_byte_data(client, reg);
-       if (v < 0)
-               return v;
-
-       v &= bits;
-
-       for (i = 0x00; i < 0xff; i += 0x20) {
-
-               voff1 = i2c_smbus_read_byte_data(client, reg + i);
-               if (voff1 < 0)
-                       return voff1;
-
-               voff2 = i2c_smbus_read_byte_data(client, reg + i + 0x08);
-               if (voff2 < 0)
-                       return voff2;
-
-               voff1 &= bits;
-               voff2 &= bits;
-
-               if (v != voff1 || v != voff2)
-                       return -ENODEV;
-       }
-
-       return 0;
-}
-
-static int ltc4245_detect(struct i2c_client *client,
-                         int kind,
-                         struct i2c_board_info *info)
-{
-       struct i2c_adapter *adapter = client->adapter;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
-               return -ENODEV;
-
-       if (kind < 0) {         /* probed detection - check the chip type */
-               s32 v;          /* 8 bits from the chip, or -ERRNO */
-
-               /* Chip registers 0x00-0x07 are control registers
-                * Chip registers 0x10-0x1f are data registers
-                *
-                * Address bits b7-b5 are ignored. This makes the chip "repeat"
-                * in steps of 0x20. Any control registers should appear with
-                * the same values across all duplicated addresses.
-                *
-                * Register 0x02 bit b2 is reserved, expect 0
-                * Register 0x07 bits b7 to b4 are reserved, expect 0
-                *
-                * Registers 0x01, 0x02 are control registers and should not
-                * change on their own.
-                *
-                * Register 0x06 bits b6 and b7 are control bits, and should
-                * not change on their own.
-                *
-                * Register 0x07 bits b3 to b0 are control bits, and should
-                * not change on their own.
-                */
-
-               /* read register 0x02 reserved bit, expect 0 */
-               v = i2c_smbus_read_byte_data(client, LTC4245_CONTROL);
-               if (v < 0 || (v & 0x04) != 0)
-                       return -ENODEV;
-
-               /* read register 0x07 reserved bits, expect 0 */
-               v = i2c_smbus_read_byte_data(client, LTC4245_ADCADR);
-               if (v < 0 || (v & 0xf0) != 0)
-                       return -ENODEV;
-
-               /* check that the alert register appears at all locations */
-               if (ltc4245_check_control_reg(client, LTC4245_ALERT, 0xff))
-                       return -ENODEV;
-
-               /* check that the control register appears at all locations */
-               if (ltc4245_check_control_reg(client, LTC4245_CONTROL, 0xff))
-                       return -ENODEV;
-
-               /* check that register 0x06 bits b6 and b7 stay constant */
-               if (ltc4245_check_control_reg(client, LTC4245_GPIO, 0xc0))
-                       return -ENODEV;
-
-               /* check that register 0x07 bits b3-b0 stay constant */
-               if (ltc4245_check_control_reg(client, LTC4245_ADCADR, 0x0f))
-                       return -ENODEV;
-       }
-
-       strlcpy(info->type, "ltc4245", I2C_NAME_SIZE);
-       dev_info(&adapter->dev, "ltc4245 %s at address 0x%02x\n",
-                       kind < 0 ? "probed" : "forced",
-                       client->addr);
-
-       return 0;
-}
-
 static const struct i2c_device_id ltc4245_id[] = {
-       { "ltc4245", ltc4245 },
+       { "ltc4245", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ltc4245_id);
 
 /* This is the driver that will be inserted */
 static struct i2c_driver ltc4245_driver = {
-       .class          = I2C_CLASS_HWMON,
        .driver = {
                .name   = "ltc4245",
        },
        .probe          = ltc4245_probe,
        .remove         = ltc4245_remove,
        .id_table       = ltc4245_id,
-       .detect         = ltc4245_detect,
-       .address_data   = &addr_data,
 };
 
 static int __init ltc4245_init(void)
index f7d6fe9c49baa3724c38463448acbcb5a4384cb4..8f0b90ef8c76fe9e76e1c2101d841004690963e4 100644 (file)
@@ -364,7 +364,7 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
        error = acpi_check_region(amd756_ioport, SMB_IOSIZE,
                                  amd756_driver.name);
        if (error)
-               return error;
+               return -ENODEV;
 
        if (!request_region(amd756_ioport, SMB_IOSIZE, amd756_driver.name)) {
                dev_err(&pdev->dev, "SMB region 0x%x already in use!\n",
index a7c59908c457cbeb23937904dc6d6a76a05e060c..5b4ad86ca166f2bdcec9e63f8fa02947f2bfd83c 100644 (file)
@@ -376,8 +376,10 @@ static int __devinit amd8111_probe(struct pci_dev *dev,
        smbus->size = pci_resource_len(dev, 0);
 
        error = acpi_check_resource_conflict(&dev->resource[0]);
-       if (error)
+       if (error) {
+               error = -ENODEV;
                goto out_kfree;
+       }
 
        if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) {
                error = -EBUSY;
index 9d2c5adf5d4fbbcf06c8baf68d98cb01c5b93706..55edcfe5b851abe5676d1d3c857eed93c233e458 100644 (file)
@@ -732,8 +732,10 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
        }
 
        err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
-       if (err)
+       if (err) {
+               err = -ENODEV;
                goto exit;
+       }
 
        err = pci_request_region(dev, SMBBAR, i801_driver.name);
        if (err) {
index 9f6b8e0f8632af44c2eb4c49667277e0656bec7b..dba6eb053e2facc6f1393abe41ac5b296b9127aa 100644 (file)
@@ -281,7 +281,7 @@ static int __devinit sch_probe(struct pci_dev *dev,
                return -ENODEV;
        }
        if (acpi_check_region(sch_smba, SMBIOSIZE, sch_driver.name))
-               return -EBUSY;
+               return -ENODEV;
        if (!request_region(sch_smba, SMBIOSIZE, sch_driver.name)) {
                dev_err(&dev->dev, "SMBus region 0x%x already in use!\n",
                        sch_smba);
index a782c7a08f9e1256d40430bf15d050d30791375b..d26a972aacaad8b0eff3f850b46fa5ed418d0440 100644 (file)
@@ -169,7 +169,7 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
        }
 
        if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
-               return -EBUSY;
+               return -ENODEV;
 
        if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
                dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
@@ -260,7 +260,7 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
 
        piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
        if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
-               return -EBUSY;
+               return -ENODEV;
 
        if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
                dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
index 8295885b2fdb9417c18f19becc3a3ce045240d18..1649963b00dcfef12861868dfa5715547f9bfc7a 100644 (file)
@@ -280,7 +280,7 @@ static int __devinit sis96x_probe(struct pci_dev *dev,
 
        retval = acpi_check_resource_conflict(&dev->resource[SIS96x_BAR]);
        if (retval)
-               return retval;
+               return -ENODEV;
 
        /* Everything is happy, let's grab the memory and set things up. */
        if (!request_region(sis96x_smbus_base, SMB_IOSIZE,
index 54d810a4d00f86aa3ff687294e235b47a0a4a7cf..e4b1543015af9cb5eeb44f40a676918c70fb83e8 100644 (file)
@@ -365,7 +365,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev,
 found:
        error = acpi_check_region(vt596_smba, 8, vt596_driver.name);
        if (error)
-               return error;
+               return -ENODEV;
 
        if (!request_region(vt596_smba, 8, vt596_driver.name)) {
                dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n",
index 51bd9669cb1f7697c0be4e1b4b0c38dc4ee05499..f504c9b00c1ba631cbe7f27b80ad0859ab9f3a08 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/poll.h>
+#include <linux/sched.h>
 #include <linux/file.h>
 #include <linux/mount.h>
 #include <linux/cdev.h>
index 8c46f2257098cf2d7e01ba472c31a48dc5ffb77a..7de02969ed7d80bcf28b59abe9471253d9a9138f 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/mutex.h>
 #include <linux/kref.h>
 #include <linux/compat.h>
+#include <linux/sched.h>
 #include <linux/semaphore.h>
 
 #include <asm/uaccess.h>
index d3fff9e008a3e01f1f81795101738ae236b02dcb..aec0fbdfe7f016bba4126bbf89d64060783501b9 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/err.h>
 #include <linux/fs.h>
 #include <linux/poll.h>
+#include <linux/sched.h>
 #include <linux/file.h>
 #include <linux/mount.h>
 #include <linux/cdev.h>
index 1148140d08a1faf72967dc3068e41c71488054d8..dee6706038aad7ad1519f551bd4d71f02fa6f9c1 100644 (file)
@@ -13,6 +13,7 @@
 #define EVDEV_BUFFER_SIZE      64
 
 #include <linux/poll.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
index 16ec33f27c5dad87d28751a54f1e6b4fc10677f7..c6f88ebb40c766e21c17104cdbbe12563ed075a7 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/random.h>
 #include <linux/major.h>
 #include <linux/proc_fs.h>
+#include <linux/sched.h>
 #include <linux/seq_file.h>
 #include <linux/poll.h>
 #include <linux/device.h>
index 901b2525993e54f77c219cac9b1d55e3431219e5..b1bd6dd322864d0bd04c2f9a48c9f80b3217dcce 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/input.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
index c5a49aba418f9232ff026dbce0a9d30db706bf1b..d3f57245420a008a412afa9b55dd4bd8f015ce8d 100644 (file)
@@ -30,6 +30,7 @@
  *             - first public version
  */
 #include <linux/poll.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
index 966b8868f7924f6f73c276411cded8f29b155714..a13d80f7da17481772cc4e00f260b2f564919e13 100644 (file)
@@ -13,6 +13,7 @@
 #define MOUSEDEV_MINORS                32
 #define MOUSEDEV_MIX           31
 
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/poll.h>
index 8b256a617c8a4524cec9f503ef7371ebbf30356b..3697c409bec66d5b9c2dbe0b31577f22fef2ef1c 100644 (file)
@@ -16,6 +16,7 @@
 #else
 #include <linux/fs.h>
 #endif
+#include <linux/sched.h>
 #include <linux/isdnif.h>
 #include <net/net_namespace.h>
 #include "isdn_divert.h"
index 708a8017c21d49e207139c9773927fd87c848f7a..adc561eb59d2ed022873bacf35501b9462e19bbc 100644 (file)
@@ -19,9 +19,6 @@
 #include <linux/workqueue.h>
 #include <linux/leds-pca9532.h>
 
-static const unsigned short normal_i2c[] = { /*0x60,*/ I2C_CLIENT_END};
-I2C_CLIENT_INSMOD_1(pca9532);
-
 #define PCA9532_REG_PSC(i) (0x2+(i)*2)
 #define PCA9532_REG_PWM(i) (0x3+(i)*2)
 #define PCA9532_REG_LS0  0x6
index fde377c60cca753eafe9c358f7e562c6d538ad7b..556f0feaa4df33fe3733e0ccf3638bb6bfe1aa44 100644 (file)
@@ -124,6 +124,8 @@ read_reg(struct thermostat* th, int reg)
        return data;
 }
 
+static struct i2c_driver thermostat_driver;
+
 static int
 attach_thermostat(struct i2c_adapter *adapter)
 {
@@ -148,7 +150,7 @@ attach_thermostat(struct i2c_adapter *adapter)
         * Let i2c-core delete that device on driver removal.
         * This is safe because i2c-core holds the core_lock mutex for us.
         */
-       list_add_tail(&client->detected, &client->driver->clients);
+       list_add_tail(&client->detected, &thermostat_driver.clients);
        return 0;
 }
 
index a028598af2d32ae030596bff2e83145420271d65..ea32c7e5a9af116c49e885b1e015fe9742f24758 100644 (file)
@@ -286,6 +286,8 @@ struct fcu_fan_table        fcu_fans[] = {
        },
 };
 
+static struct i2c_driver therm_pm72_driver;
+
 /*
  * Utility function to create an i2c_client structure and
  * attach it to one of u3 adapters
@@ -318,7 +320,7 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name)
         * Let i2c-core delete that device on driver removal.
         * This is safe because i2c-core holds the core_lock mutex for us.
         */
-       list_add_tail(&clt->detected, &clt->driver->clients);
+       list_add_tail(&clt->detected, &therm_pm72_driver.clients);
        return clt;
 }
 
index 529886c7a8263ae4d4d01df89b7b513695d983c3..ed6426a107738b4dff5a1d639140a7f22b7c9b27 100644 (file)
@@ -115,6 +115,8 @@ static int wf_lm75_probe(struct i2c_client *client,
        return rc;
 }
 
+static struct i2c_driver wf_lm75_driver;
+
 static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
                                             u8 addr, int ds1775,
                                             const char *loc)
@@ -157,7 +159,7 @@ static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
         * Let i2c-core delete that device on driver removal.
         * This is safe because i2c-core holds the core_lock mutex for us.
         */
-       list_add_tail(&client->detected, &client->driver->clients);
+       list_add_tail(&client->detected, &wf_lm75_driver.clients);
        return client;
  fail:
        return NULL;
index e2a55ecda2b28aa2c80114dd7d6c7ec0cd519827..a67b349319e9c9be57f19faf3f309ff487e06448 100644 (file)
@@ -88,6 +88,8 @@ static int wf_max6690_probe(struct i2c_client *client,
        return rc;
 }
 
+static struct i2c_driver wf_max6690_driver;
+
 static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter,
                                            u8 addr, const char *loc)
 {
@@ -119,7 +121,7 @@ static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter,
         * Let i2c-core delete that device on driver removal.
         * This is safe because i2c-core holds the core_lock mutex for us.
         */
-       list_add_tail(&client->detected, &client->driver->clients);
+       list_add_tail(&client->detected, &wf_max6690_driver.clients);
        return client;
 
  fail:
index 5da729e58f99294ec43cd23ec7bee680da7e70b7..e20330a28959bc539d0691337bf49438e2022efe 100644 (file)
@@ -194,6 +194,8 @@ static struct wf_sensor_ops wf_sat_ops = {
        .owner          = THIS_MODULE,
 };
 
+static struct i2c_driver wf_sat_driver;
+
 static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
 {
        struct i2c_board_info info;
@@ -222,7 +224,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
         * Let i2c-core delete that device on driver removal.
         * This is safe because i2c-core holds the core_lock mutex for us.
         */
-       list_add_tail(&client->detected, &client->driver->clients);
+       list_add_tail(&client->detected, &wf_sat_driver.clients);
 }
 
 static int wf_sat_probe(struct i2c_client *client,
index 376f1ab48a245fcdce521bd55a7ceb109f7f8c9e..23e76fe0d35958d604657a559a5954095854bf23 100644 (file)
@@ -130,7 +130,7 @@ struct mapped_device {
        /*
         * A list of ios that arrived while we were suspended.
         */
-       atomic_t pending[2];
+       atomic_t pending;
        wait_queue_head_t wait;
        struct work_struct work;
        struct bio_list deferred;
@@ -453,14 +453,13 @@ static void start_io_acct(struct dm_io *io)
 {
        struct mapped_device *md = io->md;
        int cpu;
-       int rw = bio_data_dir(io->bio);
 
        io->start_time = jiffies;
 
        cpu = part_stat_lock();
        part_round_stats(cpu, &dm_disk(md)->part0);
        part_stat_unlock();
-       dm_disk(md)->part0.in_flight[rw] = atomic_inc_return(&md->pending[rw]);
+       dm_disk(md)->part0.in_flight = atomic_inc_return(&md->pending);
 }
 
 static void end_io_acct(struct dm_io *io)
@@ -480,9 +479,8 @@ static void end_io_acct(struct dm_io *io)
         * After this is decremented the bio must not be touched if it is
         * a barrier.
         */
-       dm_disk(md)->part0.in_flight[rw] = pending =
-               atomic_dec_return(&md->pending[rw]);
-       pending += atomic_read(&md->pending[rw^0x1]);
+       dm_disk(md)->part0.in_flight = pending =
+               atomic_dec_return(&md->pending);
 
        /* nudge anyone waiting on suspend queue */
        if (!pending)
@@ -1787,8 +1785,7 @@ static struct mapped_device *alloc_dev(int minor)
        if (!md->disk)
                goto bad_disk;
 
-       atomic_set(&md->pending[0], 0);
-       atomic_set(&md->pending[1], 0);
+       atomic_set(&md->pending, 0);
        init_waitqueue_head(&md->wait);
        INIT_WORK(&md->work, dm_wq_work);
        init_waitqueue_head(&md->eventq);
@@ -2091,8 +2088,7 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible)
                                break;
                        }
                        spin_unlock_irqrestore(q->queue_lock, flags);
-               } else if (!atomic_read(&md->pending[0]) &&
-                                       !atomic_read(&md->pending[1]))
+               } else if (!atomic_read(&md->pending))
                        break;
 
                if (interruptible == TASK_INTERRUPTIBLE &&
index 51641498359360adae77c79698112ad52711fce6..c37790ad92d0b501e470d4c0a6de0a1713fc592a 100644 (file)
@@ -20,6 +20,7 @@
  *
  */
 
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
index eef6d36166268f77883b2fb454eb6dcd698ca1fa..91c537bca8adaac314f85c7ffc531c05f5d00620 100644 (file)
@@ -21,6 +21,7 @@
  *
  */
 
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
index 8b1440136c45b10710079bdbf2e80fba7f166978..482d0f3be5ffe7a26ed931a1c7f44042a384da9c 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/videodev2.h>   /* V4L2 API defs                */
 #include <linux/param.h>
 #include <linux/pnp.h>
+#include <linux/sched.h>
 #include <linux/io.h>          /* outb, outb_p                 */
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
index 43ab0adf3b610a8927299e833c6bb3ab5f3b73ad..2377313c041a8c33976db18f0c1ef7a698c94bd6 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 #include <linux/ctype.h>
index 5447da16a1705c49e9e72c57a58e203ceb4ce1eb..613481028272f114c754a4a652987fce90452cae 100644 (file)
@@ -57,8 +57,6 @@
  * The AB3100 is usually assigned address 0x48 (7-bit)
  * The chip is defined in the platform i2c_board_data section.
  */
-static unsigned short normal_i2c[] = { 0x48, I2C_CLIENT_END };
-I2C_CLIENT_INSMOD_1(ab3100);
 
 u8 ab3100_get_chip_type(struct ab3100 *ab3100)
 {
@@ -966,7 +964,7 @@ static int __exit ab3100_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id ab3100_id[] = {
-       { "ab3100", ab3100 },
+       { "ab3100", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ab3100_id);
index 2afc08006e6d1db891f995445a351c59186165fd..fa294b6d600a9d6af6f8f27d8b853b5aea7d55e3 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/ucb1400.h>
 
 unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel,
index 3c0c58eed34778a22b6d052dbb665584e8b55147..5a6b2bce8ad5a7a3672c8333a91a8285202b9af2 100644 (file)
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 
-/* Do not scan - the MAX6875 access method will write to some EEPROM chips */
-static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/* Insmod parameters */
-I2C_CLIENT_INSMOD_1(max6875);
-
 /* The MAX6875 can only read/write 16 bytes at a time */
 #define SLICE_SIZE                     16
 #define SLICE_BITS                     4
@@ -146,31 +140,21 @@ static struct bin_attribute user_eeprom_attr = {
        .read = max6875_read,
 };
 
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int max6875_detect(struct i2c_client *client, int kind,
-                         struct i2c_board_info *info)
+static int max6875_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct i2c_adapter *adapter = client->adapter;
+       struct max6875_data *data;
+       int err;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
                                     | I2C_FUNC_SMBUS_READ_BYTE))
                return -ENODEV;
 
-       /* Only check even addresses */
+       /* Only bind to even addresses */
        if (client->addr & 1)
                return -ENODEV;
 
-       strlcpy(info->type, "max6875", I2C_NAME_SIZE);
-
-       return 0;
-}
-
-static int max6875_probe(struct i2c_client *client,
-                        const struct i2c_device_id *id)
-{
-       struct max6875_data *data;
-       int err;
-
        if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL)))
                return -ENOMEM;
 
@@ -222,9 +206,6 @@ static struct i2c_driver max6875_driver = {
        .probe          = max6875_probe,
        .remove         = max6875_remove,
        .id_table       = max6875_id,
-
-       .detect         = max6875_detect,
-       .address_data   = &addr_data,
 };
 
 static int __init max6875_init(void)
index 0acbf4f5be50d31e31ccbce8d5e51db854e57f22..8ca17a3e96eaa0e85251ecf861d23673b9df3927 100644 (file)
@@ -32,14 +32,6 @@ struct mtd_blkcore_priv {
        spinlock_t queue_lock;
 };
 
-static int blktrans_discard_request(struct request_queue *q,
-                                   struct request *req)
-{
-       req->cmd_type = REQ_TYPE_LINUX_BLOCK;
-       req->cmd[0] = REQ_LB_OP_DISCARD;
-       return 0;
-}
-
 static int do_blktrans_request(struct mtd_blktrans_ops *tr,
                               struct mtd_blktrans_dev *dev,
                               struct request *req)
@@ -52,10 +44,6 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
 
        buf = req->buffer;
 
-       if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
-           req->cmd[0] == REQ_LB_OP_DISCARD)
-               return tr->discard(dev, block, nsect);
-
        if (!blk_fs_request(req))
                return -EIO;
 
@@ -63,6 +51,9 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
            get_capacity(req->rq_disk))
                return -EIO;
 
+       if (blk_discard_rq(req))
+               return tr->discard(dev, block, nsect);
+
        switch(rq_data_dir(req)) {
        case READ:
                for (; nsect > 0; nsect--, block++, buf += tr->blksize)
@@ -380,8 +371,8 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
        tr->blkcore_priv->rq->queuedata = tr;
        blk_queue_logical_block_size(tr->blkcore_priv->rq, tr->blksize);
        if (tr->discard)
-               blk_queue_set_discard(tr->blkcore_priv->rq,
-                                     blktrans_discard_request);
+               queue_flag_set_unlocked(QUEUE_FLAG_DISCARD,
+                                       tr->blkcore_priv->rq);
 
        tr->blkshift = ffs(tr->blksize) - 1;
 
index afdbdaaf80cb354de22e024f1c99677d81bc0665..a2a742c8ff7e30dab430ef7ece4abc1c2a930dd3 100644 (file)
@@ -1211,15 +1211,6 @@ static int sony_nc_add(struct acpi_device *device)
                }
        }
 
-       /* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1
-        * should be respected as we already checked for the device presence above */
-       if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) {
-               dprintk("Invoking _INI\n");
-               if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI,
-                                               NULL, NULL)))
-                       dprintk("_INI Method failed\n");
-       }
-
        if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
                                         &handle))) {
                if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL))
@@ -1399,27 +1390,20 @@ struct sonypi_eventtypes {
        struct sonypi_event     *events;
 };
 
-struct device_ctrl {
+struct sony_pic_dev {
+       struct acpi_device              *acpi_dev;
+       struct sony_pic_irq             *cur_irq;
+       struct sony_pic_ioport          *cur_ioport;
+       struct list_head                interrupts;
+       struct list_head                ioports;
+       struct mutex                    lock;
+       struct sonypi_eventtypes        *event_types;
+       int                             (*handle_irq)(const u8, const u8);
        int                             model;
-       int                             (*handle_irq)(const u8, const u8);
        u16                             evport_offset;
-       u8                              has_camera;
-       u8                              has_bluetooth;
-       u8                              has_wwan;
-       struct sonypi_eventtypes        *event_types;
-};
-
-struct sony_pic_dev {
-       struct device_ctrl      *control;
-       struct acpi_device      *acpi_dev;
-       struct sony_pic_irq     *cur_irq;
-       struct sony_pic_ioport  *cur_ioport;
-       struct list_head        interrupts;
-       struct list_head        ioports;
-       struct mutex            lock;
-       u8                      camera_power;
-       u8                      bluetooth_power;
-       u8                      wwan_power;
+       u8                              camera_power;
+       u8                              bluetooth_power;
+       u8                              wwan_power;
 };
 
 static struct sony_pic_dev spic_dev = {
@@ -1427,6 +1411,8 @@ static struct sony_pic_dev spic_dev = {
        .ioports        = LIST_HEAD_INIT(spic_dev.ioports),
 };
 
+static int spic_drv_registered;
+
 /* Event masks */
 #define SONYPI_JOGGER_MASK                     0x00000001
 #define SONYPI_CAPTURE_MASK                    0x00000002
@@ -1724,27 +1710,6 @@ static int type3_handle_irq(const u8 data_mask, const u8 ev)
        return 1;
 }
 
-static struct device_ctrl spic_types[] = {
-       {
-               .model = SONYPI_DEVICE_TYPE1,
-               .handle_irq = NULL,
-               .evport_offset = SONYPI_TYPE1_OFFSET,
-               .event_types = type1_events,
-       },
-       {
-               .model = SONYPI_DEVICE_TYPE2,
-               .handle_irq = NULL,
-               .evport_offset = SONYPI_TYPE2_OFFSET,
-               .event_types = type2_events,
-       },
-       {
-               .model = SONYPI_DEVICE_TYPE3,
-               .handle_irq = type3_handle_irq,
-               .evport_offset = SONYPI_TYPE3_OFFSET,
-               .event_types = type3_events,
-       },
-};
-
 static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
 {
        struct pci_dev *pcidev;
@@ -1752,48 +1717,63 @@ static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
        pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
                        PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
        if (pcidev) {
-               dev->control = &spic_types[0];
+               dev->model = SONYPI_DEVICE_TYPE1;
+               dev->evport_offset = SONYPI_TYPE1_OFFSET;
+               dev->event_types = type1_events;
                goto out;
        }
 
        pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
                        PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
        if (pcidev) {
-               dev->control = &spic_types[2];
+               dev->model = SONYPI_DEVICE_TYPE2;
+               dev->evport_offset = SONYPI_TYPE2_OFFSET;
+               dev->event_types = type2_events;
                goto out;
        }
 
        pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
                        PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
        if (pcidev) {
-               dev->control = &spic_types[2];
+               dev->model = SONYPI_DEVICE_TYPE3;
+               dev->handle_irq = type3_handle_irq;
+               dev->evport_offset = SONYPI_TYPE3_OFFSET;
+               dev->event_types = type3_events;
                goto out;
        }
 
        pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
                        PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
        if (pcidev) {
-               dev->control = &spic_types[2];
+               dev->model = SONYPI_DEVICE_TYPE3;
+               dev->handle_irq = type3_handle_irq;
+               dev->evport_offset = SONYPI_TYPE3_OFFSET;
+               dev->event_types = type3_events;
                goto out;
        }
 
        pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
                        PCI_DEVICE_ID_INTEL_ICH9_1, NULL);
        if (pcidev) {
-               dev->control = &spic_types[2];
+               dev->model = SONYPI_DEVICE_TYPE3;
+               dev->handle_irq = type3_handle_irq;
+               dev->evport_offset = SONYPI_TYPE3_OFFSET;
+               dev->event_types = type3_events;
                goto out;
        }
 
        /* default */
-       dev->control = &spic_types[1];
+       dev->model = SONYPI_DEVICE_TYPE2;
+       dev->evport_offset = SONYPI_TYPE2_OFFSET;
+       dev->event_types = type2_events;
 
 out:
        if (pcidev)
                pci_dev_put(pcidev);
 
        printk(KERN_INFO DRV_PFX "detected Type%d model\n",
-                       dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 :
-                       dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
+                       dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
+                       dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
 }
 
 /* camera tests and poweron/poweroff */
@@ -2566,7 +2546,7 @@ static int sony_pic_enable(struct acpi_device *device,
        buffer.pointer = resource;
 
        /* setup Type 1 resources */
-       if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) {
+       if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
 
                /* setup io resources */
                resource->res1.type = ACPI_RESOURCE_TYPE_IO;
@@ -2649,29 +2629,28 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
                data_mask = inb_p(dev->cur_ioport->io2.minimum);
        else
                data_mask = inb_p(dev->cur_ioport->io1.minimum +
-                               dev->control->evport_offset);
+                               dev->evport_offset);
 
        dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
                        ev, data_mask, dev->cur_ioport->io1.minimum,
-                       dev->control->evport_offset);
+                       dev->evport_offset);
 
        if (ev == 0x00 || ev == 0xff)
                return IRQ_HANDLED;
 
-       for (i = 0; dev->control->event_types[i].mask; i++) {
+       for (i = 0; dev->event_types[i].mask; i++) {
 
-               if ((data_mask & dev->control->event_types[i].data) !=
-                   dev->control->event_types[i].data)
+               if ((data_mask & dev->event_types[i].data) !=
+                   dev->event_types[i].data)
                        continue;
 
-               if (!(mask & dev->control->event_types[i].mask))
+               if (!(mask & dev->event_types[i].mask))
                        continue;
 
-               for (j = 0; dev->control->event_types[i].events[j].event; j++) {
-                       if (ev == dev->control->event_types[i].events[j].data) {
+               for (j = 0; dev->event_types[i].events[j].event; j++) {
+                       if (ev == dev->event_types[i].events[j].data) {
                                device_event =
-                                       dev->control->
-                                               event_types[i].events[j].event;
+                                       dev->event_types[i].events[j].event;
                                goto found;
                        }
                }
@@ -2679,13 +2658,12 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
        /* Still not able to decode the event try to pass
         * it over to the minidriver
         */
-       if (dev->control->handle_irq &&
-                       dev->control->handle_irq(data_mask, ev) == 0)
+       if (dev->handle_irq && dev->handle_irq(data_mask, ev) == 0)
                return IRQ_HANDLED;
 
        dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
                        ev, data_mask, dev->cur_ioport->io1.minimum,
-                       dev->control->evport_offset);
+                       dev->evport_offset);
        return IRQ_HANDLED;
 
 found:
@@ -2816,7 +2794,7 @@ static int sony_pic_add(struct acpi_device *device)
        /* request IRQ */
        list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
                if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
-                                       IRQF_SHARED, "sony-laptop", &spic_dev)) {
+                                       IRQF_DISABLED, "sony-laptop", &spic_dev)) {
                        dprintk("IRQ: %d - triggering: %d - "
                                        "polarity: %d - shr: %d\n",
                                        irq->irq.interrupts[0],
@@ -2949,6 +2927,7 @@ static int __init sony_laptop_init(void)
                                        "Unable to register SPIC driver.");
                        goto out;
                }
+               spic_drv_registered = 1;
        }
 
        result = acpi_bus_register_driver(&sony_nc_driver);
@@ -2960,7 +2939,7 @@ static int __init sony_laptop_init(void)
        return 0;
 
 out_unregister_pic:
-       if (!no_spic)
+       if (spic_drv_registered)
                acpi_bus_unregister_driver(&sony_pic_driver);
 out:
        return result;
@@ -2969,7 +2948,7 @@ out:
 static void __exit sony_laptop_exit(void)
 {
        acpi_bus_unregister_driver(&sony_nc_driver);
-       if (!no_spic)
+       if (spic_drv_registered)
                acpi_bus_unregister_driver(&sony_pic_driver);
 }
 
index d3b496800477b065b42b1b92a0a0b201e5503b78..b204a09291393406acd9450ba641d754fd0707ed 100644 (file)
@@ -90,7 +90,11 @@ static struct sfi_table_simple *syst_va __read_mostly;
  */
 static u32 sfi_use_ioremap __read_mostly;
 
-static void __iomem *sfi_map_memory(u64 phys, u32 size)
+/*
+ * sfi_un/map_memory calls early_ioremap/iounmap which is a __init function
+ * and introduces section mismatch. So use __ref to make it calm.
+ */
+static void __iomem * __ref sfi_map_memory(u64 phys, u32 size)
 {
        if (!phys || !size)
                return NULL;
@@ -101,7 +105,7 @@ static void __iomem *sfi_map_memory(u64 phys, u32 size)
                return early_ioremap(phys, size);
 }
 
-static void sfi_unmap_memory(void __iomem *virt, u32 size)
+static void __ref sfi_unmap_memory(void __iomem *virt, u32 size)
 {
        if (!virt || !size)
                return;
@@ -125,7 +129,7 @@ static void sfi_print_table_header(unsigned long long pa,
  * sfi_verify_table()
  * Sanity check table lengh, calculate checksum
  */
-static __init int sfi_verify_table(struct sfi_table_header *table)
+static int sfi_verify_table(struct sfi_table_header *table)
 {
 
        u8 checksum = 0;
@@ -213,12 +217,17 @@ static int sfi_table_check_key(struct sfi_table_header *th,
  *    the mapped virt address will be returned, and the virt space
  *    will be released by call sfi_put_table() later
  *
+ * This two cases are from two different functions with two different
+ * sections and causes section mismatch warning. So use __ref to tell
+ * modpost not to make any noise.
+ *
  * Return value:
  *     NULL:                   when can't find a table matching the key
  *     ERR_PTR(error):         error value
  *     virt table address:     when a matched table is found
  */
-struct sfi_table_header *sfi_check_table(u64 pa, struct sfi_table_key *key)
+struct sfi_table_header *
+ __ref sfi_check_table(u64 pa, struct sfi_table_key *key)
 {
        struct sfi_table_header *th;
        void *ret = NULL;
index ee1601026fb02dd79aa97a11132300f1af022d54..c24e4e0367a276ce787140154156b25ac73707bb 100644 (file)
@@ -102,7 +102,7 @@ static int dst_request(struct request_queue *q, struct bio *bio)
        struct dst_node *n = q->queuedata;
        int err = -EIO;
 
-       if (bio_empty_barrier(bio) && !q->prepare_discard_fn) {
+       if (bio_empty_barrier(bio) && !blk_queue_discard(q)) {
                /*
                 * This is a dirty^Wnice hack, but if we complete this
                 * operation with -EOPNOTSUPP like intended, XFS
index ea8a5efc19bca41120bd4e5e4d2789b9afb11c36..fc2107f4c049b4b88905bbe06ee06aa7f1c45f45 100644 (file)
@@ -239,10 +239,6 @@ static int __devexit tsl2561_remove(struct i2c_client *client)
        return tsl2561_powerdown(client);
 }
 
-static unsigned short normal_i2c[] = { 0x29, 0x39, 0x49, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
 static const struct i2c_device_id tsl2561_id[] = {
        { "tsl2561", 0 },
        { }
index c44367fea185822919231f87e16fcf9a6d994461..bf0f6520c6df3946b91f2a40f9b1a6c786918f6d 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/wait.h>
 #include <linux/compiler.h>
 #include <asm/uaccess.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
index df52cb355f7dd10b093bff43796c283c62c9bb26..406caa6a71cbb1bc40d54e44f957079a1b4f1b06 100644 (file)
 #include "../w1.h"
 #include "../w1_int.h"
 
-/**
- * Address is selected using 2 pins, resulting in 4 possible addresses.
- *  0x18, 0x19, 0x1a, 0x1b
- * However, the chip cannot be detected without doing an i2c write,
- * so use the force module parameter.
- */
-static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/**
- * Insmod parameters
- */
-I2C_CLIENT_INSMOD_1(ds2482);
-
 /**
  * The DS2482 registers - there are 3 registers that are addressed by a read
  * pointer. The read pointer is set by the last command executed.
@@ -96,8 +83,6 @@ static const u8 ds2482_chan_rd[8] =
 
 static int ds2482_probe(struct i2c_client *client,
                        const struct i2c_device_id *id);
-static int ds2482_detect(struct i2c_client *client, int kind,
-                        struct i2c_board_info *info);
 static int ds2482_remove(struct i2c_client *client);
 
 
@@ -117,8 +102,6 @@ static struct i2c_driver ds2482_driver = {
        .probe          = ds2482_probe,
        .remove         = ds2482_remove,
        .id_table       = ds2482_id,
-       .detect         = ds2482_detect,
-       .address_data   = &addr_data,
 };
 
 /*
@@ -425,19 +408,6 @@ static u8 ds2482_w1_reset_bus(void *data)
 }
 
 
-static int ds2482_detect(struct i2c_client *client, int kind,
-                        struct i2c_board_info *info)
-{
-       if (!i2c_check_functionality(client->adapter,
-                                    I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
-                                    I2C_FUNC_SMBUS_BYTE))
-               return -ENODEV;
-
-       strlcpy(info->type, "ds2482", I2C_NAME_SIZE);
-
-       return 0;
-}
-
 static int ds2482_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -446,6 +416,11 @@ static int ds2482_probe(struct i2c_client *client,
        int temp1;
        int idx;
 
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+                                    I2C_FUNC_SMBUS_BYTE))
+               return -ENODEV;
+
        if (!(data = kzalloc(sizeof(struct ds2482_data), GFP_KERNEL))) {
                err = -ENOMEM;
                goto exit;
index a9592d981b107de1ca1447d1972cd4e12a3252b4..6c4269b836b7f22ddadc2ca39d5531e467cffc95 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/mutex.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/mount.h>
 #include <linux/pagemap.h>
index d11c51fc2a3fd144ac8de14702207078743cd353..2ca7a7cafdbf9359ccf1a706a5fdda11f3fe157e 100644 (file)
@@ -8,8 +8,10 @@
  *
  */
 
+#include <linux/cred.h>
 #include <linux/file.h>
 #include <linux/poll.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/fs.h>
index 76738005c8e8af43c3b084a48d4f752e36e2186d..402cb84a92a1dbd538dc4eead68cd474bea3389b 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -249,6 +249,7 @@ void bio_free(struct bio *bio, struct bio_set *bs)
 
        mempool_free(p, bs->bio_pool);
 }
+EXPORT_SYMBOL(bio_free);
 
 void bio_init(struct bio *bio)
 {
@@ -257,6 +258,7 @@ void bio_init(struct bio *bio)
        bio->bi_comp_cpu = -1;
        atomic_set(&bio->bi_cnt, 1);
 }
+EXPORT_SYMBOL(bio_init);
 
 /**
  * bio_alloc_bioset - allocate a bio for I/O
@@ -311,6 +313,7 @@ err_free:
        mempool_free(p, bs->bio_pool);
        return NULL;
 }
+EXPORT_SYMBOL(bio_alloc_bioset);
 
 static void bio_fs_destructor(struct bio *bio)
 {
@@ -337,6 +340,7 @@ struct bio *bio_alloc(gfp_t gfp_mask, int nr_iovecs)
 
        return bio;
 }
+EXPORT_SYMBOL(bio_alloc);
 
 static void bio_kmalloc_destructor(struct bio *bio)
 {
@@ -380,6 +384,7 @@ struct bio *bio_kmalloc(gfp_t gfp_mask, int nr_iovecs)
 
        return bio;
 }
+EXPORT_SYMBOL(bio_kmalloc);
 
 void zero_fill_bio(struct bio *bio)
 {
@@ -416,6 +421,7 @@ void bio_put(struct bio *bio)
                bio->bi_destructor(bio);
        }
 }
+EXPORT_SYMBOL(bio_put);
 
 inline int bio_phys_segments(struct request_queue *q, struct bio *bio)
 {
@@ -424,6 +430,7 @@ inline int bio_phys_segments(struct request_queue *q, struct bio *bio)
 
        return bio->bi_phys_segments;
 }
+EXPORT_SYMBOL(bio_phys_segments);
 
 /**
  *     __bio_clone     -       clone a bio
@@ -451,6 +458,7 @@ void __bio_clone(struct bio *bio, struct bio *bio_src)
        bio->bi_size = bio_src->bi_size;
        bio->bi_idx = bio_src->bi_idx;
 }
+EXPORT_SYMBOL(__bio_clone);
 
 /**
  *     bio_clone       -       clone a bio
@@ -482,6 +490,7 @@ struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask)
 
        return b;
 }
+EXPORT_SYMBOL(bio_clone);
 
 /**
  *     bio_get_nr_vecs         - return approx number of vecs
@@ -505,6 +514,7 @@ int bio_get_nr_vecs(struct block_device *bdev)
 
        return nr_pages;
 }
+EXPORT_SYMBOL(bio_get_nr_vecs);
 
 static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
                          *page, unsigned int len, unsigned int offset,
@@ -635,6 +645,7 @@ int bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page *page,
        return __bio_add_page(q, bio, page, len, offset,
                              queue_max_hw_sectors(q));
 }
+EXPORT_SYMBOL(bio_add_pc_page);
 
 /**
  *     bio_add_page    -       attempt to add page to bio
@@ -655,6 +666,7 @@ int bio_add_page(struct bio *bio, struct page *page, unsigned int len,
        struct request_queue *q = bdev_get_queue(bio->bi_bdev);
        return __bio_add_page(q, bio, page, len, offset, queue_max_sectors(q));
 }
+EXPORT_SYMBOL(bio_add_page);
 
 struct bio_map_data {
        struct bio_vec *iovecs;
@@ -776,6 +788,7 @@ int bio_uncopy_user(struct bio *bio)
        bio_put(bio);
        return ret;
 }
+EXPORT_SYMBOL(bio_uncopy_user);
 
 /**
  *     bio_copy_user_iov       -       copy user data to bio
@@ -920,6 +933,7 @@ struct bio *bio_copy_user(struct request_queue *q, struct rq_map_data *map_data,
 
        return bio_copy_user_iov(q, map_data, &iov, 1, write_to_vm, gfp_mask);
 }
+EXPORT_SYMBOL(bio_copy_user);
 
 static struct bio *__bio_map_user_iov(struct request_queue *q,
                                      struct block_device *bdev,
@@ -1050,6 +1064,7 @@ struct bio *bio_map_user(struct request_queue *q, struct block_device *bdev,
 
        return bio_map_user_iov(q, bdev, &iov, 1, write_to_vm, gfp_mask);
 }
+EXPORT_SYMBOL(bio_map_user);
 
 /**
  *     bio_map_user_iov - map user sg_iovec table into bio
@@ -1117,13 +1132,13 @@ void bio_unmap_user(struct bio *bio)
        __bio_unmap_user(bio);
        bio_put(bio);
 }
+EXPORT_SYMBOL(bio_unmap_user);
 
 static void bio_map_kern_endio(struct bio *bio, int err)
 {
        bio_put(bio);
 }
 
-
 static struct bio *__bio_map_kern(struct request_queue *q, void *data,
                                  unsigned int len, gfp_t gfp_mask)
 {
@@ -1189,6 +1204,7 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len,
        bio_put(bio);
        return ERR_PTR(-EINVAL);
 }
+EXPORT_SYMBOL(bio_map_kern);
 
 static void bio_copy_kern_endio(struct bio *bio, int err)
 {
@@ -1250,6 +1266,7 @@ struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len,
 
        return bio;
 }
+EXPORT_SYMBOL(bio_copy_kern);
 
 /*
  * bio_set_pages_dirty() and bio_check_pages_dirty() are support functions
@@ -1400,6 +1417,7 @@ void bio_endio(struct bio *bio, int error)
        if (bio->bi_end_io)
                bio->bi_end_io(bio, error);
 }
+EXPORT_SYMBOL(bio_endio);
 
 void bio_pair_release(struct bio_pair *bp)
 {
@@ -1410,6 +1428,7 @@ void bio_pair_release(struct bio_pair *bp)
                mempool_free(bp, bp->bio2.bi_private);
        }
 }
+EXPORT_SYMBOL(bio_pair_release);
 
 static void bio_pair_end_1(struct bio *bi, int err)
 {
@@ -1477,6 +1496,7 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors)
 
        return bp;
 }
+EXPORT_SYMBOL(bio_split);
 
 /**
  *      bio_sector_offset - Find hardware sector offset in bio
@@ -1547,6 +1567,7 @@ void bioset_free(struct bio_set *bs)
 
        kfree(bs);
 }
+EXPORT_SYMBOL(bioset_free);
 
 /**
  * bioset_create  - Create a bio_set
@@ -1592,6 +1613,7 @@ bad:
        bioset_free(bs);
        return NULL;
 }
+EXPORT_SYMBOL(bioset_create);
 
 static void __init biovec_init_slabs(void)
 {
@@ -1636,29 +1658,4 @@ static int __init init_bio(void)
 
        return 0;
 }
-
 subsys_initcall(init_bio);
-
-EXPORT_SYMBOL(bio_alloc);
-EXPORT_SYMBOL(bio_kmalloc);
-EXPORT_SYMBOL(bio_put);
-EXPORT_SYMBOL(bio_free);
-EXPORT_SYMBOL(bio_endio);
-EXPORT_SYMBOL(bio_init);
-EXPORT_SYMBOL(__bio_clone);
-EXPORT_SYMBOL(bio_clone);
-EXPORT_SYMBOL(bio_phys_segments);
-EXPORT_SYMBOL(bio_add_page);
-EXPORT_SYMBOL(bio_add_pc_page);
-EXPORT_SYMBOL(bio_get_nr_vecs);
-EXPORT_SYMBOL(bio_map_user);
-EXPORT_SYMBOL(bio_unmap_user);
-EXPORT_SYMBOL(bio_map_kern);
-EXPORT_SYMBOL(bio_copy_kern);
-EXPORT_SYMBOL(bio_pair_release);
-EXPORT_SYMBOL(bio_split);
-EXPORT_SYMBOL(bio_copy_user);
-EXPORT_SYMBOL(bio_uncopy_user);
-EXPORT_SYMBOL(bioset_create);
-EXPORT_SYMBOL(bioset_free);
-EXPORT_SYMBOL(bio_alloc_bioset);
index 0376ac66c44a6127199c5389f33f138f73c53fba..be4392ca20983345ae180a450fd0497442b135a8 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
index 7b685e10cbad8cc9b052cec48737fbf7bf6f7afb..f38fee0311a7a82b3ee19ece135c3e17b38e1cdd 100644 (file)
@@ -248,19 +248,11 @@ ssize_t part_stat_show(struct device *dev,
                part_stat_read(p, merges[WRITE]),
                (unsigned long long)part_stat_read(p, sectors[WRITE]),
                jiffies_to_msecs(part_stat_read(p, ticks[WRITE])),
-               part_in_flight(p),
+               p->in_flight,
                jiffies_to_msecs(part_stat_read(p, io_ticks)),
                jiffies_to_msecs(part_stat_read(p, time_in_queue)));
 }
 
-ssize_t part_inflight_show(struct device *dev,
-                       struct device_attribute *attr, char *buf)
-{
-       struct hd_struct *p = dev_to_part(dev);
-
-       return sprintf(buf, "%8u %8u\n", p->in_flight[0], p->in_flight[1]);
-}
-
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 ssize_t part_fail_show(struct device *dev,
                       struct device_attribute *attr, char *buf)
@@ -289,7 +281,6 @@ static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
 static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
 static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL);
 static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
-static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 static struct device_attribute dev_attr_fail =
        __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
@@ -301,7 +292,6 @@ static struct attribute *part_attrs[] = {
        &dev_attr_size.attr,
        &dev_attr_alignment_offset.attr,
        &dev_attr_stat.attr,
-       &dev_attr_inflight.attr,
 #ifdef CONFIG_FAIL_MAKE_REQUEST
        &dev_attr_fail.attr,
 #endif
index a201fc370223b01c918ae9767432c3060c6de95e..fd38ce2e32e349ba3c418dbc454957dd0e3ad958 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/syscalls.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index e23a86cae5ac9a328fd2fe1cc7c4eecc0741760c..25119041e034c9f51bdbbbfe4d3ad146ac9ad9c4 100644 (file)
@@ -82,7 +82,6 @@ enum rq_cmd_type_bits {
 enum {
        REQ_LB_OP_EJECT = 0x40,         /* eject request */
        REQ_LB_OP_FLUSH = 0x41,         /* flush request */
-       REQ_LB_OP_DISCARD = 0x42,       /* discard sectors */
 };
 
 /*
@@ -261,7 +260,6 @@ typedef void (request_fn_proc) (struct request_queue *q);
 typedef int (make_request_fn) (struct request_queue *q, struct bio *bio);
 typedef int (prep_rq_fn) (struct request_queue *, struct request *);
 typedef void (unplug_fn) (struct request_queue *);
-typedef int (prepare_discard_fn) (struct request_queue *, struct request *);
 
 struct bio_vec;
 struct bvec_merge_data {
@@ -313,6 +311,7 @@ struct queue_limits {
        unsigned int            alignment_offset;
        unsigned int            io_min;
        unsigned int            io_opt;
+       unsigned int            max_discard_sectors;
 
        unsigned short          logical_block_size;
        unsigned short          max_hw_segments;
@@ -340,7 +339,6 @@ struct request_queue
        make_request_fn         *make_request_fn;
        prep_rq_fn              *prep_rq_fn;
        unplug_fn               *unplug_fn;
-       prepare_discard_fn      *prepare_discard_fn;
        merge_bvec_fn           *merge_bvec_fn;
        prepare_flush_fn        *prepare_flush_fn;
        softirq_done_fn         *softirq_done_fn;
@@ -460,6 +458,7 @@ struct request_queue
 #define QUEUE_FLAG_VIRT        QUEUE_FLAG_NONROT /* paravirt device */
 #define QUEUE_FLAG_IO_STAT     15      /* do IO stats */
 #define QUEUE_FLAG_CQ         16       /* hardware does queuing */
+#define QUEUE_FLAG_DISCARD     17      /* supports DISCARD */
 
 #define QUEUE_FLAG_DEFAULT     ((1 << QUEUE_FLAG_IO_STAT) |            \
                                 (1 << QUEUE_FLAG_CLUSTER) |            \
@@ -591,6 +590,7 @@ enum {
 #define blk_queue_flushing(q)  ((q)->ordseq)
 #define blk_queue_stackable(q) \
        test_bit(QUEUE_FLAG_STACKABLE, &(q)->queue_flags)
+#define blk_queue_discard(q)   test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags)
 
 #define blk_fs_request(rq)     ((rq)->cmd_type == REQ_TYPE_FS)
 #define blk_pc_request(rq)     ((rq)->cmd_type == REQ_TYPE_BLOCK_PC)
@@ -929,6 +929,8 @@ extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int);
 extern void blk_queue_max_phys_segments(struct request_queue *, unsigned short);
 extern void blk_queue_max_hw_segments(struct request_queue *, unsigned short);
 extern void blk_queue_max_segment_size(struct request_queue *, unsigned int);
+extern void blk_queue_max_discard_sectors(struct request_queue *q,
+               unsigned int max_discard_sectors);
 extern void blk_queue_logical_block_size(struct request_queue *, unsigned short);
 extern void blk_queue_physical_block_size(struct request_queue *, unsigned short);
 extern void blk_queue_alignment_offset(struct request_queue *q,
@@ -955,7 +957,6 @@ extern void blk_queue_merge_bvec(struct request_queue *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(struct request_queue *, int);
 extern void blk_queue_update_dma_alignment(struct request_queue *, int);
 extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
-extern void blk_queue_set_discard(struct request_queue *, prepare_discard_fn *);
 extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
 extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
@@ -1080,25 +1081,37 @@ static inline unsigned int queue_physical_block_size(struct request_queue *q)
        return q->limits.physical_block_size;
 }
 
+static inline int bdev_physical_block_size(struct block_device *bdev)
+{
+       return queue_physical_block_size(bdev_get_queue(bdev));
+}
+
 static inline unsigned int queue_io_min(struct request_queue *q)
 {
        return q->limits.io_min;
 }
 
+static inline int bdev_io_min(struct block_device *bdev)
+{
+       return queue_io_min(bdev_get_queue(bdev));
+}
+
 static inline unsigned int queue_io_opt(struct request_queue *q)
 {
        return q->limits.io_opt;
 }
 
+static inline int bdev_io_opt(struct block_device *bdev)
+{
+       return queue_io_opt(bdev_get_queue(bdev));
+}
+
 static inline int queue_alignment_offset(struct request_queue *q)
 {
-       if (q && q->limits.misaligned)
+       if (q->limits.misaligned)
                return -1;
 
-       if (q && q->limits.alignment_offset)
-               return q->limits.alignment_offset;
-
-       return 0;
+       return q->limits.alignment_offset;
 }
 
 static inline int queue_sector_alignment_offset(struct request_queue *q,
@@ -1108,6 +1121,19 @@ static inline int queue_sector_alignment_offset(struct request_queue *q,
                & (q->limits.io_min - 1);
 }
 
+static inline int bdev_alignment_offset(struct block_device *bdev)
+{
+       struct request_queue *q = bdev_get_queue(bdev);
+
+       if (q->limits.misaligned)
+               return -1;
+
+       if (bdev != bdev->bd_contains)
+               return bdev->bd_part->alignment_offset;
+
+       return q->limits.alignment_offset;
+}
+
 static inline int queue_dma_alignment(struct request_queue *q)
 {
        return q ? q->dma_alignment : 511;
@@ -1146,7 +1172,11 @@ static inline void put_dev_sector(Sector p)
 }
 
 struct work_struct;
+struct delayed_work;
 int kblockd_schedule_work(struct request_queue *q, struct work_struct *work);
+int kblockd_schedule_delayed_work(struct request_queue *q,
+                                       struct delayed_work *work,
+                                       unsigned long delay);
 
 #define MODULE_ALIAS_BLOCKDEV(major,minor) \
        MODULE_ALIAS("block-major-" __stringify(major) "-" __stringify(minor))
index 7e4350ece0f8dd495398ca4cbf41c95e995b6525..3b73b9992b261125a22ef70a46bebc88a2eba23a 100644 (file)
@@ -198,6 +198,7 @@ extern int blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
                           char __user *arg);
 extern int blk_trace_startstop(struct request_queue *q, int start);
 extern int blk_trace_remove(struct request_queue *q);
+extern void blk_trace_remove_sysfs(struct device *dev);
 extern int blk_trace_init_sysfs(struct device *dev);
 
 extern struct attribute_group blk_trace_attr_group;
@@ -211,6 +212,7 @@ extern struct attribute_group blk_trace_attr_group;
 # define blk_trace_startstop(q, start)                 (-ENOTTY)
 # define blk_trace_remove(q)                           (-ENOTTY)
 # define blk_add_trace_msg(q, fmt, ...)                        do { } while (0)
+# define blk_trace_remove_sysfs(dev)                   do { } while (0)
 static inline int blk_trace_init_sysfs(struct device *dev)
 {
        return 0;
index a1e6899d4b6ca70a46518a2b75fc2f0e2a0aac38..2620a8c63571a673f29a802a8144fec5014575f3 100644 (file)
@@ -300,6 +300,10 @@ struct inodes_stat_t {
 #define BLKTRACESTOP _IO(0x12,117)
 #define BLKTRACETEARDOWN _IO(0x12,118)
 #define BLKDISCARD _IO(0x12,119)
+#define BLKIOMIN _IO(0x12,120)
+#define BLKIOOPT _IO(0x12,121)
+#define BLKALIGNOFF _IO(0x12,122)
+#define BLKPBSZGET _IO(0x12,123)
 
 #define BMAP_IOCTL 1           /* obsolete - kept for compatibility */
 #define FIBMAP    _IO(0x00,1)  /* bmap access */
index 297df45ffd0ad27e8219aaf3715a00d030f5bf54..7beaa21b3880051c341d55358b5312cdfb10c65a 100644 (file)
@@ -98,7 +98,7 @@ struct hd_struct {
        int make_it_fail;
 #endif
        unsigned long stamp;
-       int in_flight[2];
+       int in_flight;
 #ifdef CONFIG_SMP
        struct disk_stats *dkstats;
 #else
@@ -322,23 +322,18 @@ static inline void free_part_stats(struct hd_struct *part)
 #define part_stat_sub(cpu, gendiskp, field, subnd)                     \
        part_stat_add(cpu, gendiskp, field, -subnd)
 
-static inline void part_inc_in_flight(struct hd_struct *part, int rw)
+static inline void part_inc_in_flight(struct hd_struct *part)
 {
-       part->in_flight[rw]++;
+       part->in_flight++;
        if (part->partno)
-               part_to_disk(part)->part0.in_flight[rw]++;
+               part_to_disk(part)->part0.in_flight++;
 }
 
-static inline void part_dec_in_flight(struct hd_struct *part, int rw)
+static inline void part_dec_in_flight(struct hd_struct *part)
 {
-       part->in_flight[rw]--;
+       part->in_flight--;
        if (part->partno)
-               part_to_disk(part)->part0.in_flight[rw]--;
-}
-
-static inline int part_in_flight(struct hd_struct *part)
-{
-       return part->in_flight[0] + part->in_flight[1];
+               part_to_disk(part)->part0.in_flight--;
 }
 
 /* block/blk-core.c */
@@ -551,8 +546,6 @@ extern ssize_t part_size_show(struct device *dev,
                              struct device_attribute *attr, char *buf);
 extern ssize_t part_stat_show(struct device *dev,
                              struct device_attribute *attr, char *buf);
-extern ssize_t part_inflight_show(struct device *dev,
-                             struct device_attribute *attr, char *buf);
 #ifdef CONFIG_FAIL_MAKE_REQUEST
 extern ssize_t part_fail_show(struct device *dev,
                              struct device_attribute *attr, char *buf);
index fa287f25138dc2a243e27825f92d670b210a4b6b..6673743946f776d2bd7a61bacd68afdc6fd94f36 100644 (file)
@@ -6,10 +6,10 @@
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
+#include <linux/ktime.h>
 #include <linux/wait.h>
 #include <linux/string.h>
 #include <linux/fs.h>
-#include <linux/sched.h>
 #include <asm/uaccess.h>
 
 /* ~832 bytes of stack space used max in sys_select/sys_poll before allocating
index d86af94691c2c4148711f29880187b0587409581..00405b5f624a2d742a1d95d2a6fb59d530b6e369 100644 (file)
@@ -488,6 +488,39 @@ TRACE_EVENT(block_remap,
                  (unsigned long long)__entry->old_sector)
 );
 
+TRACE_EVENT(block_rq_remap,
+
+       TP_PROTO(struct request_queue *q, struct request *rq, dev_t dev,
+                sector_t from),
+
+       TP_ARGS(q, rq, dev, from),
+
+       TP_STRUCT__entry(
+               __field( dev_t,         dev             )
+               __field( sector_t,      sector          )
+               __field( unsigned int,  nr_sector       )
+               __field( dev_t,         old_dev         )
+               __field( sector_t,      old_sector      )
+               __array( char,          rwbs,   6       )
+       ),
+
+       TP_fast_assign(
+               __entry->dev            = disk_devt(rq->rq_disk);
+               __entry->sector         = blk_rq_pos(rq);
+               __entry->nr_sector      = blk_rq_sectors(rq);
+               __entry->old_dev        = dev;
+               __entry->old_sector     = from;
+               blk_fill_rwbs_rq(__entry->rwbs, rq);
+       ),
+
+       TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu",
+                 MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs,
+                 (unsigned long long)__entry->sector,
+                 __entry->nr_sector,
+                 MAJOR(__entry->old_dev), MINOR(__entry->old_dev),
+                 (unsigned long long)__entry->old_sector)
+);
+
 #endif /* _TRACE_BLOCK_H */
 
 /* This part must be outside protection */
index 6d7020490f94fdc3563f81c0582935492f724a34..3e1c36e7998fdbeffa17142bade5c358c61a2857 100644 (file)
@@ -726,8 +726,6 @@ static int hrtimer_switch_to_hres(void)
        /* "Retrigger" the interrupt to get things going */
        retrigger_next_event(NULL);
        local_irq_restore(flags);
-       printk(KERN_DEBUG "Switched to high resolution mode on CPU %d\n",
-              smp_processor_id());
        return 1;
 }
 
index 0f86feb6db0c227c2f4e7b1c47c8b4d2c0e92156..e491fb0879398b23a6951f7ea4c11f804e4e8eb4 100644 (file)
@@ -1030,14 +1030,10 @@ void __perf_event_sched_out(struct perf_event_context *ctx,
        update_context_time(ctx);
 
        perf_disable();
-       if (ctx->nr_active) {
-               list_for_each_entry(event, &ctx->group_list, group_entry) {
-                       if (event != event->group_leader)
-                               event_sched_out(event, cpuctx, ctx);
-                       else
-                               group_sched_out(event, cpuctx, ctx);
-               }
-       }
+       if (ctx->nr_active)
+               list_for_each_entry(event, &ctx->group_list, group_entry)
+                       group_sched_out(event, cpuctx, ctx);
+
        perf_enable();
  out:
        spin_unlock(&ctx->lock);
@@ -1258,12 +1254,8 @@ __perf_event_sched_in(struct perf_event_context *ctx,
                if (event->cpu != -1 && event->cpu != cpu)
                        continue;
 
-               if (event != event->group_leader)
-                       event_sched_in(event, cpuctx, ctx, cpu);
-               else {
-                       if (group_can_go_on(event, cpuctx, 1))
-                               group_sched_in(event, cpuctx, ctx, cpu);
-               }
+               if (group_can_go_on(event, cpuctx, 1))
+                       group_sched_in(event, cpuctx, ctx, cpu);
 
                /*
                 * If this pinned group hasn't been scheduled,
@@ -1291,15 +1283,9 @@ __perf_event_sched_in(struct perf_event_context *ctx,
                if (event->cpu != -1 && event->cpu != cpu)
                        continue;
 
-               if (event != event->group_leader) {
-                       if (event_sched_in(event, cpuctx, ctx, cpu))
+               if (group_can_go_on(event, cpuctx, can_add_hw))
+                       if (group_sched_in(event, cpuctx, ctx, cpu))
                                can_add_hw = 0;
-               } else {
-                       if (group_can_go_on(event, cpuctx, can_add_hw)) {
-                               if (group_sched_in(event, cpuctx, ctx, cpu))
-                                       can_add_hw = 0;
-                       }
-               }
        }
        perf_enable();
  out:
@@ -4781,9 +4767,7 @@ int perf_event_init_task(struct task_struct *child)
         * We dont have to disable NMIs - we are only looking at
         * the list, not manipulating it:
         */
-       list_for_each_entry_rcu(event, &parent_ctx->event_list, event_entry) {
-               if (event != event->group_leader)
-                       continue;
+       list_for_each_entry(event, &parent_ctx->group_list, group_entry) {
 
                if (!event->attr.inherit) {
                        inherited_all = 0;
index 3eb159c277c85a7a9d30f3b94d1a68bfa52661b0..d9d6206e0b148f5c67e5ecda22a7c7992eec76d7 100644 (file)
@@ -855,6 +855,37 @@ static void blk_add_trace_remap(struct request_queue *q, struct bio *bio,
                        sizeof(r), &r);
 }
 
+/**
+ * blk_add_trace_rq_remap - Add a trace for a request-remap operation
+ * @q:         queue the io is for
+ * @rq:                the source request
+ * @dev:       target device
+ * @from:      source sector
+ *
+ * Description:
+ *     Device mapper remaps request to other devices.
+ *     Add a trace for that action.
+ *
+ **/
+static void blk_add_trace_rq_remap(struct request_queue *q,
+                                  struct request *rq, dev_t dev,
+                                  sector_t from)
+{
+       struct blk_trace *bt = q->blk_trace;
+       struct blk_io_trace_remap r;
+
+       if (likely(!bt))
+               return;
+
+       r.device_from = cpu_to_be32(dev);
+       r.device_to   = cpu_to_be32(disk_devt(rq->rq_disk));
+       r.sector_from = cpu_to_be64(from);
+
+       __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq),
+                       rq_data_dir(rq), BLK_TA_REMAP, !!rq->errors,
+                       sizeof(r), &r);
+}
+
 /**
  * blk_add_driver_data - Add binary message with driver-specific data
  * @q:         queue the io is for
@@ -922,10 +953,13 @@ static void blk_register_tracepoints(void)
        WARN_ON(ret);
        ret = register_trace_block_remap(blk_add_trace_remap);
        WARN_ON(ret);
+       ret = register_trace_block_rq_remap(blk_add_trace_rq_remap);
+       WARN_ON(ret);
 }
 
 static void blk_unregister_tracepoints(void)
 {
+       unregister_trace_block_rq_remap(blk_add_trace_rq_remap);
        unregister_trace_block_remap(blk_add_trace_remap);
        unregister_trace_block_split(blk_add_trace_split);
        unregister_trace_block_unplug_io(blk_add_trace_unplug_io);
@@ -1657,6 +1691,11 @@ int blk_trace_init_sysfs(struct device *dev)
        return sysfs_create_group(&dev->kobj, &blk_trace_attr_group);
 }
 
+void blk_trace_remove_sysfs(struct device *dev)
+{
+       sysfs_remove_group(&dev->kobj, &blk_trace_attr_group);
+}
+
 #endif /* CONFIG_BLK_DEV_IO_TRACE */
 
 #ifdef CONFIG_EVENT_TRACING
index 46592feab5a6b0cf47e5cc147f43e1669efcf712..3724756e41ca9771d311101a38d2f408d416ef6a 100644 (file)
@@ -225,7 +225,11 @@ static void ftrace_update_pid_func(void)
        if (ftrace_trace_function == ftrace_stub)
                return;
 
+#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
        func = ftrace_trace_function;
+#else
+       func = __ftrace_trace_function;
+#endif
 
        if (ftrace_pid_trace) {
                set_ftrace_pid_function(func);
index 81b1645c85490175beeea335fcebecb12fd4783a..a91da69f153ad0c859997356d53db6548006db7c 100644 (file)
@@ -501,7 +501,7 @@ static int __init init_kmem_tracer(void)
                return 1;
        }
 
-       if (!register_tracer(&kmem_tracer)) {
+       if (register_tracer(&kmem_tracer) != 0) {
                pr_warning("Warning: could not register the kmem tracer\n");
                return 1;
        }
index 4de7f02f820b03bfcf36b5fc8d6827b5eecd38cb..a1bc6b9af9a23634f4185e85775d94a6500bbb0e 100644 (file)
@@ -1974,12 +1974,14 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
                goto bad_swap;
        }
 
-       if (blk_queue_nonrot(bdev_get_queue(p->bdev))) {
-               p->flags |= SWP_SOLIDSTATE;
-               p->cluster_next = 1 + (random32() % p->highest_bit);
+       if (p->bdev) {
+               if (blk_queue_nonrot(bdev_get_queue(p->bdev))) {
+                       p->flags |= SWP_SOLIDSTATE;
+                       p->cluster_next = 1 + (random32() % p->highest_bit);
+               }
+               if (discard_swap(p) == 0)
+                       p->flags |= SWP_DISCARDABLE;
        }
-       if (discard_swap(p) == 0)
-               p->flags |= SWP_DISCARDABLE;
 
        mutex_lock(&swapon_mutex);
        spin_lock(&swap_lock);
index dbeaf2983822e99a36377017b16e33e1fae32a03..ba2efb960c6007ecbd9b5b0a49372d21d32ed68a 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/rfkill.h>
+#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/miscdevice.h>
 #include <linux/wait.h>
index 1c2ed3090cce2de65ef80be78f9db02644531854..a7910099d6fd5111470b543d9aa2bcfe57fc96c4 100644 (file)
@@ -31,6 +31,9 @@ OPTIONS
 -w::
 --width=::
         Select the width of the SVG file (default: 1000)
+-p::
+--power-only::
+        Only output the CPU power section of the diagram
 
 
 SEE ALSO
index b5f1953b614438a38dbab19efc4b61d95e8e656c..5881943f0c3430e5023796b0f5e0fc83d40b2796 100644 (file)
@@ -728,7 +728,7 @@ $(BUILT_INS): perf$X
 common-cmds.h: util/generate-cmdlist.sh command-list.txt
 
 common-cmds.h: $(wildcard Documentation/perf-*.txt)
-       $(QUIET_GEN)util/generate-cmdlist.sh > $@+ && mv $@+ $@
+       $(QUIET_GEN)util/generate-cmdlist.sh > $@+ && mv $@+ $@
 
 $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
        $(QUIET_GEN)$(RM) $@ $@+ && \
index 4405681b31348d5613927488f953d90b016bcd5b..702d8fe58fbcd43152f1083c3e171b46a1abd48f 100644 (file)
@@ -46,6 +46,8 @@ static u64            turbo_frequency;
 
 static u64             first_time, last_time;
 
+static int             power_only;
+
 
 static struct perf_header      *header;
 
@@ -547,7 +549,7 @@ static void end_sample_processing(void)
        u64 cpu;
        struct power_event *pwr;
 
-       for (cpu = 0; cpu < numcpus; cpu++) {
+       for (cpu = 0; cpu <= numcpus; cpu++) {
                pwr = malloc(sizeof(struct power_event));
                if (!pwr)
                        return;
@@ -871,7 +873,7 @@ static int determine_display_tasks(u64 threshold)
                /* no exit marker, task kept running to the end */
                if (p->end_time == 0)
                        p->end_time = last_time;
-               if (p->total_time >= threshold)
+               if (p->total_time >= threshold && !power_only)
                        p->display = 1;
 
                c = p->all;
@@ -882,7 +884,7 @@ static int determine_display_tasks(u64 threshold)
                        if (c->start_time == 1)
                                c->start_time = first_time;
 
-                       if (c->total_time >= threshold) {
+                       if (c->total_time >= threshold && !power_only) {
                                c->display = 1;
                                count++;
                        }
@@ -1134,6 +1136,8 @@ static const struct option options[] = {
                    "output file name"),
        OPT_INTEGER('w', "width", &svg_page_width,
                    "page width"),
+       OPT_BOOLEAN('p', "power-only", &power_only,
+                   "output power data only"),
        OPT_END()
 };
 
index 1ca88896eee452adbc1425005776f66a13fc9611..37512e936235359aa4ebbf93d21831cce56750d7 100644 (file)
@@ -782,6 +782,7 @@ static const char *skip_symbols[] = {
        "exit_idle",
        "mwait_idle",
        "mwait_idle_with_hints",
+       "poll_idle",
        "ppc64_runlatch_off",
        "pseries_dedicated_idle_sleep",
        NULL
index a778fd0f4ae4796617365e105aa660ee6de57907..856655d8b0b8665b9cd3cd0edb482564d7b65a8a 100644 (file)
@@ -28,7 +28,7 @@ static u64 turbo_frequency, max_freq;
 
 int svg_page_width = 1000;
 
-#define MIN_TEXT_SIZE 0.001
+#define MIN_TEXT_SIZE 0.01
 
 static u64 total_height;
 static FILE *svgfile;
@@ -217,6 +217,18 @@ static char *cpu_model(void)
                }
                fclose(file);
        }
+
+       /* CPU type */
+       file = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies", "r");
+       if (file) {
+               while (fgets(buf, 255, file)) {
+                       unsigned int freq;
+                       freq = strtoull(buf, NULL, 10);
+                       if (freq > max_freq)
+                               max_freq = freq;
+               }
+               fclose(file);
+       }
        return cpu_m;
 }
 
This page took 0.167371 seconds and 5 git commands to generate.