diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 18:05:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 18:05:40 -0400 |
commit | a5e6b135bdff649e4330f98e2e80dbb1984f7e77 (patch) | |
tree | 475bfb1163c59d1370fd77415255afba768f9520 /drivers/base | |
parent | 971f115a50afbe409825c9f3399d5a3b9aca4381 (diff) | |
parent | 9d90c8d9cde929cbc575098e825d7c29d9f45054 (diff) |
Merge branch 'driver-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* 'driver-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (50 commits)
printk: do not mangle valid userspace syslog prefixes
efivars: Add Documentation
efivars: Expose efivars functionality to external drivers.
efivars: Parameterize operations.
efivars: Split out variable registration
efivars: parameterize efivars
efivars: Make efivars bin_attributes dynamic
efivars: move efivars globals into struct efivars
drivers:misc: ti-st: fix debugging code
kref: Fix typo in kref documentation
UIO: add PRUSS UIO driver support
Fix spelling mistakes in Documentation/zh_CN/SubmittingPatches
firmware: Fix unaligned memory accesses in dmi-sysfs
firmware: Add documentation for /sys/firmware/dmi
firmware: Expose DMI type 15 System Event Log
firmware: Break out system_event_log in dmi-sysfs
firmware: Basic dmi-sysfs support
firmware: Add DMI entry types to the headers
Driver core: convert platform_{get,set}_drvdata to static inline functions
Translate linux-2.6/Documentation/magic-number.txt into Chinese
...
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/core.c | 34 | ||||
-rw-r--r-- | drivers/base/firmware_class.c | 7 | ||||
-rw-r--r-- | drivers/base/memory.c | 197 | ||||
-rw-r--r-- | drivers/base/node.c | 12 | ||||
-rw-r--r-- | drivers/base/sys.c | 65 |
5 files changed, 232 insertions, 83 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 080e9ca11017..81b78ede37c4 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -1320,7 +1320,10 @@ struct root_device | |||
1320 | struct module *owner; | 1320 | struct module *owner; |
1321 | }; | 1321 | }; |
1322 | 1322 | ||
1323 | #define to_root_device(dev) container_of(dev, struct root_device, dev) | 1323 | inline struct root_device *to_root_device(struct device *d) |
1324 | { | ||
1325 | return container_of(d, struct root_device, dev); | ||
1326 | } | ||
1324 | 1327 | ||
1325 | static void root_device_release(struct device *dev) | 1328 | static void root_device_release(struct device *dev) |
1326 | { | 1329 | { |
@@ -1551,7 +1554,34 @@ EXPORT_SYMBOL_GPL(device_destroy); | |||
1551 | * on the same device to ensure that new_name is valid and | 1554 | * on the same device to ensure that new_name is valid and |
1552 | * won't conflict with other devices. | 1555 | * won't conflict with other devices. |
1553 | * | 1556 | * |
1554 | * "Never use this function, bad things will happen" - gregkh | 1557 | * Note: Don't call this function. Currently, the networking layer calls this |
1558 | * function, but that will change. The following text from Kay Sievers offers | ||
1559 | * some insight: | ||
1560 | * | ||
1561 | * Renaming devices is racy at many levels, symlinks and other stuff are not | ||
1562 | * replaced atomically, and you get a "move" uevent, but it's not easy to | ||
1563 | * connect the event to the old and new device. Device nodes are not renamed at | ||
1564 | * all, there isn't even support for that in the kernel now. | ||
1565 | * | ||
1566 | * In the meantime, during renaming, your target name might be taken by another | ||
1567 | * driver, creating conflicts. Or the old name is taken directly after you | ||
1568 | * renamed it -- then you get events for the same DEVPATH, before you even see | ||
1569 | * the "move" event. It's just a mess, and nothing new should ever rely on | ||
1570 | * kernel device renaming. Besides that, it's not even implemented now for | ||
1571 | * other things than (driver-core wise very simple) network devices. | ||
1572 | * | ||
1573 | * We are currently about to change network renaming in udev to completely | ||
1574 | * disallow renaming of devices in the same namespace as the kernel uses, | ||
1575 | * because we can't solve the problems properly, that arise with swapping names | ||
1576 | * of multiple interfaces without races. Means, renaming of eth[0-9]* will only | ||
1577 | * be allowed to some other name than eth[0-9]*, for the aforementioned | ||
1578 | * reasons. | ||
1579 | * | ||
1580 | * Make up a "real" name in the driver before you register anything, or add | ||
1581 | * some other attributes for userspace to find the device, or use udev to add | ||
1582 | * symlinks -- but never rename kernel devices later, it's a complete mess. We | ||
1583 | * don't even want to get into that and try to implement the missing pieces in | ||
1584 | * the core. We really have other pieces to fix in the driver core mess. :) | ||
1555 | */ | 1585 | */ |
1556 | int device_rename(struct device *dev, const char *new_name) | 1586 | int device_rename(struct device *dev, const char *new_name) |
1557 | { | 1587 | { |
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 40af43ebd92d..8c798ef7f13f 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -593,8 +593,7 @@ int | |||
593 | request_firmware(const struct firmware **firmware_p, const char *name, | 593 | request_firmware(const struct firmware **firmware_p, const char *name, |
594 | struct device *device) | 594 | struct device *device) |
595 | { | 595 | { |
596 | int uevent = 1; | 596 | return _request_firmware(firmware_p, name, device, true, false); |
597 | return _request_firmware(firmware_p, name, device, uevent, false); | ||
598 | } | 597 | } |
599 | 598 | ||
600 | /** | 599 | /** |
@@ -618,7 +617,7 @@ struct firmware_work { | |||
618 | struct device *device; | 617 | struct device *device; |
619 | void *context; | 618 | void *context; |
620 | void (*cont)(const struct firmware *fw, void *context); | 619 | void (*cont)(const struct firmware *fw, void *context); |
621 | int uevent; | 620 | bool uevent; |
622 | }; | 621 | }; |
623 | 622 | ||
624 | static int request_firmware_work_func(void *arg) | 623 | static int request_firmware_work_func(void *arg) |
@@ -661,7 +660,7 @@ static int request_firmware_work_func(void *arg) | |||
661 | **/ | 660 | **/ |
662 | int | 661 | int |
663 | request_firmware_nowait( | 662 | request_firmware_nowait( |
664 | struct module *module, int uevent, | 663 | struct module *module, bool uevent, |
665 | const char *name, struct device *device, gfp_t gfp, void *context, | 664 | const char *name, struct device *device, gfp_t gfp, void *context, |
666 | void (*cont)(const struct firmware *fw, void *context)) | 665 | void (*cont)(const struct firmware *fw, void *context)) |
667 | { | 666 | { |
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index cafeaaf0428f..3da6a43b7756 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -30,6 +30,14 @@ | |||
30 | static DEFINE_MUTEX(mem_sysfs_mutex); | 30 | static DEFINE_MUTEX(mem_sysfs_mutex); |
31 | 31 | ||
32 | #define MEMORY_CLASS_NAME "memory" | 32 | #define MEMORY_CLASS_NAME "memory" |
33 | #define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS) | ||
34 | |||
35 | static int sections_per_block; | ||
36 | |||
37 | static inline int base_memory_block_id(int section_nr) | ||
38 | { | ||
39 | return section_nr / sections_per_block; | ||
40 | } | ||
33 | 41 | ||
34 | static struct sysdev_class memory_sysdev_class = { | 42 | static struct sysdev_class memory_sysdev_class = { |
35 | .name = MEMORY_CLASS_NAME, | 43 | .name = MEMORY_CLASS_NAME, |
@@ -84,39 +92,72 @@ EXPORT_SYMBOL(unregister_memory_isolate_notifier); | |||
84 | * register_memory - Setup a sysfs device for a memory block | 92 | * register_memory - Setup a sysfs device for a memory block |
85 | */ | 93 | */ |
86 | static | 94 | static |
87 | int register_memory(struct memory_block *memory, struct mem_section *section) | 95 | int register_memory(struct memory_block *memory) |
88 | { | 96 | { |
89 | int error; | 97 | int error; |
90 | 98 | ||
91 | memory->sysdev.cls = &memory_sysdev_class; | 99 | memory->sysdev.cls = &memory_sysdev_class; |
92 | memory->sysdev.id = __section_nr(section); | 100 | memory->sysdev.id = memory->start_section_nr / sections_per_block; |
93 | 101 | ||
94 | error = sysdev_register(&memory->sysdev); | 102 | error = sysdev_register(&memory->sysdev); |
95 | return error; | 103 | return error; |
96 | } | 104 | } |
97 | 105 | ||
98 | static void | 106 | static void |
99 | unregister_memory(struct memory_block *memory, struct mem_section *section) | 107 | unregister_memory(struct memory_block *memory) |
100 | { | 108 | { |
101 | BUG_ON(memory->sysdev.cls != &memory_sysdev_class); | 109 | BUG_ON(memory->sysdev.cls != &memory_sysdev_class); |
102 | BUG_ON(memory->sysdev.id != __section_nr(section)); | ||
103 | 110 | ||
104 | /* drop the ref. we got in remove_memory_block() */ | 111 | /* drop the ref. we got in remove_memory_block() */ |
105 | kobject_put(&memory->sysdev.kobj); | 112 | kobject_put(&memory->sysdev.kobj); |
106 | sysdev_unregister(&memory->sysdev); | 113 | sysdev_unregister(&memory->sysdev); |
107 | } | 114 | } |
108 | 115 | ||
116 | unsigned long __weak memory_block_size_bytes(void) | ||
117 | { | ||
118 | return MIN_MEMORY_BLOCK_SIZE; | ||
119 | } | ||
120 | |||
121 | static unsigned long get_memory_block_size(void) | ||
122 | { | ||
123 | unsigned long block_sz; | ||
124 | |||
125 | block_sz = memory_block_size_bytes(); | ||
126 | |||
127 | /* Validate blk_sz is a power of 2 and not less than section size */ | ||
128 | if ((block_sz & (block_sz - 1)) || (block_sz < MIN_MEMORY_BLOCK_SIZE)) { | ||
129 | WARN_ON(1); | ||
130 | block_sz = MIN_MEMORY_BLOCK_SIZE; | ||
131 | } | ||
132 | |||
133 | return block_sz; | ||
134 | } | ||
135 | |||
109 | /* | 136 | /* |
110 | * use this as the physical section index that this memsection | 137 | * use this as the physical section index that this memsection |
111 | * uses. | 138 | * uses. |
112 | */ | 139 | */ |
113 | 140 | ||
114 | static ssize_t show_mem_phys_index(struct sys_device *dev, | 141 | static ssize_t show_mem_start_phys_index(struct sys_device *dev, |
115 | struct sysdev_attribute *attr, char *buf) | 142 | struct sysdev_attribute *attr, char *buf) |
116 | { | 143 | { |
117 | struct memory_block *mem = | 144 | struct memory_block *mem = |
118 | container_of(dev, struct memory_block, sysdev); | 145 | container_of(dev, struct memory_block, sysdev); |
119 | return sprintf(buf, "%08lx\n", mem->phys_index); | 146 | unsigned long phys_index; |
147 | |||
148 | phys_index = mem->start_section_nr / sections_per_block; | ||
149 | return sprintf(buf, "%08lx\n", phys_index); | ||
150 | } | ||
151 | |||
152 | static ssize_t show_mem_end_phys_index(struct sys_device *dev, | ||
153 | struct sysdev_attribute *attr, char *buf) | ||
154 | { | ||
155 | struct memory_block *mem = | ||
156 | container_of(dev, struct memory_block, sysdev); | ||
157 | unsigned long phys_index; | ||
158 | |||
159 | phys_index = mem->end_section_nr / sections_per_block; | ||
160 | return sprintf(buf, "%08lx\n", phys_index); | ||
120 | } | 161 | } |
121 | 162 | ||
122 | /* | 163 | /* |
@@ -125,13 +166,16 @@ static ssize_t show_mem_phys_index(struct sys_device *dev, | |||
125 | static ssize_t show_mem_removable(struct sys_device *dev, | 166 | static ssize_t show_mem_removable(struct sys_device *dev, |
126 | struct sysdev_attribute *attr, char *buf) | 167 | struct sysdev_attribute *attr, char *buf) |
127 | { | 168 | { |
128 | unsigned long start_pfn; | 169 | unsigned long i, pfn; |
129 | int ret; | 170 | int ret = 1; |
130 | struct memory_block *mem = | 171 | struct memory_block *mem = |
131 | container_of(dev, struct memory_block, sysdev); | 172 | container_of(dev, struct memory_block, sysdev); |
132 | 173 | ||
133 | start_pfn = section_nr_to_pfn(mem->phys_index); | 174 | for (i = 0; i < sections_per_block; i++) { |
134 | ret = is_mem_section_removable(start_pfn, PAGES_PER_SECTION); | 175 | pfn = section_nr_to_pfn(mem->start_section_nr + i); |
176 | ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION); | ||
177 | } | ||
178 | |||
135 | return sprintf(buf, "%d\n", ret); | 179 | return sprintf(buf, "%d\n", ret); |
136 | } | 180 | } |
137 | 181 | ||
@@ -184,17 +228,14 @@ int memory_isolate_notify(unsigned long val, void *v) | |||
184 | * OK to have direct references to sparsemem variables in here. | 228 | * OK to have direct references to sparsemem variables in here. |
185 | */ | 229 | */ |
186 | static int | 230 | static int |
187 | memory_block_action(struct memory_block *mem, unsigned long action) | 231 | memory_section_action(unsigned long phys_index, unsigned long action) |
188 | { | 232 | { |
189 | int i; | 233 | int i; |
190 | unsigned long psection; | ||
191 | unsigned long start_pfn, start_paddr; | 234 | unsigned long start_pfn, start_paddr; |
192 | struct page *first_page; | 235 | struct page *first_page; |
193 | int ret; | 236 | int ret; |
194 | int old_state = mem->state; | ||
195 | 237 | ||
196 | psection = mem->phys_index; | 238 | first_page = pfn_to_page(phys_index << PFN_SECTION_SHIFT); |
197 | first_page = pfn_to_page(psection << PFN_SECTION_SHIFT); | ||
198 | 239 | ||
199 | /* | 240 | /* |
200 | * The probe routines leave the pages reserved, just | 241 | * The probe routines leave the pages reserved, just |
@@ -207,8 +248,8 @@ memory_block_action(struct memory_block *mem, unsigned long action) | |||
207 | continue; | 248 | continue; |
208 | 249 | ||
209 | printk(KERN_WARNING "section number %ld page number %d " | 250 | printk(KERN_WARNING "section number %ld page number %d " |
210 | "not reserved, was it already online? \n", | 251 | "not reserved, was it already online?\n", |
211 | psection, i); | 252 | phys_index, i); |
212 | return -EBUSY; | 253 | return -EBUSY; |
213 | } | 254 | } |
214 | } | 255 | } |
@@ -219,18 +260,13 @@ memory_block_action(struct memory_block *mem, unsigned long action) | |||
219 | ret = online_pages(start_pfn, PAGES_PER_SECTION); | 260 | ret = online_pages(start_pfn, PAGES_PER_SECTION); |
220 | break; | 261 | break; |
221 | case MEM_OFFLINE: | 262 | case MEM_OFFLINE: |
222 | mem->state = MEM_GOING_OFFLINE; | ||
223 | start_paddr = page_to_pfn(first_page) << PAGE_SHIFT; | 263 | start_paddr = page_to_pfn(first_page) << PAGE_SHIFT; |
224 | ret = remove_memory(start_paddr, | 264 | ret = remove_memory(start_paddr, |
225 | PAGES_PER_SECTION << PAGE_SHIFT); | 265 | PAGES_PER_SECTION << PAGE_SHIFT); |
226 | if (ret) { | ||
227 | mem->state = old_state; | ||
228 | break; | ||
229 | } | ||
230 | break; | 266 | break; |
231 | default: | 267 | default: |
232 | WARN(1, KERN_WARNING "%s(%p, %ld) unknown action: %ld\n", | 268 | WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: " |
233 | __func__, mem, action, action); | 269 | "%ld\n", __func__, phys_index, action, action); |
234 | ret = -EINVAL; | 270 | ret = -EINVAL; |
235 | } | 271 | } |
236 | 272 | ||
@@ -240,7 +276,8 @@ memory_block_action(struct memory_block *mem, unsigned long action) | |||
240 | static int memory_block_change_state(struct memory_block *mem, | 276 | static int memory_block_change_state(struct memory_block *mem, |
241 | unsigned long to_state, unsigned long from_state_req) | 277 | unsigned long to_state, unsigned long from_state_req) |
242 | { | 278 | { |
243 | int ret = 0; | 279 | int i, ret = 0; |
280 | |||
244 | mutex_lock(&mem->state_mutex); | 281 | mutex_lock(&mem->state_mutex); |
245 | 282 | ||
246 | if (mem->state != from_state_req) { | 283 | if (mem->state != from_state_req) { |
@@ -248,8 +285,23 @@ static int memory_block_change_state(struct memory_block *mem, | |||
248 | goto out; | 285 | goto out; |
249 | } | 286 | } |
250 | 287 | ||
251 | ret = memory_block_action(mem, to_state); | 288 | if (to_state == MEM_OFFLINE) |
252 | if (!ret) | 289 | mem->state = MEM_GOING_OFFLINE; |
290 | |||
291 | for (i = 0; i < sections_per_block; i++) { | ||
292 | ret = memory_section_action(mem->start_section_nr + i, | ||
293 | to_state); | ||
294 | if (ret) | ||
295 | break; | ||
296 | } | ||
297 | |||
298 | if (ret) { | ||
299 | for (i = 0; i < sections_per_block; i++) | ||
300 | memory_section_action(mem->start_section_nr + i, | ||
301 | from_state_req); | ||
302 | |||
303 | mem->state = from_state_req; | ||
304 | } else | ||
253 | mem->state = to_state; | 305 | mem->state = to_state; |
254 | 306 | ||
255 | out: | 307 | out: |
@@ -262,20 +314,15 @@ store_mem_state(struct sys_device *dev, | |||
262 | struct sysdev_attribute *attr, const char *buf, size_t count) | 314 | struct sysdev_attribute *attr, const char *buf, size_t count) |
263 | { | 315 | { |
264 | struct memory_block *mem; | 316 | struct memory_block *mem; |
265 | unsigned int phys_section_nr; | ||
266 | int ret = -EINVAL; | 317 | int ret = -EINVAL; |
267 | 318 | ||
268 | mem = container_of(dev, struct memory_block, sysdev); | 319 | mem = container_of(dev, struct memory_block, sysdev); |
269 | phys_section_nr = mem->phys_index; | ||
270 | |||
271 | if (!present_section_nr(phys_section_nr)) | ||
272 | goto out; | ||
273 | 320 | ||
274 | if (!strncmp(buf, "online", min((int)count, 6))) | 321 | if (!strncmp(buf, "online", min((int)count, 6))) |
275 | ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); | 322 | ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); |
276 | else if(!strncmp(buf, "offline", min((int)count, 7))) | 323 | else if(!strncmp(buf, "offline", min((int)count, 7))) |
277 | ret = memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE); | 324 | ret = memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE); |
278 | out: | 325 | |
279 | if (ret) | 326 | if (ret) |
280 | return ret; | 327 | return ret; |
281 | return count; | 328 | return count; |
@@ -298,7 +345,8 @@ static ssize_t show_phys_device(struct sys_device *dev, | |||
298 | return sprintf(buf, "%d\n", mem->phys_device); | 345 | return sprintf(buf, "%d\n", mem->phys_device); |
299 | } | 346 | } |
300 | 347 | ||
301 | static SYSDEV_ATTR(phys_index, 0444, show_mem_phys_index, NULL); | 348 | static SYSDEV_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL); |
349 | static SYSDEV_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL); | ||
302 | static SYSDEV_ATTR(state, 0644, show_mem_state, store_mem_state); | 350 | static SYSDEV_ATTR(state, 0644, show_mem_state, store_mem_state); |
303 | static SYSDEV_ATTR(phys_device, 0444, show_phys_device, NULL); | 351 | static SYSDEV_ATTR(phys_device, 0444, show_phys_device, NULL); |
304 | static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL); | 352 | static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL); |
@@ -315,7 +363,7 @@ static ssize_t | |||
315 | print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr, | 363 | print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr, |
316 | char *buf) | 364 | char *buf) |
317 | { | 365 | { |
318 | return sprintf(buf, "%lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE); | 366 | return sprintf(buf, "%lx\n", get_memory_block_size()); |
319 | } | 367 | } |
320 | 368 | ||
321 | static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL); | 369 | static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL); |
@@ -339,12 +387,19 @@ memory_probe_store(struct class *class, struct class_attribute *attr, | |||
339 | { | 387 | { |
340 | u64 phys_addr; | 388 | u64 phys_addr; |
341 | int nid; | 389 | int nid; |
342 | int ret; | 390 | int i, ret; |
343 | 391 | ||
344 | phys_addr = simple_strtoull(buf, NULL, 0); | 392 | phys_addr = simple_strtoull(buf, NULL, 0); |
345 | 393 | ||
346 | nid = memory_add_physaddr_to_nid(phys_addr); | 394 | for (i = 0; i < sections_per_block; i++) { |
347 | ret = add_memory(nid, phys_addr, PAGES_PER_SECTION << PAGE_SHIFT); | 395 | nid = memory_add_physaddr_to_nid(phys_addr); |
396 | ret = add_memory(nid, phys_addr, | ||
397 | PAGES_PER_SECTION << PAGE_SHIFT); | ||
398 | if (ret) | ||
399 | break; | ||
400 | |||
401 | phys_addr += MIN_MEMORY_BLOCK_SIZE; | ||
402 | } | ||
348 | 403 | ||
349 | if (ret) | 404 | if (ret) |
350 | count = ret; | 405 | count = ret; |
@@ -444,6 +499,7 @@ struct memory_block *find_memory_block_hinted(struct mem_section *section, | |||
444 | struct sys_device *sysdev; | 499 | struct sys_device *sysdev; |
445 | struct memory_block *mem; | 500 | struct memory_block *mem; |
446 | char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; | 501 | char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; |
502 | int block_id = base_memory_block_id(__section_nr(section)); | ||
447 | 503 | ||
448 | kobj = hint ? &hint->sysdev.kobj : NULL; | 504 | kobj = hint ? &hint->sysdev.kobj : NULL; |
449 | 505 | ||
@@ -451,7 +507,7 @@ struct memory_block *find_memory_block_hinted(struct mem_section *section, | |||
451 | * This only works because we know that section == sysdev->id | 507 | * This only works because we know that section == sysdev->id |
452 | * slightly redundant with sysdev_register() | 508 | * slightly redundant with sysdev_register() |
453 | */ | 509 | */ |
454 | sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section)); | 510 | sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, block_id); |
455 | 511 | ||
456 | kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj); | 512 | kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj); |
457 | if (!kobj) | 513 | if (!kobj) |
@@ -476,36 +532,62 @@ struct memory_block *find_memory_block(struct mem_section *section) | |||
476 | return find_memory_block_hinted(section, NULL); | 532 | return find_memory_block_hinted(section, NULL); |
477 | } | 533 | } |
478 | 534 | ||
479 | static int add_memory_block(int nid, struct mem_section *section, | 535 | static int init_memory_block(struct memory_block **memory, |
480 | unsigned long state, enum mem_add_context context) | 536 | struct mem_section *section, unsigned long state) |
481 | { | 537 | { |
482 | struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL); | 538 | struct memory_block *mem; |
483 | unsigned long start_pfn; | 539 | unsigned long start_pfn; |
540 | int scn_nr; | ||
484 | int ret = 0; | 541 | int ret = 0; |
485 | 542 | ||
543 | mem = kzalloc(sizeof(*mem), GFP_KERNEL); | ||
486 | if (!mem) | 544 | if (!mem) |
487 | return -ENOMEM; | 545 | return -ENOMEM; |
488 | 546 | ||
489 | mutex_lock(&mem_sysfs_mutex); | 547 | scn_nr = __section_nr(section); |
490 | 548 | mem->start_section_nr = | |
491 | mem->phys_index = __section_nr(section); | 549 | base_memory_block_id(scn_nr) * sections_per_block; |
550 | mem->end_section_nr = mem->start_section_nr + sections_per_block - 1; | ||
492 | mem->state = state; | 551 | mem->state = state; |
493 | mem->section_count++; | 552 | mem->section_count++; |
494 | mutex_init(&mem->state_mutex); | 553 | mutex_init(&mem->state_mutex); |
495 | start_pfn = section_nr_to_pfn(mem->phys_index); | 554 | start_pfn = section_nr_to_pfn(mem->start_section_nr); |
496 | mem->phys_device = arch_get_memory_phys_device(start_pfn); | 555 | mem->phys_device = arch_get_memory_phys_device(start_pfn); |
497 | 556 | ||
498 | ret = register_memory(mem, section); | 557 | ret = register_memory(mem); |
499 | if (!ret) | 558 | if (!ret) |
500 | ret = mem_create_simple_file(mem, phys_index); | 559 | ret = mem_create_simple_file(mem, phys_index); |
501 | if (!ret) | 560 | if (!ret) |
561 | ret = mem_create_simple_file(mem, end_phys_index); | ||
562 | if (!ret) | ||
502 | ret = mem_create_simple_file(mem, state); | 563 | ret = mem_create_simple_file(mem, state); |
503 | if (!ret) | 564 | if (!ret) |
504 | ret = mem_create_simple_file(mem, phys_device); | 565 | ret = mem_create_simple_file(mem, phys_device); |
505 | if (!ret) | 566 | if (!ret) |
506 | ret = mem_create_simple_file(mem, removable); | 567 | ret = mem_create_simple_file(mem, removable); |
568 | |||
569 | *memory = mem; | ||
570 | return ret; | ||
571 | } | ||
572 | |||
573 | static int add_memory_section(int nid, struct mem_section *section, | ||
574 | unsigned long state, enum mem_add_context context) | ||
575 | { | ||
576 | struct memory_block *mem; | ||
577 | int ret = 0; | ||
578 | |||
579 | mutex_lock(&mem_sysfs_mutex); | ||
580 | |||
581 | mem = find_memory_block(section); | ||
582 | if (mem) { | ||
583 | mem->section_count++; | ||
584 | kobject_put(&mem->sysdev.kobj); | ||
585 | } else | ||
586 | ret = init_memory_block(&mem, section, state); | ||
587 | |||
507 | if (!ret) { | 588 | if (!ret) { |
508 | if (context == HOTPLUG) | 589 | if (context == HOTPLUG && |
590 | mem->section_count == sections_per_block) | ||
509 | ret = register_mem_sect_under_node(mem, nid); | 591 | ret = register_mem_sect_under_node(mem, nid); |
510 | } | 592 | } |
511 | 593 | ||
@@ -520,16 +602,19 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, | |||
520 | 602 | ||
521 | mutex_lock(&mem_sysfs_mutex); | 603 | mutex_lock(&mem_sysfs_mutex); |
522 | mem = find_memory_block(section); | 604 | mem = find_memory_block(section); |
605 | unregister_mem_sect_under_nodes(mem, __section_nr(section)); | ||
523 | 606 | ||
524 | mem->section_count--; | 607 | mem->section_count--; |
525 | if (mem->section_count == 0) { | 608 | if (mem->section_count == 0) { |
526 | unregister_mem_sect_under_nodes(mem); | ||
527 | mem_remove_simple_file(mem, phys_index); | 609 | mem_remove_simple_file(mem, phys_index); |
610 | mem_remove_simple_file(mem, end_phys_index); | ||
528 | mem_remove_simple_file(mem, state); | 611 | mem_remove_simple_file(mem, state); |
529 | mem_remove_simple_file(mem, phys_device); | 612 | mem_remove_simple_file(mem, phys_device); |
530 | mem_remove_simple_file(mem, removable); | 613 | mem_remove_simple_file(mem, removable); |
531 | unregister_memory(mem, section); | 614 | unregister_memory(mem); |
532 | } | 615 | kfree(mem); |
616 | } else | ||
617 | kobject_put(&mem->sysdev.kobj); | ||
533 | 618 | ||
534 | mutex_unlock(&mem_sysfs_mutex); | 619 | mutex_unlock(&mem_sysfs_mutex); |
535 | return 0; | 620 | return 0; |
@@ -541,7 +626,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, | |||
541 | */ | 626 | */ |
542 | int register_new_memory(int nid, struct mem_section *section) | 627 | int register_new_memory(int nid, struct mem_section *section) |
543 | { | 628 | { |
544 | return add_memory_block(nid, section, MEM_OFFLINE, HOTPLUG); | 629 | return add_memory_section(nid, section, MEM_OFFLINE, HOTPLUG); |
545 | } | 630 | } |
546 | 631 | ||
547 | int unregister_memory_section(struct mem_section *section) | 632 | int unregister_memory_section(struct mem_section *section) |
@@ -560,12 +645,16 @@ int __init memory_dev_init(void) | |||
560 | unsigned int i; | 645 | unsigned int i; |
561 | int ret; | 646 | int ret; |
562 | int err; | 647 | int err; |
648 | unsigned long block_sz; | ||
563 | 649 | ||
564 | memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops; | 650 | memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops; |
565 | ret = sysdev_class_register(&memory_sysdev_class); | 651 | ret = sysdev_class_register(&memory_sysdev_class); |
566 | if (ret) | 652 | if (ret) |
567 | goto out; | 653 | goto out; |
568 | 654 | ||
655 | block_sz = get_memory_block_size(); | ||
656 | sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE; | ||
657 | |||
569 | /* | 658 | /* |
570 | * Create entries for memory sections that were found | 659 | * Create entries for memory sections that were found |
571 | * during boot and have been initialized | 660 | * during boot and have been initialized |
@@ -573,8 +662,8 @@ int __init memory_dev_init(void) | |||
573 | for (i = 0; i < NR_MEM_SECTIONS; i++) { | 662 | for (i = 0; i < NR_MEM_SECTIONS; i++) { |
574 | if (!present_section_nr(i)) | 663 | if (!present_section_nr(i)) |
575 | continue; | 664 | continue; |
576 | err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, | 665 | err = add_memory_section(0, __nr_to_section(i), MEM_ONLINE, |
577 | BOOT); | 666 | BOOT); |
578 | if (!ret) | 667 | if (!ret) |
579 | ret = err; | 668 | ret = err; |
580 | } | 669 | } |
diff --git a/drivers/base/node.c b/drivers/base/node.c index 36b43052001d..b3b72d64e805 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c | |||
@@ -375,8 +375,10 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, int nid) | |||
375 | return -EFAULT; | 375 | return -EFAULT; |
376 | if (!node_online(nid)) | 376 | if (!node_online(nid)) |
377 | return 0; | 377 | return 0; |
378 | sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index); | 378 | |
379 | sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; | 379 | sect_start_pfn = section_nr_to_pfn(mem_blk->start_section_nr); |
380 | sect_end_pfn = section_nr_to_pfn(mem_blk->end_section_nr); | ||
381 | sect_end_pfn += PAGES_PER_SECTION - 1; | ||
380 | for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { | 382 | for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { |
381 | int page_nid; | 383 | int page_nid; |
382 | 384 | ||
@@ -400,7 +402,8 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, int nid) | |||
400 | } | 402 | } |
401 | 403 | ||
402 | /* unregister memory section under all nodes that it spans */ | 404 | /* unregister memory section under all nodes that it spans */ |
403 | int unregister_mem_sect_under_nodes(struct memory_block *mem_blk) | 405 | int unregister_mem_sect_under_nodes(struct memory_block *mem_blk, |
406 | unsigned long phys_index) | ||
404 | { | 407 | { |
405 | NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL); | 408 | NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL); |
406 | unsigned long pfn, sect_start_pfn, sect_end_pfn; | 409 | unsigned long pfn, sect_start_pfn, sect_end_pfn; |
@@ -412,7 +415,8 @@ int unregister_mem_sect_under_nodes(struct memory_block *mem_blk) | |||
412 | if (!unlinked_nodes) | 415 | if (!unlinked_nodes) |
413 | return -ENOMEM; | 416 | return -ENOMEM; |
414 | nodes_clear(*unlinked_nodes); | 417 | nodes_clear(*unlinked_nodes); |
415 | sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index); | 418 | |
419 | sect_start_pfn = section_nr_to_pfn(phys_index); | ||
416 | sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; | 420 | sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; |
417 | for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { | 421 | for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { |
418 | int nid; | 422 | int nid; |
diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 1667aaf4fde6..f6fb54741602 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c | |||
@@ -166,6 +166,36 @@ EXPORT_SYMBOL_GPL(sysdev_class_unregister); | |||
166 | 166 | ||
167 | static DEFINE_MUTEX(sysdev_drivers_lock); | 167 | static DEFINE_MUTEX(sysdev_drivers_lock); |
168 | 168 | ||
169 | /* | ||
170 | * @dev != NULL means that we're unwinding because some drv->add() | ||
171 | * failed for some reason. You need to grab sysdev_drivers_lock before | ||
172 | * calling this. | ||
173 | */ | ||
174 | static void __sysdev_driver_remove(struct sysdev_class *cls, | ||
175 | struct sysdev_driver *drv, | ||
176 | struct sys_device *from_dev) | ||
177 | { | ||
178 | struct sys_device *dev = from_dev; | ||
179 | |||
180 | list_del_init(&drv->entry); | ||
181 | if (!cls) | ||
182 | return; | ||
183 | |||
184 | if (!drv->remove) | ||
185 | goto kset_put; | ||
186 | |||
187 | if (dev) | ||
188 | list_for_each_entry_continue_reverse(dev, &cls->kset.list, | ||
189 | kobj.entry) | ||
190 | drv->remove(dev); | ||
191 | else | ||
192 | list_for_each_entry(dev, &cls->kset.list, kobj.entry) | ||
193 | drv->remove(dev); | ||
194 | |||
195 | kset_put: | ||
196 | kset_put(&cls->kset); | ||
197 | } | ||
198 | |||
169 | /** | 199 | /** |
170 | * sysdev_driver_register - Register auxillary driver | 200 | * sysdev_driver_register - Register auxillary driver |
171 | * @cls: Device class driver belongs to. | 201 | * @cls: Device class driver belongs to. |
@@ -175,14 +205,14 @@ static DEFINE_MUTEX(sysdev_drivers_lock); | |||
175 | * called on each operation on devices of that class. The refcount | 205 | * called on each operation on devices of that class. The refcount |
176 | * of @cls is incremented. | 206 | * of @cls is incremented. |
177 | */ | 207 | */ |
178 | |||
179 | int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) | 208 | int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) |
180 | { | 209 | { |
210 | struct sys_device *dev = NULL; | ||
181 | int err = 0; | 211 | int err = 0; |
182 | 212 | ||
183 | if (!cls) { | 213 | if (!cls) { |
184 | WARN(1, KERN_WARNING "sysdev: invalid class passed to " | 214 | WARN(1, KERN_WARNING "sysdev: invalid class passed to %s!\n", |
185 | "sysdev_driver_register!\n"); | 215 | __func__); |
186 | return -EINVAL; | 216 | return -EINVAL; |
187 | } | 217 | } |
188 | 218 | ||
@@ -198,19 +228,27 @@ int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) | |||
198 | 228 | ||
199 | /* If devices of this class already exist, tell the driver */ | 229 | /* If devices of this class already exist, tell the driver */ |
200 | if (drv->add) { | 230 | if (drv->add) { |
201 | struct sys_device *dev; | 231 | list_for_each_entry(dev, &cls->kset.list, kobj.entry) { |
202 | list_for_each_entry(dev, &cls->kset.list, kobj.entry) | 232 | err = drv->add(dev); |
203 | drv->add(dev); | 233 | if (err) |
234 | goto unwind; | ||
235 | } | ||
204 | } | 236 | } |
205 | } else { | 237 | } else { |
206 | err = -EINVAL; | 238 | err = -EINVAL; |
207 | WARN(1, KERN_ERR "%s: invalid device class\n", __func__); | 239 | WARN(1, KERN_ERR "%s: invalid device class\n", __func__); |
208 | } | 240 | } |
241 | |||
242 | goto unlock; | ||
243 | |||
244 | unwind: | ||
245 | __sysdev_driver_remove(cls, drv, dev); | ||
246 | |||
247 | unlock: | ||
209 | mutex_unlock(&sysdev_drivers_lock); | 248 | mutex_unlock(&sysdev_drivers_lock); |
210 | return err; | 249 | return err; |
211 | } | 250 | } |
212 | 251 | ||
213 | |||
214 | /** | 252 | /** |
215 | * sysdev_driver_unregister - Remove an auxillary driver. | 253 | * sysdev_driver_unregister - Remove an auxillary driver. |
216 | * @cls: Class driver belongs to. | 254 | * @cls: Class driver belongs to. |
@@ -220,23 +258,12 @@ void sysdev_driver_unregister(struct sysdev_class *cls, | |||
220 | struct sysdev_driver *drv) | 258 | struct sysdev_driver *drv) |
221 | { | 259 | { |
222 | mutex_lock(&sysdev_drivers_lock); | 260 | mutex_lock(&sysdev_drivers_lock); |
223 | list_del_init(&drv->entry); | 261 | __sysdev_driver_remove(cls, drv, NULL); |
224 | if (cls) { | ||
225 | if (drv->remove) { | ||
226 | struct sys_device *dev; | ||
227 | list_for_each_entry(dev, &cls->kset.list, kobj.entry) | ||
228 | drv->remove(dev); | ||
229 | } | ||
230 | kset_put(&cls->kset); | ||
231 | } | ||
232 | mutex_unlock(&sysdev_drivers_lock); | 262 | mutex_unlock(&sysdev_drivers_lock); |
233 | } | 263 | } |
234 | |||
235 | EXPORT_SYMBOL_GPL(sysdev_driver_register); | 264 | EXPORT_SYMBOL_GPL(sysdev_driver_register); |
236 | EXPORT_SYMBOL_GPL(sysdev_driver_unregister); | 265 | EXPORT_SYMBOL_GPL(sysdev_driver_unregister); |
237 | 266 | ||
238 | |||
239 | |||
240 | /** | 267 | /** |
241 | * sysdev_register - add a system device to the tree | 268 | * sysdev_register - add a system device to the tree |
242 | * @sysdev: device in question | 269 | * @sysdev: device in question |