diff options
Diffstat (limited to 'drivers/hwmon/hwmon.c')
| -rw-r--r-- | drivers/hwmon/hwmon.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index dddd3eb9b387..106fa01cdb60 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/idr.h> | 17 | #include <linux/idr.h> |
| 18 | #include <linux/hwmon.h> | 18 | #include <linux/hwmon.h> |
| 19 | #include <linux/gfp.h> | 19 | #include <linux/gfp.h> |
| 20 | #include <linux/spinlock.h> | ||
| 20 | 21 | ||
| 21 | #define HWMON_ID_PREFIX "hwmon" | 22 | #define HWMON_ID_PREFIX "hwmon" |
| 22 | #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" | 23 | #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" |
| @@ -24,6 +25,7 @@ | |||
| 24 | static struct class *hwmon_class; | 25 | static struct class *hwmon_class; |
| 25 | 26 | ||
| 26 | static DEFINE_IDR(hwmon_idr); | 27 | static DEFINE_IDR(hwmon_idr); |
| 28 | static DEFINE_SPINLOCK(idr_lock); | ||
| 27 | 29 | ||
| 28 | /** | 30 | /** |
| 29 | * hwmon_device_register - register w/ hwmon sysfs class | 31 | * hwmon_device_register - register w/ hwmon sysfs class |
| @@ -37,20 +39,30 @@ static DEFINE_IDR(hwmon_idr); | |||
| 37 | struct class_device *hwmon_device_register(struct device *dev) | 39 | struct class_device *hwmon_device_register(struct device *dev) |
| 38 | { | 40 | { |
| 39 | struct class_device *cdev; | 41 | struct class_device *cdev; |
| 40 | int id; | 42 | int id, err; |
| 41 | 43 | ||
| 42 | if (idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0) | 44 | again: |
| 45 | if (unlikely(idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0)) | ||
| 43 | return ERR_PTR(-ENOMEM); | 46 | return ERR_PTR(-ENOMEM); |
| 44 | 47 | ||
| 45 | if (idr_get_new(&hwmon_idr, NULL, &id) < 0) | 48 | spin_lock(&idr_lock); |
| 46 | return ERR_PTR(-ENOMEM); | 49 | err = idr_get_new(&hwmon_idr, NULL, &id); |
| 50 | spin_unlock(&idr_lock); | ||
| 51 | |||
| 52 | if (unlikely(err == -EAGAIN)) | ||
| 53 | goto again; | ||
| 54 | else if (unlikely(err)) | ||
| 55 | return ERR_PTR(err); | ||
| 47 | 56 | ||
| 48 | id = id & MAX_ID_MASK; | 57 | id = id & MAX_ID_MASK; |
| 49 | cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev, | 58 | cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev, |
| 50 | HWMON_ID_FORMAT, id); | 59 | HWMON_ID_FORMAT, id); |
| 51 | 60 | ||
| 52 | if (IS_ERR(cdev)) | 61 | if (IS_ERR(cdev)) { |
| 62 | spin_lock(&idr_lock); | ||
| 53 | idr_remove(&hwmon_idr, id); | 63 | idr_remove(&hwmon_idr, id); |
| 64 | spin_unlock(&idr_lock); | ||
| 65 | } | ||
| 54 | 66 | ||
| 55 | return cdev; | 67 | return cdev; |
| 56 | } | 68 | } |
| @@ -64,9 +76,11 @@ void hwmon_device_unregister(struct class_device *cdev) | |||
| 64 | { | 76 | { |
| 65 | int id; | 77 | int id; |
| 66 | 78 | ||
| 67 | if (sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1) { | 79 | if (likely(sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1)) { |
| 68 | class_device_unregister(cdev); | 80 | class_device_unregister(cdev); |
| 81 | spin_lock(&idr_lock); | ||
| 69 | idr_remove(&hwmon_idr, id); | 82 | idr_remove(&hwmon_idr, id); |
| 83 | spin_unlock(&idr_lock); | ||
| 70 | } else | 84 | } else |
| 71 | dev_dbg(cdev->dev, | 85 | dev_dbg(cdev->dev, |
| 72 | "hwmon_device_unregister() failed: bad class ID!\n"); | 86 | "hwmon_device_unregister() failed: bad class ID!\n"); |
