Merge branch 'linux-2.6'
authorPaul Mackerras <paulus@samba.org>
Tue, 8 May 2007 03:37:51 +0000 (13:37 +1000)
committerPaul Mackerras <paulus@samba.org>
Tue, 8 May 2007 03:37:51 +0000 (13:37 +1000)
16 files changed:
1  2 
arch/powerpc/Kconfig
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/legacy_serial.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/vio.c
arch/ppc/syslib/ppc4xx_sgdma.c
drivers/ide/pci/pdc202xx_new.c
drivers/infiniband/hw/ehca/ehca_main.c
drivers/pci/hotplug/rpaphp_core.c
drivers/scsi/ibmvscsi/ibmvstgt.c
drivers/serial/of_serial.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ohci-ps3.c
drivers/video/ps3fb.c
include/linux/suspend.h
kernel/power/Kconfig

diff --combined arch/powerpc/Kconfig
@@@ -117,20 -117,25 +117,33 @@@ config GENERIC_BU
        default y
        depends on BUG
  
 +config SYS_SUPPORTS_APM_EMULATION
 +      bool
 +
+ #
+ # Powerpc uses the slab allocator to manage its ptes and the
+ # page structs of ptes are used for splitting the page table
+ # lock for configurations supporting more than SPLIT_PTLOCK_CPUS.
+ #
+ # In that special configuration the page structs of slabs are modified.
+ # This setting disables the selection of SLUB as a slab allocator.
+ #
+ config ARCH_USES_SLAB_PAGE_STRUCT
+       bool
+       default y
+       depends on SPLIT_PTLOCK_CPUS <= NR_CPUS
  config DEFAULT_UIMAGE
        bool
        help
          Used to allow a board to specify it wants a uImage built by default
        default n
  
 +config PPC64_SWSUSP
 +      bool
 +      depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL))
 +      default y
 +
  menu "Processor support"
  choice
        prompt "Processor Type"
@@@ -664,7 -669,7 +677,7 @@@ config MC
  config PCI
        bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
                || PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
 -              || MPC7448HPC2 || PPC_PS3
 +              || MPC7448HPC2 || PPC_PS3 || PPC_HOLLY
        default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx \
                && !PPC_85xx && !PPC_86xx
        default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
@@@ -36,9 -36,8 +36,9 @@@ obj-$(CONFIG_GENERIC_TBSYNC)  += smp-tbs
  obj-$(CONFIG_CRASH_DUMP)      += crash_dump.o
  obj-$(CONFIG_6xx)             += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
  obj-$(CONFIG_TAU)             += tau_6xx.o
- obj-$(CONFIG_SOFTWARE_SUSPEND)        += swsusp.o
++obj-$(CONFIG_SOFTWARE_SUSPEND)        += swsusp.o suspend.o
  obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
 -obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
 +obj64-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_64.o swsusp_asm64.o
  obj32-$(CONFIG_MODULES)               += module_32.o
  
  ifeq ($(CONFIG_PPC_MERGE),y)
@@@ -115,7 -115,8 +115,8 @@@ static int __init add_legacy_soc_port(s
  {
        u64 addr;
        const u32 *addrp;
-       upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+       upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ
+               | UPF_FIXED_PORT;
        struct device_node *tsi = of_get_parent(np);
  
        /* We only support ports that have a clock frequency properly
@@@ -243,9 -244,9 +244,9 @@@ static int __init add_legacy_pci_port(s
         * doesn't work for these settings, you'll have to add your own special
         * cases here
         */
 -      if (device_is_compatible(pci_dev, "pci13a8,152") ||
 -          device_is_compatible(pci_dev, "pci13a8,154") ||
 -          device_is_compatible(pci_dev, "pci13a8,158")) {
 +      if (of_device_is_compatible(pci_dev, "pci13a8,152") ||
 +          of_device_is_compatible(pci_dev, "pci13a8,154") ||
 +          of_device_is_compatible(pci_dev, "pci13a8,158")) {
                addr += 0x200 * lindex;
                base += 0x200 * lindex;
        } else {
@@@ -364,11 -365,11 +365,11 @@@ void __init find_legacy_serial_ports(vo
                /* Check for known pciclass, and also check wether we have
                 * a device with child nodes for ports or not
                 */
 -              if (device_is_compatible(np, "pciclass,0700") ||
 -                  device_is_compatible(np, "pciclass,070002"))
 +              if (of_device_is_compatible(np, "pciclass,0700") ||
 +                  of_device_is_compatible(np, "pciclass,070002"))
                        pci = np;
 -              else if (device_is_compatible(parent, "pciclass,0700") ||
 -                       device_is_compatible(parent, "pciclass,070002"))
 +              else if (of_device_is_compatible(parent, "pciclass,0700") ||
 +                       of_device_is_compatible(parent, "pciclass,070002"))
                        pci = parent;
                else {
                        of_node_put(parent);
@@@ -340,7 -340,7 +340,7 @@@ struct pci_dev *of_create_pci_dev(struc
        struct pci_dev *dev;
        const char *type;
  
-       dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+       dev = alloc_pci_dev();
        if (!dev)
                return NULL;
        type = of_get_property(node, "device_type", NULL);
@@@ -1006,9 -1006,8 +1006,9 @@@ void __devinit pci_process_bridge_OF_ra
  
                switch ((pci_space >> 24) & 0x3) {
                case 1:         /* I/O space */
 -                      hose->io_base_phys = cpu_phys_addr;
 -                      hose->pci_io_size = size;
 +                      hose->io_base_phys = cpu_phys_addr - pci_addr;
 +                      /* handle from 0 to top of I/O window */
 +                      hose->pci_io_size = pci_addr + size;
  
                        res = &hose->io_resource;
                        res->flags = IORESOURCE_IO;
@@@ -1118,8 -1117,8 +1118,8 @@@ static int get_bus_io_range(struct pci_
        } else {
                /* Root Bus */
                res = &hose->io_resource;
 -              *start_phys = hose->io_base_phys;
 -              *start_virt = (unsigned long) hose->io_base_virt;
 +              *start_phys = hose->io_base_phys + res->start;
 +              *start_virt = (unsigned long) hose->io_base_virt + res->start;
                if (res->end > res->start)
                        *size = res->end - res->start + 1;
                else {
@@@ -37,7 -37,7 +37,7 @@@
  #include <asm/iseries/hv_call_xm.h>
  #include <asm/iseries/iommu.h>
  
- extern struct subsystem devices_subsys; /* needed for vio_find_name() */
+ extern struct kset devices_subsys; /* needed for vio_find_name() */
  
  static struct vio_dev vio_bus_device  = { /* fake "parent" device */
        .name = vio_bus_device.dev.bus_id,
@@@ -117,7 -117,7 +117,7 @@@ static const struct vio_device_id *vio_
  {
        while (ids->type[0] != '\0') {
                if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&
 -                  device_is_compatible(dev->dev.archdata.of_node,
 +                  of_device_is_compatible(dev->dev.archdata.of_node,
                                         ids->compat))
                        return ids;
                ids++;
@@@ -427,7 -427,7 +427,7 @@@ static struct vio_dev *vio_find_name(co
  {
        struct kobject *found;
  
-       found = kset_find_obj(&devices_subsys.kset, kobj_name);
+       found = kset_find_obj(&devices_subsys, kobj_name);
        if (!found)
                return NULL;
  
  #include <linux/mm.h>
  #include <linux/init.h>
  #include <linux/module.h>
- #include <linux/pci.h>
 +#include <linux/dma-mapping.h>
  
  #include <asm/system.h>
  #include <asm/io.h>
 -#include <asm/dma-mapping.h>
  #include <asm/ppc4xx_dma.h>
  
  void
@@@ -255,9 -255,6 +255,6 @@@ static int config_chipset_for_dma(ide_d
                printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
        }
  
-       if (drive->media != ide_disk && drive->media != ide_cdrom)
-               return 0;
        if (id->capability & 4) {
                /*
                 * Set IORDY_EN & PREFETCH_EN (this seems to have
@@@ -398,7 -395,7 +395,7 @@@ static void __devinit apple_kiwi_init(s
        unsigned int class_rev = 0;
        u8 conf;
  
 -      if (np == NULL || !device_is_compatible(np, "kiwi-root"))
 +      if (np == NULL || !of_device_is_compatible(np, "kiwi-root"))
                return;
  
        pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
@@@ -313,6 -313,7 +313,7 @@@ int ehca_init_device(struct ehca_shca *
  
        shca->ib_device.node_type           = RDMA_NODE_IB_CA;
        shca->ib_device.phys_port_cnt       = shca->num_ports;
+       shca->ib_device.num_comp_vectors    = 1;
        shca->ib_device.dma_device          = &shca->ibmebus_dev->ofdev.dev;
        shca->ib_device.query_device        = ehca_query_device;
        shca->ib_device.query_port          = ehca_query_port;
@@@ -375,7 -376,7 +376,7 @@@ static int ehca_create_aqp1(struct ehca
                return -EPERM;
        }
  
-       ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10);
+       ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10, 0);
        if (IS_ERR(ibcq)) {
                ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
                return PTR_ERR(ibcq);
@@@ -569,7 -570,7 +570,7 @@@ static int __devinit ehca_probe(struct 
        struct ib_pd *ibpd;
        int ret;
  
 -      handle = get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
 +      handle = of_get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
        if (!handle) {
                ehca_gen_err("Cannot get eHCA handle for adapter: %s.",
                             dev->ofdev.node->full_name);
@@@ -39,9 -39,7 +39,7 @@@
  #include "rpaphp.h"
  
  int debug;
- static struct semaphore rpaphp_sem;
  LIST_HEAD(rpaphp_slot_head);
- int num_slots;
  
  #define DRIVER_VERSION        "0.1"
  #define DRIVER_AUTHOR "Linda Xie <lxie@us.ibm.com>"
@@@ -55,11 -53,6 +53,6 @@@ MODULE_LICENSE("GPL")
  
  module_param(debug, bool, 0644);
  
- static int rpaphp_get_attention_status(struct slot *slot)
- {
-       return slot->hotplug_slot->info->attention_status;
- }
  /**
   * set_attention_status - set attention LED
   * echo 0 > attention -- set LED OFF
   */
  static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
  {
-       int retval = 0;
+       int rc;
        struct slot *slot = (struct slot *)hotplug_slot->private;
  
-       down(&rpaphp_sem);
        switch (value) {
        case 0:
-               retval = rpaphp_set_attention_status(slot, LED_OFF);
-               hotplug_slot->info->attention_status = 0;
-               break;
        case 1:
-       default:
-               retval = rpaphp_set_attention_status(slot, LED_ON);
-               hotplug_slot->info->attention_status = 1;
-               break;
        case 2:
-               retval = rpaphp_set_attention_status(slot, LED_ID);
-               hotplug_slot->info->attention_status = 2;
+               break;
+       default:
+               value = 1;
                break;
        }
-       up(&rpaphp_sem);
-       return retval;
+       rc = rtas_set_indicator(DR_INDICATOR, slot->index, value);
+       if (!rc)
+               hotplug_slot->info->attention_status = value;
+       return rc;
  }
  
  /**
   * get_power_status - get power status of a slot
   * @hotplug_slot: slot to get status
   * @value: pointer to store status
-  *
-  *
   */
  static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
  {
-       int retval;
+       int retval, level;
        struct slot *slot = (struct slot *)hotplug_slot->private;
  
-       down(&rpaphp_sem);
-       retval = rpaphp_get_power_status(slot, value);
-       up(&rpaphp_sem);
+       retval = rtas_get_power_level (slot->power_domain, &level);
+       if (!retval)
+               *value = level;
        return retval;
  }
  
  /**
   * get_attention_status - get attention LED status
-  *
-  *
   */
  static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
  {
-       int retval = 0;
        struct slot *slot = (struct slot *)hotplug_slot->private;
-       down(&rpaphp_sem);
-       *value = rpaphp_get_attention_status(slot);
-       up(&rpaphp_sem);
-       return retval;
+       *value = slot->hotplug_slot->info->attention_status;
+       return 0;
  }
  
  static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
  {
        struct slot *slot = (struct slot *)hotplug_slot->private;
-       int retval = 0;
+       int rc, state;
  
-       down(&rpaphp_sem);
-       retval = rpaphp_get_pci_adapter_status(slot, 0, value);
-       up(&rpaphp_sem);
-       return retval;
+       rc = rpaphp_get_sensor_state(slot, &state);
+       *value = NOT_VALID;
+       if (rc)
+               return rc;
+       if (state == EMPTY)
+               *value = EMPTY;
+       else if (state == PRESENT)
+               *value = slot->state;
+       return 0;
  }
  
  static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
  {
        struct slot *slot = (struct slot *)hotplug_slot->private;
  
-       down(&rpaphp_sem);
        switch (slot->type) {
        case 1:
        case 2:
                break;
  
        }
-       up(&rpaphp_sem);
        return 0;
  }
  
@@@ -182,10 -170,10 +170,10 @@@ static int get_children_props(struct de
  {
        const int *indexes, *names, *types, *domains;
  
 -      indexes = get_property(dn, "ibm,drc-indexes", NULL);
 -      names = get_property(dn, "ibm,drc-names", NULL);
 -      types = get_property(dn, "ibm,drc-types", NULL);
 -      domains = get_property(dn, "ibm,drc-power-domains", NULL);
 +      indexes = of_get_property(dn, "ibm,drc-indexes", NULL);
 +      names = of_get_property(dn, "ibm,drc-names", NULL);
 +      types = of_get_property(dn, "ibm,drc-types", NULL);
 +      domains = of_get_property(dn, "ibm,drc-power-domains", NULL);
  
        if (!indexes || !names || !types || !domains) {
                /* Slot does not have dynamically-removable children */
@@@ -218,7 -206,7 +206,7 @@@ int rpaphp_get_drc_props(struct device_
        char *name_tmp, *type_tmp;
        int i, rc;
  
 -      my_index = get_property(dn, "ibm,my-drc-index", NULL);
 +      my_index = of_get_property(dn, "ibm,my-drc-index", NULL);
        if (!my_index) {
                /* Node isn't DLPAR/hotplug capable */
                return -EINVAL;
@@@ -265,6 -253,14 +253,14 @@@ static int is_php_type(char *drc_type
        return 1;
  }
  
+ /**
+  * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0
+  *
+  * This routine will return true only if the device node is
+  * a hotpluggable slot. This routine will return false
+  * for built-in pci slots (even when the built-in slots are
+  * dlparable.)
+  */
  static int is_php_dn(struct device_node *dn, const int **indexes,
                const int **names, const int **types, const int **power_domains)
  {
        int rc;
  
        rc = get_children_props(dn, indexes, names, &drc_types, power_domains);
-       if (rc >= 0) {
-               if (is_php_type((char *) &drc_types[1])) {
-                       *types = drc_types;
-                       return 1;
-               }
-       }
+       if (rc < 0)
+               return 0;
  
-       return 0;
+       if (!is_php_type((char *) &drc_types[1]))
+               return 0;
+       *types = drc_types;
+       return 1;
  }
  
  /**
-  * rpaphp_add_slot -- add hotplug or dlpar slot
+  * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem.
+  * @dn device node of slot
+  *
+  * This subroutine will register a hotplugable slot with the
+  * PCI hotplug infrastructure. This routine is typicaly called
+  * during boot time, if the hotplug slots are present at boot time,
+  * or is called later, by the dlpar add code, if the slot is
+  * being dynamically added during runtime.
+  *
+  * If the device node points at an embedded (built-in) slot, this
+  * routine will just return without doing anything, since embedded
+  * slots cannot be hotplugged.
   *
-  *    rpaphp not only registers PCI hotplug slots(HOTPLUG), 
-  *    but also logical DR slots(EMBEDDED).
-  *    HOTPLUG slot: An adapter can be physically added/removed. 
-  *    EMBEDDED slot: An adapter can be logically removed/added
-  *              from/to a partition with the slot.
+  * To remove a slot, it suffices to call rpaphp_deregister_slot()
   */
  int rpaphp_add_slot(struct device_node *dn)
  {
        const int *indexes, *names, *types, *power_domains;
        char *name, *type;
  
+       if (!dn->name || strcmp(dn->name, "pci"))
+               return 0;
+       /* If this is not a hotplug slot, return without doing anything. */
+       if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
+               return 0;
        dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name);
  
        /* register PCI devices */
-       if (dn->name != 0 && strcmp(dn->name, "pci") == 0) {
-               if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
-                       goto exit;
-               name = (char *) &names[1];
-               type = (char *) &types[1];
-               for (i = 0; i < indexes[0]; i++,
-                       name += (strlen(name) + 1), type += (strlen(type) + 1))                 {
-                       if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name,
-                                      power_domains[i + 1]))) {
-                               retval = -ENOMEM;
-                               goto exit;
-                       }
-                       slot->type = simple_strtoul(type, NULL, 10);
+       name = (char *) &names[1];
+       type = (char *) &types[1];
+       for (i = 0; i < indexes[0]; i++) {
+               slot = alloc_slot_struct(dn, indexes[i + 1], name, power_domains[i + 1]);
+               if (!slot)
+                       return -ENOMEM;
+               slot->type = simple_strtoul(type, NULL, 10);
                                
-                       dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
-                                       indexes[i + 1], name, type);
+               dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
+                               indexes[i + 1], name, type);
  
-                       retval = rpaphp_register_pci_slot(slot);
-               }
+               retval = rpaphp_enable_slot(slot);
+               if (!retval)
+                       retval = rpaphp_register_slot(slot);
+               if (retval)
+                       dealloc_slot_struct(slot);
+               name += strlen(name) + 1;
+               type += strlen(type) + 1;
        }
- exit:
-       dbg("%s - Exit: num_slots=%d rc[%d]\n",
-           __FUNCTION__, num_slots, retval);
+       dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
+       /* XXX FIXME: reports a failure only if last entry in loop failed */
        return retval;
  }
  
@@@ -354,7 -365,6 +365,6 @@@ static int __init rpaphp_init(void
        struct device_node *dn = NULL;
  
        info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
-       init_MUTEX(&rpaphp_sem);
  
        while ((dn = of_find_node_by_name(dn, "pci")))
                rpaphp_add_slot(dn);
@@@ -367,8 -377,9 +377,9 @@@ static void __exit rpaphp_exit(void
        cleanup_slots();
  }
  
- static int __enable_slot(struct slot *slot)
+ static int enable_slot(struct hotplug_slot *hotplug_slot)
  {
+       struct slot *slot = (struct slot *)hotplug_slot->private;
        int state;
        int retval;
  
        return 0;
  }
  
- static int enable_slot(struct hotplug_slot *hotplug_slot)
+ static int disable_slot(struct hotplug_slot *hotplug_slot)
  {
-       int retval;
        struct slot *slot = (struct slot *)hotplug_slot->private;
-       down(&rpaphp_sem);
-       retval = __enable_slot(slot);
-       up(&rpaphp_sem);
-       return retval;
- }
- static int __disable_slot(struct slot *slot)
- {
-       struct pci_dev *dev, *tmp;
        if (slot->state == NOT_CONFIGURED)
                return -EINVAL;
  
-       list_for_each_entry_safe(dev, tmp, &slot->bus->devices, bus_list) {
-               eeh_remove_bus_device(dev);
-               pci_remove_bus_device(dev);
-       }
+       pcibios_remove_pci_devices(slot->bus);
        slot->state = NOT_CONFIGURED;
        return 0;
  }
  
- static int disable_slot(struct hotplug_slot *hotplug_slot)
- {
-       struct slot *slot = (struct slot *)hotplug_slot->private;
-       int retval;
-       down(&rpaphp_sem);
-       retval = __disable_slot (slot);
-       up(&rpaphp_sem);
-       return retval;
- }
  struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
        .owner = THIS_MODULE,
        .enable_slot = enable_slot,
@@@ -35,7 -35,7 +35,7 @@@
  #include "ibmvscsi.h"
  
  #define       INITIAL_SRP_LIMIT       16
- #define       DEFAULT_MAX_SECTORS     512
+ #define       DEFAULT_MAX_SECTORS     256
  
  #define       TGT_NAME        "ibmvstgt"
  
@@@ -248,8 -248,8 +248,8 @@@ static int ibmvstgt_rdma(struct scsi_cm
                                                  md[i].va + mdone);
  
                        if (err != H_SUCCESS) {
-                               eprintk("rdma error %d %d\n", dir, slen);
-                               goto out;
+                               eprintk("rdma error %d %d %ld\n", dir, slen, err);
+                               return -EIO;
                        }
  
                        mlen -= slen;
                                if (sidx > nsg) {
                                        eprintk("out of sg %p %d %d\n",
                                                iue, sidx, nsg);
-                                       goto out;
+                                       return -EIO;
                                }
                        }
                };
  
                rest -= mlen;
        }
- out:
        return 0;
  }
  
- static int ibmvstgt_transfer_data(struct scsi_cmnd *sc,
-                                 void (*done)(struct scsi_cmnd *))
- {
-       struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
-       int err;
-       err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
-       done(sc);
-       return err;
- }
  static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
                             void (*done)(struct scsi_cmnd *))
  {
        unsigned long flags;
        struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
        struct srp_target *target = iue->target;
+       int err = 0;
  
-       dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]);
+       dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
+               cmd->usg_sg);
+       if (sc->use_sg)
+               err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
  
        spin_lock_irqsave(&target->lock, flags);
        list_del(&iue->ilist);
        spin_unlock_irqrestore(&target->lock, flags);
  
-       if (sc->result != SAM_STAT_GOOD) {
+       if (err|| sc->result != SAM_STAT_GOOD) {
                eprintk("operation failed %p %d %x\n",
                        iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]);
                send_rsp(iue, sc, HARDWARE_ERROR, 0x00);
@@@ -503,7 -493,8 +493,8 @@@ static void process_iu(struct viosrp_cr
  {
        struct vio_port *vport = target_to_port(target);
        struct iu_entry *iue;
-       long err, done;
+       long err;
+       int done = 1;
  
        iue = srp_iu_get(target);
        if (!iue) {
  
        if (err != H_SUCCESS) {
                eprintk("%ld transferring data error %p\n", err, iue);
-               done = 1;
                goto out;
        }
  
@@@ -794,7 -784,6 +784,6 @@@ static struct scsi_host_template ibmvst
        .use_clustering         = DISABLE_CLUSTERING,
        .max_sectors            = DEFAULT_MAX_SECTORS,
        .transfer_response      = ibmvstgt_cmd_done,
-       .transfer_data          = ibmvstgt_transfer_data,
        .eh_abort_handler       = ibmvstgt_eh_abort_handler,
        .tsk_mgmt_response      = ibmvstgt_tsk_mgmt_response,
        .shost_attrs            = ibmvstgt_attrs,
@@@ -903,16 -892,16 +892,16 @@@ static int get_system_info(void
        if (!rootdn)
                return -ENOENT;
  
 -      model = get_property(rootdn, "model", NULL);
 -      id = get_property(rootdn, "system-id", NULL);
 +      model = of_get_property(rootdn, "model", NULL);
 +      id = of_get_property(rootdn, "system-id", NULL);
        if (model && id)
                snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
  
 -      name = get_property(rootdn, "ibm,partition-name", NULL);
 +      name = of_get_property(rootdn, "ibm,partition-name", NULL);
        if (name)
                strncpy(partition_name, name, sizeof(partition_name));
  
 -      num = get_property(rootdn, "ibm,partition-no", NULL);
 +      num = of_get_property(rootdn, "ibm,partition-no", NULL);
        if (num)
                partition_number = *num;
  
@@@ -29,8 -29,8 +29,8 @@@ static int __devinit of_platform_serial
        int ret;
  
        memset(port, 0, sizeof *port);
 -      spd = get_property(np, "current-speed", NULL);
 -      clk = get_property(np, "clock-frequency", NULL);
 +      spd = of_get_property(np, "current-speed", NULL);
 +      clk = of_get_property(np, "clock-frequency", NULL);
        if (!clk) {
                dev_warn(&ofdev->dev, "no clock-frequency property set\n");
                return -ENODEV;
@@@ -48,7 -48,8 +48,8 @@@
        port->iotype = UPIO_MEM;
        port->type = type;
        port->uartclk = *clk;
-       port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+       port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
+               | UPF_FIXED_PORT;
        port->dev = &ofdev->dev;
        port->custom_divisor = *clk / (16 * (*spd));
  
@@@ -73,13 -73,6 +73,6 @@@ static const struct hc_driver ps3_ehci_
  #endif
  };
  
- #if !defined(DEBUG)
- #undef dev_dbg
- static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
-       const struct device *_dev, const char *fmt, ...) {return 0;}
- #endif
  static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
  {
        int result;
        dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
                __LINE__, dev->m_region->lpar_addr);
  
 -      result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
 +      result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
  
        if (result) {
                dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
@@@ -162,7 -155,7 +155,7 @@@ fail_add_hcd
  fail_ioremap:
        usb_put_hcd(hcd);
  fail_create_hcd:
 -      ps3_free_io_irq(virq);
 +      ps3_io_irq_destroy(virq);
  fail_irq:
        ps3_free_mmio_region(dev->m_region);
  fail_mmio:
@@@ -75,14 -75,6 +75,6 @@@ static const struct hc_driver ps3_ohci_
  #endif
  };
  
- /* redefine dev_dbg to do a syntax check */
- #if !defined(DEBUG)
- #undef dev_dbg
- static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
-       const struct device *_dev, const char *fmt, ...) {return 0;}
- #endif
  static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
  {
        int result;
        dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
                __LINE__, dev->m_region->lpar_addr);
  
 -      result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
 +      result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
  
        if (result) {
                dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
@@@ -165,7 -157,7 +157,7 @@@ fail_add_hcd
  fail_ioremap:
        usb_put_hcd(hcd);
  fail_create_hcd:
 -      ps3_free_io_irq(virq);
 +      ps3_io_irq_destroy(virq);
  fail_irq:
        ps3_free_mmio_region(dev->m_region);
  fail_mmio:
diff --combined drivers/video/ps3fb.c
@@@ -32,6 -32,8 +32,8 @@@
  #include <linux/ioctl.h>
  #include <linux/notifier.h>
  #include <linux/reboot.h>
+ #include <linux/kthread.h>
+ #include <linux/freezer.h>
  
  #include <asm/uaccess.h>
  #include <linux/fb.h>
@@@ -45,7 -47,7 +47,7 @@@
  #include <asm/ps3.h>
  
  #ifdef PS3FB_DEBUG
- #define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args)
+ #define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args)
  #else
  #define DPRINTK(fmt, args...)
  #endif
@@@ -129,7 -131,6 +131,6 @@@ struct ps3fb_priv 
        u64 context_handle, memory_handle;
        void *xdr_ea;
        struct gpu_driver_info *dinfo;
-       struct semaphore sem;
        u32 res_index;
  
        u64 vblank_count;       /* frame count */
        atomic_t ext_flip;      /* on/off flip with vsync */
        atomic_t f_count;       /* fb_open count */
        int is_blanked;
+       int is_kicked;
+       struct task_struct *task;
  };
  static struct ps3fb_priv ps3fb;
  
@@@ -294,10 -297,10 +297,10 @@@ static const struct fb_videomode ps3fb_
  #define VP_OFF(i)     (WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP)
  #define FB_OFF(i)     (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
  
- static int ps3fb_mode = 0;
+ static int ps3fb_mode;
  module_param(ps3fb_mode, bool, 0);
  
- static char *mode_option __initdata = NULL;
+ static char *mode_option __initdata;
  
  
  static int ps3fb_get_res_table(u32 xres, u32 yres)
@@@ -393,7 -396,7 +396,7 @@@ static int ps3fb_sync(u32 frame
  
        if (frame > ps3fb.num_frames - 1) {
                printk(KERN_WARNING "%s: invalid frame number (%u)\n",
-                      __FUNCTION__, frame);
+                      __func__, frame);
                return -EINVAL;
        }
        offset = xres * yres * BPP * frame;
                                           (xres << 16) | yres,
                                           xres * BPP); /* line_length */
        if (status)
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
-                      __FUNCTION__, status);
+               printk(KERN_ERR
+                      "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
+                      __func__, status);
  #ifdef HEAD_A
        status = lv1_gpu_context_attribute(ps3fb.context_handle,
                                           L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
                                           0, offset, 0, 0);
        if (status)
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
-                      __FUNCTION__, status);
+               printk(KERN_ERR
+                      "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+                      __func__, status);
  #endif
  #ifdef HEAD_B
        status = lv1_gpu_context_attribute(ps3fb.context_handle,
                                           L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
                                           1, offset, 0, 0);
        if (status)
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
-                      __FUNCTION__, status);
+               printk(KERN_ERR
+                      "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+                      __func__, status);
  #endif
        return 0;
  }
@@@ -631,7 -637,7 +637,7 @@@ static int ps3fb_blank(int blank, struc
  {
        int retval;
  
-       DPRINTK("%s: blank:%d\n", __FUNCTION__, blank);
+       DPRINTK("%s: blank:%d\n", __func__, blank);
        switch (blank) {
        case FB_BLANK_POWERDOWN:
        case FB_BLANK_HSYNC_SUSPEND:
@@@ -677,13 -683,10 +683,10 @@@ EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync)
  
  void ps3fb_flip_ctl(int on)
  {
-       if (on) {
-               if (atomic_read(&ps3fb.ext_flip) > 0) {
-                       atomic_dec(&ps3fb.ext_flip);
-               }
-       } else {
+       if (on)
+               atomic_dec_if_positive(&ps3fb.ext_flip);
+       else
                atomic_inc(&ps3fb.ext_flip);
-       }
  }
  
  EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
@@@ -732,6 -735,11 +735,11 @@@ static int ps3fb_ioctl(struct fb_info *
                        if (copy_from_user(&val, argp, sizeof(val)))
                                break;
  
+                       if (!(val & PS3AV_MODE_MASK)) {
+                               u32 id = ps3av_get_auto_mode(0);
+                               if (id > 0)
+                                       val = (val & ~PS3AV_MODE_MASK) | id;
+                       }
                        DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val);
                        retval = -EINVAL;
                        old_mode = ps3fb_mode;
  
        case PS3FB_IOCTL_OFF:
                DPRINTK("PS3FB_IOCTL_OFF:\n");
-               if (atomic_read(&ps3fb.ext_flip) > 0)
-                       atomic_dec(&ps3fb.ext_flip);
+               atomic_dec_if_positive(&ps3fb.ext_flip);
                retval = 0;
                break;
  
  
  static int ps3fbd(void *arg)
  {
-       daemonize("ps3fbd");
-       for (;;) {
-               down(&ps3fb.sem);
-               if (atomic_read(&ps3fb.ext_flip) == 0)
+       while (!kthread_should_stop()) {
+               try_to_freeze();
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (ps3fb.is_kicked) {
+                       ps3fb.is_kicked = 0;
                        ps3fb_sync(0);  /* single buffer */
+               }
+               schedule();
        }
        return 0;
  }
@@@ -823,15 -833,18 +833,18 @@@ static irqreturn_t ps3fb_vsync_interrup
        status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
        if (status) {
                printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n",
-                      __FUNCTION__, status);
+                      __func__, status);
                return IRQ_NONE;
        }
  
        if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) {
                /* VSYNC */
                ps3fb.vblank_count = head->vblank_count;
-               if (!ps3fb.is_blanked)
-                       up(&ps3fb.sem);
+               if (ps3fb.task && !ps3fb.is_blanked &&
+                   !atomic_read(&ps3fb.ext_flip)) {
+                       ps3fb.is_kicked = 1;
+                       wake_up_process(ps3fb.task);
+               }
                wake_up_interruptible(&ps3fb.wait_vsync);
        }
  
@@@ -879,16 -892,16 +892,16 @@@ static int ps3fb_vsync_settings(struct 
                dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
  
        if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
-               printk(KERN_ERR "%s: version_driver err:%x\n", __FUNCTION__,
+               printk(KERN_ERR "%s: version_driver err:%x\n", __func__,
                       dinfo->version_driver);
                return -EINVAL;
        }
  
        ps3fb.dev = dev;
 -      error = ps3_alloc_irq(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
 -                            &ps3fb.irq_no);
 +      error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
 +                                 &ps3fb.irq_no);
        if (error) {
-               printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __FUNCTION__,
+               printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __func__,
                       error);
                return error;
        }
        error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
                            "ps3fb vsync", ps3fb.dev);
        if (error) {
-               printk(KERN_ERR "%s: request_irq failed %d\n", __FUNCTION__,
+               printk(KERN_ERR "%s: request_irq failed %d\n", __func__,
                       error);
 -              ps3_free_irq(ps3fb.irq_no);
 +              ps3_irq_plug_destroy(ps3fb.irq_no);
                return error;
        }
  
@@@ -915,7 -928,7 +928,7 @@@ static int ps3fb_xdr_settings(u64 xdr_l
                                       xdr_lpar, ps3fb_videomemory.size, 0);
        if (status) {
                printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n",
-                      __FUNCTION__, status);
+                      __func__, status);
                return -ENXIO;
        }
        DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
                                           xdr_lpar, ps3fb_videomemory.size,
                                           GPU_IOIF, 0);
        if (status) {
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
-                      __FUNCTION__, status);
+               printk(KERN_ERR
+                      "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
+                      __func__, status);
                return -ENXIO;
        }
        return 0;
@@@ -968,13 -982,14 +982,14 @@@ static int __init ps3fb_probe(struct pl
        u64 xdr_lpar;
        int status;
        unsigned long offset;
+       struct task_struct *task;
  
        /* get gpu context handle */
        status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
                                         &ps3fb.memory_handle, &ddr_lpar);
        if (status) {
                printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n",
-                      __FUNCTION__, status);
+                      __func__, status);
                goto err;
        }
        DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar);
                                          &lpar_reports, &lpar_reports_size);
        if (status) {
                printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n",
-                      __FUNCTION__, status);
+                      __func__, status);
                goto err_gpu_memory_free;
        }
  
        /* vsync interrupt */
        ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
        if (!ps3fb.dinfo) {
-               printk(KERN_ERR "%s: ioremap failed\n", __FUNCTION__);
+               printk(KERN_ERR "%s: ioremap failed\n", __func__);
                goto err_gpu_context_free;
        }
  
               "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
               info->node, ps3fb_videomemory.size >> 10);
  
-       kernel_thread(ps3fbd, info, CLONE_KERNEL);
+       task = kthread_run(ps3fbd, info, "ps3fbd");
+       if (IS_ERR(task)) {
+               retval = PTR_ERR(task);
+               goto err_unregister_framebuffer;
+       }
+       ps3fb.task = task;
        return 0;
  
+ err_unregister_framebuffer:
+       unregister_framebuffer(info);
  err_fb_dealloc:
        fb_dealloc_cmap(&info->cmap);
  err_framebuffer_release:
        framebuffer_release(info);
  err_free_irq:
        free_irq(ps3fb.irq_no, ps3fb.dev);
 -      ps3_free_irq(ps3fb.irq_no);
 +      ps3_irq_plug_destroy(ps3fb.irq_no);
  err_iounmap_dinfo:
        iounmap((u8 __iomem *)ps3fb.dinfo);
  err_gpu_context_free:
@@@ -1075,7 -1099,7 +1099,7 @@@ static void ps3fb_shutdown(struct platf
        ps3fb_flip_ctl(0);      /* flip off */
        ps3fb.dinfo->irq.mask = 0;
        free_irq(ps3fb.irq_no, ps3fb.dev);
 -      ps3_free_irq(ps3fb.irq_no);
 +      ps3_irq_plug_destroy(ps3fb.irq_no);
        iounmap((u8 __iomem *)ps3fb.dinfo);
  }
  
@@@ -1083,9 -1107,14 +1107,14 @@@ void ps3fb_cleanup(void
  {
        int status;
  
+       if (ps3fb.task) {
+               struct task_struct *task = ps3fb.task;
+               ps3fb.task = NULL;
+               kthread_stop(task);
+       }
        if (ps3fb.irq_no) {
                free_irq(ps3fb.irq_no, ps3fb.dev);
 -              ps3_free_irq(ps3fb.irq_no);
 +              ps3_irq_plug_destroy(ps3fb.irq_no);
        }
        iounmap((u8 __iomem *)ps3fb.dinfo);
  
@@@ -1137,8 -1166,9 +1166,9 @@@ int ps3fb_set_sync(void
                                           L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
                                           0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
        if (status) {
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
-                      __FUNCTION__, status);
+               printk(KERN_ERR
+                      "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
+                      __func__, status);
                return -1;
        }
  #endif
                                           1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
  
        if (status) {
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
-                      __FUNCTION__, status);
+               printk(KERN_ERR
+                      "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
+                      __func__, status);
                return -1;
        }
  #endif
@@@ -1174,7 -1205,7 +1205,7 @@@ static int __init ps3fb_init(void
  
        error = ps3av_dev_open();
        if (error) {
-               printk(KERN_ERR "%s: ps3av_dev_open failed\n", __FUNCTION__);
+               printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__);
                goto err;
        }
  
  
        atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
        atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
-       init_MUTEX(&ps3fb.sem);
        init_waitqueue_head(&ps3fb.wait_vsync);
        ps3fb.num_frames = 1;
  
diff --combined include/linux/suspend.h
@@@ -1,13 -1,14 +1,14 @@@
  #ifndef _LINUX_SWSUSP_H
  #define _LINUX_SWSUSP_H
  
 -#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32)
 +#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
  #include <asm/suspend.h>
  #endif
  #include <linux/swap.h>
  #include <linux/notifier.h>
  #include <linux/init.h>
  #include <linux/pm.h>
+ #include <linux/mm.h>
  
  /* struct pbe is used for creating lists of pages that should be restored
   * atomically during the resume from disk, because the page frames they have
@@@ -23,36 -24,32 +24,32 @@@ struct pbe 
  extern void drain_local_pages(void);
  extern void mark_free_pages(struct zone *zone);
  
- #ifdef CONFIG_PM
- /* kernel/power/swsusp.c */
- extern int software_suspend(void);
- #if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
+ #if defined(CONFIG_PM) && defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
  extern int pm_prepare_console(void);
  extern void pm_restore_console(void);
  #else
  static inline int pm_prepare_console(void) { return 0; }
  static inline void pm_restore_console(void) {}
- #endif /* defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) */
+ #endif
+ #if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
+ /* kernel/power/snapshot.c */
+ extern void __init register_nosave_region(unsigned long, unsigned long);
+ extern int swsusp_page_is_forbidden(struct page *);
+ extern void swsusp_set_page_free(struct page *);
+ extern void swsusp_unset_page_free(struct page *);
+ extern unsigned long get_safe_page(gfp_t gfp_mask);
  #else
- static inline int software_suspend(void)
- {
-       printk("Warning: fake suspend called\n");
-       return -ENOSYS;
- }
- #endif /* CONFIG_PM */
+ static inline void register_nosave_region(unsigned long b, unsigned long e) {}
+ static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
+ static inline void swsusp_set_page_free(struct page *p) {}
+ static inline void swsusp_unset_page_free(struct page *p) {}
+ #endif /* defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND) */
  
  void save_processor_state(void);
  void restore_processor_state(void);
  struct saved_context;
  void __save_processor_state(struct saved_context *ctxt);
  void __restore_processor_state(struct saved_context *ctxt);
- unsigned long get_safe_page(gfp_t gfp_mask);
- /*
-  * XXX: We try to keep some more pages free so that I/O operations succeed
-  * without paging. Might this be more?
-  */
- #define PAGES_FOR_IO  1024
  
  #endif /* _LINUX_SWSUSP_H */
diff --combined kernel/power/Kconfig
@@@ -78,17 -78,22 +78,22 @@@ config PM_SYSFS_DEPRECATE
          are likely to be bus or driver specific.
  
  config SOFTWARE_SUSPEND
-       bool "Software Suspend"
+       bool "Software Suspend (Hibernation)"
 -      depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
 +      depends on PM && SWAP && (((X86 || PPC64_SWSUSP) && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
        ---help---
-         Enable the suspend to disk (STD) functionality.
+         Enable the suspend to disk (STD) functionality, which is usually
+         called "hibernation" in user interfaces.  STD checkpoints the
+         system and powers it off; and restores that checkpoint on reboot.
  
          You can suspend your machine with 'echo disk > /sys/power/state'.
          Alternatively, you can use the additional userland tools available
          from <http://suspend.sf.net>.
  
          In principle it does not require ACPI or APM, although for example
-         ACPI will be used if available.
+         ACPI will be used for the final steps when it is available.  One
+         of the reasons to use software suspend is that the firmware hooks
+         for suspend states like suspend-to-RAM (STR) often don't work very
+         well with Linux.
  
          It creates an image which is saved in your active swap. Upon the next
          boot, pass the 'resume=/dev/swappartition' argument to the kernel to
@@@ -134,7 -139,7 +139,7 @@@ config PM_STD_PARTITIO
  
  config SUSPEND_SMP
        bool
 -      depends on HOTPLUG_CPU && X86 && PM
 +      depends on HOTPLUG_CPU && (X86 || PPC64) && PM
        default y
  
  config APM_EMULATION