Commit 7e298750 authored by Steve French's avatar Steve French
parents b1a45695 49a43876
...@@ -7,7 +7,6 @@ that support it. For example, a given bus might look like this: ...@@ -7,7 +7,6 @@ that support it. For example, a given bus might look like this:
|-- 0000:17:00.0 |-- 0000:17:00.0
| |-- class | |-- class
| |-- config | |-- config
| |-- detach_state
| |-- device | |-- device
| |-- irq | |-- irq
| |-- local_cpus | |-- local_cpus
...@@ -19,7 +18,7 @@ that support it. For example, a given bus might look like this: ...@@ -19,7 +18,7 @@ that support it. For example, a given bus might look like this:
| |-- subsystem_device | |-- subsystem_device
| |-- subsystem_vendor | |-- subsystem_vendor
| `-- vendor | `-- vendor
`-- detach_state `-- ...
The topmost element describes the PCI domain and bus number. In this case, The topmost element describes the PCI domain and bus number. In this case,
the domain number is 0000 and the bus number is 17 (both values are in hex). the domain number is 0000 and the bus number is 17 (both values are in hex).
...@@ -31,7 +30,6 @@ files, each with their own function. ...@@ -31,7 +30,6 @@ files, each with their own function.
---- -------- ---- --------
class PCI class (ascii, ro) class PCI class (ascii, ro)
config PCI config space (binary, rw) config PCI config space (binary, rw)
detach_state connection status (bool, rw)
device PCI device (ascii, ro) device PCI device (ascii, ro)
irq IRQ number (ascii, ro) irq IRQ number (ascii, ro)
local_cpus nearby CPU mask (cpumask, ro) local_cpus nearby CPU mask (cpumask, ro)
......
...@@ -207,27 +207,6 @@ SYSTEM_SHUTDOWN, I do not understand this one too much. probably event ...@@ -207,27 +207,6 @@ SYSTEM_SHUTDOWN, I do not understand this one too much. probably event
#READY_AFTER_RESUME #READY_AFTER_RESUME
# #
Driver Detach Power Management
The kernel now supports the ability to place a device in a low-power
state when it is detached from its driver, which happens when its
module is removed.
Each device contains a 'detach_state' file in its sysfs directory
which can be used to control this state. Reading from this file
displays what the current detach state is set to. This is 0 (On) by
default. A user may write a positive integer value to this file in the
range of 1-4 inclusive.
A value of 1-3 will indicate the device should be placed in that
low-power state, which will cause ->suspend() to be called for that
device. A value of 4 indicates that the device should be shutdown, so
->shutdown() will be called for that device.
The driver is responsible for reinitializing the device when the
module is re-inserted during it's ->probe() (or equivalent) method.
The driver core will not call any extra functions when binding the
device to the driver.
pm_message_t meaning pm_message_t meaning
......
...@@ -348,7 +348,7 @@ looks like the following: ...@@ -348,7 +348,7 @@ looks like the following:
Pow5:/sys/bus/vio/drivers/hvcs/30000004 # ls Pow5:/sys/bus/vio/drivers/hvcs/30000004 # ls
. current_vty devspec name partner_vtys . current_vty devspec name partner_vtys
.. detach_state index partner_clcs vterm_state .. index partner_clcs vterm_state
Each entry is provided, by default with a "name" attribute. Reading the Each entry is provided, by default with a "name" attribute. Reading the
"name" attribute will reveal the device type as shown in the following "name" attribute will reveal the device type as shown in the following
......
# Makefile for the Linux device tree # Makefile for the Linux device tree
obj-y := core.o sys.o interface.o bus.o \ obj-y := core.o sys.o bus.o \
driver.o class.o class_simple.o platform.o \ driver.o class.o class_simple.o platform.o \
cpu.o firmware.o init.o map.o dmapool.o \ cpu.o firmware.o init.o map.o dmapool.o \
attribute_container.o transport_class.o attribute_container.o transport_class.o
......
...@@ -390,7 +390,6 @@ void device_release_driver(struct device * dev) ...@@ -390,7 +390,6 @@ void device_release_driver(struct device * dev)
sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
sysfs_remove_link(&dev->kobj, "driver"); sysfs_remove_link(&dev->kobj, "driver");
list_del_init(&dev->driver_list); list_del_init(&dev->driver_list);
device_detach_shutdown(dev);
if (drv->remove) if (drv->remove)
drv->remove(dev); drv->remove(dev);
dev->driver = NULL; dev->driver = NULL;
......
...@@ -31,8 +31,6 @@ int (*platform_notify_remove)(struct device * dev) = NULL; ...@@ -31,8 +31,6 @@ int (*platform_notify_remove)(struct device * dev) = NULL;
#define to_dev(obj) container_of(obj, struct device, kobj) #define to_dev(obj) container_of(obj, struct device, kobj)
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
extern struct attribute * dev_default_attrs[];
static ssize_t static ssize_t
dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{ {
...@@ -89,7 +87,6 @@ static void device_release(struct kobject * kobj) ...@@ -89,7 +87,6 @@ static void device_release(struct kobject * kobj)
static struct kobj_type ktype_device = { static struct kobj_type ktype_device = {
.release = device_release, .release = device_release,
.sysfs_ops = &dev_sysfs_ops, .sysfs_ops = &dev_sysfs_ops,
.default_attrs = dev_default_attrs,
}; };
......
/*
* drivers/base/interface.c - common driverfs interface that's exported to
* the world for all devices.
*
* Copyright (c) 2002-3 Patrick Mochel
* Copyright (c) 2002-3 Open Source Development Labs
*
* This file is released under the GPLv2
*
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/stat.h>
#include <linux/string.h>
/**
* detach_state - control the default power state for the device.
*
* This is the state the device enters when it's driver module is
* unloaded. The value is an unsigned integer, in the range of 0-4.
* '0' indicates 'On', so no action will be taken when the driver is
* unloaded. This is the default behavior.
* '4' indicates 'Off', meaning the driver core will call the driver's
* shutdown method to quiesce the device.
* 1-3 indicate a low-power state for the device to enter via the
* driver's suspend method.
*/
static ssize_t detach_show(struct device * dev, char * buf)
{
return sprintf(buf, "%u\n", dev->detach_state);
}
static ssize_t detach_store(struct device * dev, const char * buf, size_t n)
{
u32 state;
state = simple_strtoul(buf, NULL, 10);
if (state > 4)
return -EINVAL;
dev->detach_state = state;
return n;
}
static DEVICE_ATTR(detach_state, 0644, detach_show, detach_store);
struct attribute * dev_default_attrs[] = {
&dev_attr_detach_state.attr,
NULL,
};
enum {
DEVICE_PM_ON,
DEVICE_PM1,
DEVICE_PM2,
DEVICE_PM3,
DEVICE_PM_OFF,
};
/* /*
* shutdown.c * shutdown.c
*/ */
extern int device_detach_shutdown(struct device *);
extern void device_shutdown(void); extern void device_shutdown(void);
......
...@@ -22,8 +22,17 @@ extern int sysdev_resume(void); ...@@ -22,8 +22,17 @@ extern int sysdev_resume(void);
int resume_device(struct device * dev) int resume_device(struct device * dev)
{ {
if (dev->bus && dev->bus->resume) if (dev->power.pm_parent
&& dev->power.pm_parent->power.power_state) {
dev_err(dev, "PM: resume from %d, parent %s still %d\n",
dev->power.power_state,
dev->power.pm_parent->bus_id,
dev->power.pm_parent->power.power_state);
}
if (dev->bus && dev->bus->resume) {
dev_dbg(dev,"resuming\n");
return dev->bus->resume(dev); return dev->bus->resume(dev);
}
return 0; return 0;
} }
......
...@@ -19,20 +19,6 @@ ...@@ -19,20 +19,6 @@
extern struct subsystem devices_subsys; extern struct subsystem devices_subsys;
int device_detach_shutdown(struct device * dev)
{
if (!dev->detach_state)
return 0;
if (dev->detach_state == DEVICE_PM_OFF) {
if (dev->driver && dev->driver->shutdown)
dev->driver->shutdown(dev);
return 0;
}
return dpm_runtime_suspend(dev, dev->detach_state);
}
/** /**
* We handle system devices differently - we suspend and shut them * We handle system devices differently - we suspend and shut them
* down last and resume them first. That way, we don't do anything stupid like * down last and resume them first. That way, we don't do anything stupid like
...@@ -52,13 +38,12 @@ void device_shutdown(void) ...@@ -52,13 +38,12 @@ void device_shutdown(void)
struct device * dev; struct device * dev;
down_write(&devices_subsys.rwsem); down_write(&devices_subsys.rwsem);
list_for_each_entry_reverse(dev, &devices_subsys.kset.list, kobj.entry) { list_for_each_entry_reverse(dev, &devices_subsys.kset.list,
pr_debug("shutting down %s: ", dev->bus_id); kobj.entry) {
if (dev->driver && dev->driver->shutdown) { if (dev->driver && dev->driver->shutdown) {
pr_debug("Ok\n"); dev_dbg(dev, "shutdown\n");
dev->driver->shutdown(dev); dev->driver->shutdown(dev);
} else }
pr_debug("Ignored.\n");
} }
up_write(&devices_subsys.rwsem); up_write(&devices_subsys.rwsem);
......
...@@ -39,12 +39,25 @@ int suspend_device(struct device * dev, pm_message_t state) ...@@ -39,12 +39,25 @@ int suspend_device(struct device * dev, pm_message_t state)
{ {
int error = 0; int error = 0;
dev_dbg(dev, "suspending\n"); if (dev->power.power_state) {
dev_dbg(dev, "PM: suspend %d-->%d\n",
dev->power.power_state, state);
}
if (dev->power.pm_parent
&& dev->power.pm_parent->power.power_state) {
dev_err(dev,
"PM: suspend %d->%d, parent %s already %d\n",
dev->power.power_state, state,
dev->power.pm_parent->bus_id,
dev->power.pm_parent->power.power_state);
}
dev->power.prev_state = dev->power.power_state; dev->power.prev_state = dev->power.power_state;
if (dev->bus && dev->bus->suspend && !dev->power.power_state) if (dev->bus && dev->bus->suspend && !dev->power.power_state) {
dev_dbg(dev, "suspending\n");
error = dev->bus->suspend(dev, state); error = dev->bus->suspend(dev, state);
}
return error; return error;
} }
......
...@@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp, ...@@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp,
{ {
struct block_device *bdev = filp->private_data; struct block_device *bdev = filp->private_data;
return blkdev_ioctl(bdev->bd_inode, filp, command, arg); return blkdev_ioctl(bdev->bd_inode, NULL, command, arg);
} }
static void bind_device(struct raw_config_request *rq) static void bind_device(struct raw_config_request *rq)
......
...@@ -52,116 +52,17 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp, ...@@ -52,116 +52,17 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp,
if ((buffer_size - length <= 0) || (i >= num_envp)) if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM; return -ENOMEM;
envp[i] = NULL; envp[i++] = scratch;
length += scnprintf (scratch, buffer_size - length,
return 0; "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n",
} pdev->vendor, pdev->device,
pdev->subsystem_vendor, pdev->subsystem_device,
static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent) (u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
{ (u8)(pdev->class));
struct list_head *ln; if ((buffer_size - length <= 0) || (i >= num_envp))
struct pci_dev *dev; return -ENOMEM;
struct pci_dev_wrapped wrapped_dev;
int result = 0;
pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(wrapped_bus->bus),
wrapped_bus->bus->number);
if (fn->pre_visit_pci_bus) {
result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent);
if (result)
return result;
}
ln = wrapped_bus->bus->devices.next;
while (ln != &wrapped_bus->bus->devices) {
dev = pci_dev_b(ln);
ln = ln->next;
memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
wrapped_dev.dev = dev;
result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus);
if (result)
return result;
}
if (fn->post_visit_pci_bus)
result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent);
return result;
}
static int pci_visit_bridge (struct pci_visit * fn,
struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent)
{
struct pci_bus *bus;
struct pci_bus_wrapped wrapped_bus;
int result = 0;
pr_debug("PCI: Scanning bridge %s\n", pci_name(wrapped_dev->dev));
if (fn->visit_pci_dev) {
result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
if (result)
return result;
}
bus = wrapped_dev->dev->subordinate;
if (bus) {
memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
wrapped_bus.bus = bus;
result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
}
return result;
}
/** envp[i] = NULL;
* pci_visit_dev - scans the pci buses.
* @fn: callback functions that are called while visiting
* @wrapped_dev: the device to scan
* @wrapped_parent: the bus where @wrapped_dev is connected to
*
* Every bus and every function is presented to a custom
* function that can act upon it.
*/
int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent)
{
struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL;
int result = 0;
if (!dev)
return 0; return 0;
if (fn->pre_visit_pci_dev) {
result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent);
if (result)
return result;
}
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
result = pci_visit_bridge(fn, wrapped_dev,
wrapped_parent);
if (result)
return result;
break;
default:
pr_debug("PCI: Scanning device %s\n", pci_name(dev));
if (fn->visit_pci_dev) {
result = fn->visit_pci_dev (wrapped_dev,
wrapped_parent);
if (result)
return result;
}
}
if (fn->post_visit_pci_dev)
result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent);
return result;
} }
EXPORT_SYMBOL(pci_visit_dev);
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pci.h> #include <linux/pci.h>
/* PICMG 2.12 R2.0 HS CSR bits: */ /* PICMG 2.1 R2.0 HS CSR bits: */
#define HS_CSR_INS 0x0080 #define HS_CSR_INS 0x0080
#define HS_CSR_EXT 0x0040 #define HS_CSR_EXT 0x0040
#define HS_CSR_PI 0x0030 #define HS_CSR_PI 0x0030
......
...@@ -33,11 +33,11 @@ ...@@ -33,11 +33,11 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <asm/atomic.h>
#include <linux/delay.h> #include <linux/delay.h>
#include "pci_hotplug.h" #include "pci_hotplug.h"
#include "cpci_hotplug.h" #include "cpci_hotplug.h"
#define DRIVER_VERSION "0.2"
#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" #define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
#define DRIVER_DESC "CompactPCI Hot Plug Core" #define DRIVER_DESC "CompactPCI Hot Plug Core"
...@@ -54,9 +54,10 @@ ...@@ -54,9 +54,10 @@
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
/* local variables */ /* local variables */
static spinlock_t list_lock; static DECLARE_RWSEM(list_rwsem);
static LIST_HEAD(slot_list); static LIST_HEAD(slot_list);
static int slots; static int slots;
static atomic_t extracting;
int cpci_debug; int cpci_debug;
static struct cpci_hp_controller *controller; static struct cpci_hp_controller *controller;
static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
...@@ -68,6 +69,8 @@ static int disable_slot(struct hotplug_slot *slot); ...@@ -68,6 +69,8 @@ static int disable_slot(struct hotplug_slot *slot);
static int set_attention_status(struct hotplug_slot *slot, u8 value); static int set_attention_status(struct hotplug_slot *slot, u8 value);
static int get_power_status(struct hotplug_slot *slot, u8 * value); static int get_power_status(struct hotplug_slot *slot, u8 * value);
static int get_attention_status(struct hotplug_slot *slot, u8 * value); static int get_attention_status(struct hotplug_slot *slot, u8 * value);
static int get_adapter_status(struct hotplug_slot *slot, u8 * value);
static int get_latch_status(struct hotplug_slot *slot, u8 * value);
static struct hotplug_slot_ops cpci_hotplug_slot_ops = { static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -76,6 +79,8 @@ static struct hotplug_slot_ops cpci_hotplug_slot_ops = { ...@@ -76,6 +79,8 @@ static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
.set_attention_status = set_attention_status, .set_attention_status = set_attention_status,
.get_power_status = get_power_status, .get_power_status = get_power_status,
.get_attention_status = get_attention_status, .get_attention_status = get_attention_status,
.get_adapter_status = get_adapter_status,
.get_latch_status = get_latch_status,
}; };
static int static int
...@@ -148,8 +153,10 @@ disable_slot(struct hotplug_slot *hotplug_slot) ...@@ -148,8 +153,10 @@ disable_slot(struct hotplug_slot *hotplug_slot)
warn("failure to update adapter file"); warn("failure to update adapter file");
} }
if(slot->extracting) {
slot->extracting = 0; slot->extracting = 0;
atomic_dec(&extracting);
}
return retval; return retval;
} }
...@@ -188,6 +195,20 @@ set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) ...@@ -188,6 +195,20 @@ set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
return cpci_set_attention_status(hotplug_slot->private, status); return cpci_set_attention_status(hotplug_slot->private, status);
} }
static int
get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
{
*value = hotplug_slot->info->adapter_status;
return 0;
}
static int
get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value)
{
*value = hotplug_slot->info->latch_status;
return 0;
}
static void release_slot(struct hotplug_slot *hotplug_slot) static void release_slot(struct hotplug_slot *hotplug_slot)
{ {
struct slot *slot = hotplug_slot->private; struct slot *slot = hotplug_slot->private;
...@@ -273,10 +294,10 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) ...@@ -273,10 +294,10 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
} }
/* Add slot to our internal list */ /* Add slot to our internal list */
spin_lock(&list_lock); down_write(&list_rwsem);
list_add(&slot->slot_list, &slot_list); list_add(&slot->slot_list, &slot_list);
slots++; slots++;
spin_unlock(&list_lock); up_write(&list_rwsem);
} }
return 0; return 0;
error_name: error_name:
...@@ -299,9 +320,9 @@ cpci_hp_unregister_bus(struct pci_bus *bus) ...@@ -299,9 +320,9 @@ cpci_hp_unregister_bus(struct pci_bus *bus)
struct list_head *next; struct list_head *next;
int status; int status;
spin_lock(&list_lock); down_write(&list_rwsem);
if(!slots) { if(!slots) {
spin_unlock(&list_lock); up_write(&list_rwsem);
return -1; return -1;
} }
list_for_each_safe(tmp, next, &slot_list) { list_for_each_safe(tmp, next, &slot_list) {
...@@ -319,7 +340,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus) ...@@ -319,7 +340,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus)
slots--; slots--;
} }
} }
spin_unlock(&list_lock); up_write(&list_rwsem);
return 0; return 0;
} }
...@@ -347,7 +368,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs) ...@@ -347,7 +368,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
} }
/* /*
* According to PICMG 2.12 R2.0, section 6.3.2, upon * According to PICMG 2.1 R2.0, section 6.3.2, upon
* initialization, the system driver shall clear the * initialization, the system driver shall clear the
* INS bits of the cold-inserted devices. * INS bits of the cold-inserted devices.
*/ */
...@@ -359,9 +380,9 @@ init_slots(void) ...@@ -359,9 +380,9 @@ init_slots(void)
struct pci_dev* dev; struct pci_dev* dev;
dbg("%s - enter", __FUNCTION__); dbg("%s - enter", __FUNCTION__);
spin_lock(&list_lock); down_read(&list_rwsem);
if(!slots) { if(!slots) {
spin_unlock(&list_lock); up_read(&list_rwsem);
return -1; return -1;
} }
list_for_each(tmp, &slot_list) { list_for_each(tmp, &slot_list) {
...@@ -386,7 +407,7 @@ init_slots(void) ...@@ -386,7 +407,7 @@ init_slots(void)
} }
} }
} }
spin_unlock(&list_lock); up_read(&list_rwsem);
dbg("%s - exit", __FUNCTION__); dbg("%s - exit", __FUNCTION__);
return 0; return 0;
} }
...@@ -398,10 +419,11 @@ check_slots(void) ...@@ -398,10 +419,11 @@ check_slots(void)
struct list_head *tmp; struct list_head *tmp;
int extracted; int extracted;
int inserted; int inserted;
u16 hs_csr;
spin_lock(&list_lock); down_read(&list_rwsem);
if(!slots) { if(!slots) {
spin_unlock(&list_lock); up_read(&list_rwsem);
err("no slots registered, shutting down"); err("no slots registered, shutting down");
return -1; return -1;
} }
...@@ -411,8 +433,6 @@ check_slots(void) ...@@ -411,8 +433,6 @@ check_slots(void)
dbg("%s - looking at slot %s", dbg("%s - looking at slot %s",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
if(cpci_check_and_clear_ins(slot)) { if(cpci_check_and_clear_ins(slot)) {
u16 hs_csr;
/* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */ /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */
if(slot->dev) { if(slot->dev) {
warn("slot %s already inserted", slot->hotplug_slot->name); warn("slot %s already inserted", slot->hotplug_slot->name);
...@@ -462,8 +482,6 @@ check_slots(void) ...@@ -462,8 +482,6 @@ check_slots(void)
inserted++; inserted++;
} else if(cpci_check_ext(slot)) { } else if(cpci_check_ext(slot)) {
u16 hs_csr;
/* Process extraction request */ /* Process extraction request */
dbg("%s - slot %s extracted", dbg("%s - slot %s extracted",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
...@@ -476,20 +494,40 @@ check_slots(void) ...@@ -476,20 +494,40 @@ check_slots(void)
if(!slot->extracting) { if(!slot->extracting) {
if(update_latch_status(slot->hotplug_slot, 0)) { if(update_latch_status(slot->hotplug_slot, 0)) {
warn("failure to update latch file"); warn("failure to update latch file");
} }
atomic_inc(&extracting);
slot->extracting = 1; slot->extracting = 1;
} }
extracted++; extracted++;
} else if(slot->extracting) {
hs_csr = cpci_get_hs_csr(slot);
if(hs_csr == 0xffff) {
/*
* Hmmm, we're likely hosed at this point, should we
* bother trying to tell the driver or not?
*/
err("card in slot %s was improperly removed",
slot->hotplug_slot->name);
if(update_adapter_status(slot->hotplug_slot, 0)) {
warn("failure to update adapter file");
} }
slot->extracting = 0;
atomic_dec(&extracting);
} }
spin_unlock(&list_lock); }
}
up_read(&list_rwsem);
dbg("inserted=%d, extracted=%d, extracting=%d",
inserted, extracted, atomic_read(&extracting));
if(inserted || extracted) { if(inserted || extracted) {
return extracted; return extracted;
} }
else { else if(!atomic_read(&extracting)) {
err("cannot find ENUM# source, shutting down"); err("cannot find ENUM# source, shutting down");
return -1; return -1;
} }
return 0;
} }
/* This is the interrupt mode worker thread body */ /* This is the interrupt mode worker thread body */
...@@ -497,8 +535,6 @@ static int ...@@ -497,8 +535,6 @@ static int
event_thread(void *data) event_thread(void *data)
{ {
int rc; int rc;
struct slot *slot;
struct list_head *tmp;
lock_kernel(); lock_kernel();
daemonize("cpci_hp_eventd"); daemonize("cpci_hp_eventd");
...@@ -512,39 +548,22 @@ event_thread(void *data) ...@@ -512,39 +548,22 @@ event_thread(void *data)
thread_finished); thread_finished);
if(thread_finished || signal_pending(current)) if(thread_finished || signal_pending(current))
break; break;
while(controller->ops->query_enum()) { do {
rc = check_slots(); rc = check_slots();
if (rc > 0) if (rc > 0) {
/* Give userspace a chance to handle extraction */ /* Give userspace a chance to handle extraction */
msleep(500); msleep(500);
else if (rc < 0) { } else if (rc < 0) {
dbg("%s - error checking slots", __FUNCTION__); dbg("%s - error checking slots", __FUNCTION__);
thread_finished = 1; thread_finished = 1;
break; break;
} }
} } while(atomic_read(&extracting) != 0);
/* Check for someone yanking out a board */
list_for_each(tmp, &slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
if(slot->extracting) {
/*
* Hmmm, we're likely hosed at this point, should we
* bother trying to tell the driver or not?
*/
err("card in slot %s was improperly removed",
slot->hotplug_slot->name);
if(update_adapter_status(slot->hotplug_slot, 0)) {
warn("failure to update adapter file");
}
slot->extracting = 0;
}
}
/* Re-enable ENUM# interrupt */ /* Re-enable ENUM# interrupt */
dbg("%s - re-enabling irq", __FUNCTION__); dbg("%s - re-enabling irq", __FUNCTION__);
controller->ops->enable_irq(); controller->ops->enable_irq();
} }
dbg("%s - event thread signals exit", __FUNCTION__); dbg("%s - event thread signals exit", __FUNCTION__);
up(&thread_exit); up(&thread_exit);
return 0; return 0;
...@@ -555,8 +574,6 @@ static int ...@@ -555,8 +574,6 @@ static int
poll_thread(void *data) poll_thread(void *data)
{ {
int rc; int rc;
struct slot *slot;
struct list_head *tmp;
lock_kernel(); lock_kernel();
daemonize("cpci_hp_polld"); daemonize("cpci_hp_polld");
...@@ -565,35 +582,19 @@ poll_thread(void *data) ...@@ -565,35 +582,19 @@ poll_thread(void *data)
while(1) { while(1) {
if(thread_finished || signal_pending(current)) if(thread_finished || signal_pending(current))
break; break;
if(controller->ops->query_enum()) {
while(controller->ops->query_enum()) { do {
rc = check_slots(); rc = check_slots();
if(rc > 0) if(rc > 0) {
/* Give userspace a chance to handle extraction */ /* Give userspace a chance to handle extraction */
msleep(500); msleep(500);
else if (rc < 0) { } else if(rc < 0) {
dbg("%s - error checking slots", __FUNCTION__); dbg("%s - error checking slots", __FUNCTION__);
thread_finished = 1; thread_finished = 1;
break; break;
} }
} while(atomic_read(&extracting) != 0);
} }
/* Check for someone yanking out a board */
list_for_each(tmp, &slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
if(slot->extracting) {
/*
* Hmmm, we're likely hosed at this point, should we
* bother trying to tell the driver or not?
*/
err("card in slot %s was improperly removed",
slot->hotplug_slot->name);
if(update_adapter_status(slot->hotplug_slot, 0)) {
warn("failure to update adapter file");
}
slot->extracting = 0;
}
}
msleep(100); msleep(100);
} }
dbg("poll thread signals exit"); dbg("poll thread signals exit");
...@@ -667,6 +668,9 @@ cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) ...@@ -667,6 +668,9 @@ cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
int status = 0; int status = 0;
if(controller) { if(controller) {
if(atomic_read(&extracting) != 0) {
return -EBUSY;
}
if(!thread_finished) { if(!thread_finished) {
cpci_stop_thread(); cpci_stop_thread();
} }
...@@ -691,12 +695,12 @@ cpci_hp_start(void) ...@@ -691,12 +695,12 @@ cpci_hp_start(void)
return -ENODEV; return -ENODEV;
} }
spin_lock(&list_lock); down_read(&list_rwsem);
if(!slots) { if(list_empty(&slot_list)) {
spin_unlock(&list_lock); up_read(&list_rwsem);
return -ENODEV; return -ENODEV;
} }
spin_unlock(&list_lock); up_read(&list_rwsem);
if(first) { if(first) {
status = init_slots(); status = init_slots();
...@@ -727,7 +731,9 @@ cpci_hp_stop(void) ...@@ -727,7 +731,9 @@ cpci_hp_stop(void)
if(!controller) { if(!controller) {
return -ENODEV; return -ENODEV;
} }
if(atomic_read(&extracting) != 0) {
return -EBUSY;
}
if(controller->irq) { if(controller->irq) {
/* Stop enum interrupt processing */ /* Stop enum interrupt processing */
dbg("%s - disabling irq", __FUNCTION__); dbg("%s - disabling irq", __FUNCTION__);
...@@ -747,7 +753,7 @@ cleanup_slots(void) ...@@ -747,7 +753,7 @@ cleanup_slots(void)
* Unregister all of our slots with the pci_hotplug subsystem, * Unregister all of our slots with the pci_hotplug subsystem,
* and free up all memory that we had allocated. * and free up all memory that we had allocated.
*/ */
spin_lock(&list_lock); down_write(&list_rwsem);
if(!slots) { if(!slots) {
goto null_cleanup; goto null_cleanup;
} }
...@@ -761,17 +767,14 @@ cleanup_slots(void) ...@@ -761,17 +767,14 @@ cleanup_slots(void)
kfree(slot); kfree(slot);
} }
null_cleanup: null_cleanup:
spin_unlock(&list_lock); up_write(&list_rwsem);
return; return;
} }
int __init int __init
cpci_hotplug_init(int debug) cpci_hotplug_init(int debug)
{ {
spin_lock_init(&list_lock);
cpci_debug = debug; cpci_debug = debug;
info(DRIVER_DESC " version: " DRIVER_VERSION);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -130,6 +130,7 @@ struct controller { ...@@ -130,6 +130,7 @@ struct controller {
u8 slot_bus; /* Bus where the slots handled by this controller sit */ u8 slot_bus; /* Bus where the slots handled by this controller sit */
u8 ctrlcap; u8 ctrlcap;
u16 vendor_id; u16 vendor_id;
u8 cap_base;
}; };
struct irq_mapping { struct irq_mapping {
......
...@@ -607,7 +607,7 @@ static int pciehp_resume (struct pcie_device *dev) ...@@ -607,7 +607,7 @@ static int pciehp_resume (struct pcie_device *dev)
static struct pcie_port_service_id port_pci_ids[] = { { static struct pcie_port_service_id port_pci_ids[] = { {
.vendor = PCI_ANY_ID, .vendor = PCI_ANY_ID,
.device = PCI_ANY_ID, .device = PCI_ANY_ID,
.port_type = PCIE_RC_PORT, .port_type = PCIE_ANY_PORT,
.service_type = PCIE_PORT_SERVICE_HP, .service_type = PCIE_PORT_SERVICE_HP,
.driver_data = 0, .driver_data = 0,
}, { /* end: all zeroes */ } }, { /* end: all zeroes */ }
......
This diff is collapsed.
...@@ -95,7 +95,7 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = { ...@@ -95,7 +95,7 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
*/ */
static void release_slot(struct hotplug_slot *hotplug_slot) static void release_slot(struct hotplug_slot *hotplug_slot)
{ {
struct slot *slot = (struct slot *)hotplug_slot->private; struct slot *slot = hotplug_slot->private;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
......
...@@ -1885,7 +1885,7 @@ int shpchp_enable_slot (struct slot *p_slot) ...@@ -1885,7 +1885,7 @@ int shpchp_enable_slot (struct slot *p_slot)
func = shpchp_slot_find(p_slot->bus, p_slot->device, 0); func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
if (!func) { if (!func) {
dbg("%s: Error! slot NULL\n", __FUNCTION__); dbg("%s: Error! slot NULL\n", __FUNCTION__);
return 1; return -ENODEV;
} }
/* Check to see if (latch closed, card present, power off) */ /* Check to see if (latch closed, card present, power off) */
...@@ -1894,19 +1894,19 @@ int shpchp_enable_slot (struct slot *p_slot) ...@@ -1894,19 +1894,19 @@ int shpchp_enable_slot (struct slot *p_slot)
if (rc || !getstatus) { if (rc || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect); up(&p_slot->ctrl->crit_sect);
return 1; return -ENODEV;
} }
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) { if (rc || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect); up(&p_slot->ctrl->crit_sect);
return 1; return -ENODEV;
} }
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) { if (rc || getstatus) {
info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect); up(&p_slot->ctrl->crit_sect);
return 1; return -ENODEV;
} }
up(&p_slot->ctrl->crit_sect); up(&p_slot->ctrl->crit_sect);
...@@ -1914,7 +1914,7 @@ int shpchp_enable_slot (struct slot *p_slot) ...@@ -1914,7 +1914,7 @@ int shpchp_enable_slot (struct slot *p_slot)
func = shpchp_slot_create(p_slot->bus); func = shpchp_slot_create(p_slot->bus);
if (func == NULL) if (func == NULL)
return 1; return -ENOMEM;
func->bus = p_slot->bus; func->bus = p_slot->bus;
func->device = p_slot->device; func->device = p_slot->device;
...@@ -1939,7 +1939,7 @@ int shpchp_enable_slot (struct slot *p_slot) ...@@ -1939,7 +1939,7 @@ int shpchp_enable_slot (struct slot *p_slot)
/* Setup slot structure with entry for empty slot */ /* Setup slot structure with entry for empty slot */
func = shpchp_slot_create(p_slot->bus); func = shpchp_slot_create(p_slot->bus);
if (func == NULL) if (func == NULL)
return (1); /* Out of memory */ return -ENOMEM; /* Out of memory */
func->bus = p_slot->bus; func->bus = p_slot->bus;
func->device = p_slot->device; func->device = p_slot->device;
...@@ -1972,7 +1972,7 @@ int shpchp_disable_slot (struct slot *p_slot) ...@@ -1972,7 +1972,7 @@ int shpchp_disable_slot (struct slot *p_slot)
struct pci_func *func; struct pci_func *func;
if (!p_slot->ctrl) if (!p_slot->ctrl)
return 1; return -ENODEV;
pci_bus = p_slot->ctrl->pci_dev->subordinate; pci_bus = p_slot->ctrl->pci_dev->subordinate;
...@@ -1983,19 +1983,19 @@ int shpchp_disable_slot (struct slot *p_slot) ...@@ -1983,19 +1983,19 @@ int shpchp_disable_slot (struct slot *p_slot)
if (ret || !getstatus) { if (ret || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect); up(&p_slot->ctrl->crit_sect);
return 1; return -ENODEV;
} }
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) { if (ret || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect); up(&p_slot->ctrl->crit_sect);
return 1; return -ENODEV;
} }
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) { if (ret || !getstatus) {
info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
up(&p_slot->ctrl->crit_sect); up(&p_slot->ctrl->crit_sect);
return 1; return -ENODEV;
} }
up(&p_slot->ctrl->crit_sect); up(&p_slot->ctrl->crit_sect);
...@@ -2011,7 +2011,7 @@ int shpchp_disable_slot (struct slot *p_slot) ...@@ -2011,7 +2011,7 @@ int shpchp_disable_slot (struct slot *p_slot)
/* Check the Class Code */ /* Check the Class Code */
rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
if (rc) if (rc)
return rc; return -ENODEV;
if (class_code == PCI_BASE_CLASS_DISPLAY) { if (class_code == PCI_BASE_CLASS_DISPLAY) {
/* Display/Video adapter (not supported) */ /* Display/Video adapter (not supported) */
...@@ -2020,13 +2020,13 @@ int shpchp_disable_slot (struct slot *p_slot) ...@@ -2020,13 +2020,13 @@ int shpchp_disable_slot (struct slot *p_slot)
/* See if it's a bridge */ /* See if it's a bridge */
rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
if (rc) if (rc)
return rc; return -ENODEV;
/* If it's a bridge, check the VGA Enable bit */ /* If it's a bridge, check the VGA Enable bit */
if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
if (rc) if (rc)
return rc; return -ENODEV;
/* If the VGA Enable bit is set, remove isn't supported */ /* If the VGA Enable bit is set, remove isn't supported */
if (BCR & PCI_BRIDGE_CTL_VGA) { if (BCR & PCI_BRIDGE_CTL_VGA) {
...@@ -2042,12 +2042,12 @@ int shpchp_disable_slot (struct slot *p_slot) ...@@ -2042,12 +2042,12 @@ int shpchp_disable_slot (struct slot *p_slot)
if ((func != NULL) && !rc) { if ((func != NULL) && !rc) {
rc = remove_board(func, p_slot->ctrl); rc = remove_board(func, p_slot->ctrl);
} else if (!rc) } else if (!rc)
rc = 1; rc = -ENODEV;
if (p_slot) if (p_slot)
update_slot_info(p_slot); update_slot_info(p_slot);
return(rc); return rc;
} }
......
...@@ -73,6 +73,17 @@ resource_show(struct device * dev, char * buf) ...@@ -73,6 +73,17 @@ resource_show(struct device * dev, char * buf)
return (str - buf); return (str - buf);
} }
static ssize_t modalias_show(struct device *dev, char *buf)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n",
pci_dev->vendor, pci_dev->device,
pci_dev->subsystem_vendor, pci_dev->subsystem_device,
(u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8),
(u8)(pci_dev->class));
}
struct device_attribute pci_dev_attrs[] = { struct device_attribute pci_dev_attrs[] = {
__ATTR_RO(resource), __ATTR_RO(resource),
__ATTR_RO(vendor), __ATTR_RO(vendor),
...@@ -82,6 +93,7 @@ struct device_attribute pci_dev_attrs[] = { ...@@ -82,6 +93,7 @@ struct device_attribute pci_dev_attrs[] = {
__ATTR_RO(class), __ATTR_RO(class),
__ATTR_RO(irq), __ATTR_RO(irq),
__ATTR_RO(local_cpus), __ATTR_RO(local_cpus),
__ATTR_RO(modalias),
__ATTR_NULL, __ATTR_NULL,
}; };
......
...@@ -32,33 +32,6 @@ extern unsigned char pci_max_busnr(void); ...@@ -32,33 +32,6 @@ extern unsigned char pci_max_busnr(void);
extern unsigned char pci_bus_max_busnr(struct pci_bus *bus); extern unsigned char pci_bus_max_busnr(struct pci_bus *bus);
extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap); extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
struct pci_dev_wrapped {
struct pci_dev *dev;
void *data;
};
struct pci_bus_wrapped {
struct pci_bus *bus;
void *data;
};
struct pci_visit {
int (* pre_visit_pci_bus) (struct pci_bus_wrapped *,
struct pci_dev_wrapped *);
int (* post_visit_pci_bus) (struct pci_bus_wrapped *,
struct pci_dev_wrapped *);
int (* pre_visit_pci_dev) (struct pci_dev_wrapped *,
struct pci_bus_wrapped *);
int (* visit_pci_dev) (struct pci_dev_wrapped *,
struct pci_bus_wrapped *);
int (* post_visit_pci_dev) (struct pci_dev_wrapped *,
struct pci_bus_wrapped *);
};
extern int pci_visit_dev(struct pci_visit *fn,
struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent);
extern void pci_remove_legacy_files(struct pci_bus *bus); extern void pci_remove_legacy_files(struct pci_bus *bus);
/* Lock for read/write access to pci device and bus lists */ /* Lock for read/write access to pci device and bus lists */
......
...@@ -39,7 +39,8 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) ...@@ -39,7 +39,8 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
driver->id_table->vendor != pciedev->id.vendor) || driver->id_table->vendor != pciedev->id.vendor) ||
(driver->id_table->device != PCI_ANY_ID && (driver->id_table->device != PCI_ANY_ID &&
driver->id_table->device != pciedev->id.device) || driver->id_table->device != pciedev->id.device) ||
driver->id_table->port_type != pciedev->id.port_type || (driver->id_table->port_type != PCIE_ANY_PORT &&
driver->id_table->port_type != pciedev->id.port_type) ||
driver->id_table->service_type != pciedev->id.service_type ) driver->id_table->service_type != pciedev->id.service_type )
return 0; return 0;
......
...@@ -225,8 +225,16 @@ void __ext3_std_error (struct super_block * sb, const char * function, ...@@ -225,8 +225,16 @@ void __ext3_std_error (struct super_block * sb, const char * function,
int errno) int errno)
{ {
char nbuf[16]; char nbuf[16];
const char *errstr = ext3_decode_error(sb, errno, nbuf); const char *errstr;
/* Special case: if the error is EROFS, and we're not already
* inside a transaction, then there's really no point in logging
* an error. */
if (errno == -EROFS && journal_current_handle() == NULL &&
(sb->s_flags & MS_RDONLY))
return;
errstr = ext3_decode_error(sb, errno, nbuf);
printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n", printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n",
sb->s_id, function, errstr); sb->s_id, function, errstr);
......
...@@ -273,9 +273,6 @@ struct device { ...@@ -273,9 +273,6 @@ struct device {
BIOS data relevant to device) */ BIOS data relevant to device) */
struct dev_pm_info power; struct dev_pm_info power;
u32 detach_state; /* State to enter when device is
detached from its driver. */
u64 *dma_mask; /* dma mask (if dma'able device) */ u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as alloc_coherent mappings as
......
...@@ -156,14 +156,14 @@ static int enter_state(suspend_state_t state) ...@@ -156,14 +156,14 @@ static int enter_state(suspend_state_t state)
goto Unlock; goto Unlock;
} }
pr_debug("PM: Preparing system for suspend\n"); pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
if ((error = suspend_prepare(state))) if ((error = suspend_prepare(state)))
goto Unlock; goto Unlock;
pr_debug("PM: Entering state.\n"); pr_debug("PM: Entering %s sleep\n", pm_states[state]);
error = suspend_enter(state); error = suspend_enter(state);
pr_debug("PM: Finishing up.\n"); pr_debug("PM: Finishing wakeup.\n");
suspend_finish(state); suspend_finish(state);
Unlock: Unlock:
up(&pm_sem); up(&pm_sem);
......
...@@ -1244,7 +1244,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, ...@@ -1244,7 +1244,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
addr = mm->free_area_cache; addr = mm->free_area_cache;
/* make sure it can fit in the remaining address space */ /* make sure it can fit in the remaining address space */
if (addr >= len) { if (addr > len) {
vma = find_vma(mm, addr-len); vma = find_vma(mm, addr-len);
if (!vma || addr <= vma->vm_start) if (!vma || addr <= vma->vm_start)
/* remember the address as a hint for next time */ /* remember the address as a hint for next time */
...@@ -1266,7 +1266,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, ...@@ -1266,7 +1266,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
/* try just below the current vma->vm_start */ /* try just below the current vma->vm_start */
addr = vma->vm_start-len; addr = vma->vm_start-len;
} while (len <= vma->vm_start); } while (len < vma->vm_start);
/* /*
* A failed mmap() very likely causes application failure, * A failed mmap() very likely causes application failure,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment