aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm/extmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/mm/extmem.c')
-rw-r--r--arch/s390/mm/extmem.c66
1 files changed, 55 insertions, 11 deletions
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index 775bf19e742b..394980b05e6f 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -15,6 +15,7 @@
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/bootmem.h> 16#include <linux/bootmem.h>
17#include <linux/ctype.h> 17#include <linux/ctype.h>
18#include <linux/ioport.h>
18#include <asm/page.h> 19#include <asm/page.h>
19#include <asm/pgtable.h> 20#include <asm/pgtable.h>
20#include <asm/ebcdic.h> 21#include <asm/ebcdic.h>
@@ -70,6 +71,7 @@ struct qin64 {
70struct dcss_segment { 71struct dcss_segment {
71 struct list_head list; 72 struct list_head list;
72 char dcss_name[8]; 73 char dcss_name[8];
74 char res_name[15];
73 unsigned long start_addr; 75 unsigned long start_addr;
74 unsigned long end; 76 unsigned long end;
75 atomic_t ref_count; 77 atomic_t ref_count;
@@ -77,6 +79,7 @@ struct dcss_segment {
77 unsigned int vm_segtype; 79 unsigned int vm_segtype;
78 struct qrange range[6]; 80 struct qrange range[6];
79 int segcnt; 81 int segcnt;
82 struct resource *res;
80}; 83};
81 84
82static DEFINE_MUTEX(dcss_lock); 85static DEFINE_MUTEX(dcss_lock);
@@ -88,7 +91,7 @@ static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
88 * Create the 8 bytes, ebcdic VM segment name from 91 * Create the 8 bytes, ebcdic VM segment name from
89 * an ascii name. 92 * an ascii name.
90 */ 93 */
91static void inline 94static void
92dcss_mkname(char *name, char *dcss_name) 95dcss_mkname(char *name, char *dcss_name)
93{ 96{
94 int i; 97 int i;
@@ -303,6 +306,29 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
303 goto out_free; 306 goto out_free;
304 } 307 }
305 308
309 seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL);
310 if (seg->res == NULL) {
311 rc = -ENOMEM;
312 goto out_shared;
313 }
314 seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
315 seg->res->start = seg->start_addr;
316 seg->res->end = seg->end;
317 memcpy(&seg->res_name, seg->dcss_name, 8);
318 EBCASC(seg->res_name, 8);
319 seg->res_name[8] = '\0';
320 strncat(seg->res_name, " (DCSS)", 7);
321 seg->res->name = seg->res_name;
322 rc = seg->vm_segtype;
323 if (rc == SEG_TYPE_SC ||
324 ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
325 seg->res->flags |= IORESOURCE_READONLY;
326 if (request_resource(&iomem_resource, seg->res)) {
327 rc = -EBUSY;
328 kfree(seg->res);
329 goto out_shared;
330 }
331
306 if (do_nonshared) 332 if (do_nonshared)
307 dcss_command = DCSS_LOADNSR; 333 dcss_command = DCSS_LOADNSR;
308 else 334 else
@@ -316,12 +342,11 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
316 rc = dcss_diag_translate_rc (seg->end); 342 rc = dcss_diag_translate_rc (seg->end);
317 dcss_diag(DCSS_PURGESEG, seg->dcss_name, 343 dcss_diag(DCSS_PURGESEG, seg->dcss_name,
318 &seg->start_addr, &seg->end); 344 &seg->start_addr, &seg->end);
319 goto out_shared; 345 goto out_resource;
320 } 346 }
321 seg->do_nonshared = do_nonshared; 347 seg->do_nonshared = do_nonshared;
322 atomic_set(&seg->ref_count, 1); 348 atomic_set(&seg->ref_count, 1);
323 list_add(&seg->list, &dcss_list); 349 list_add(&seg->list, &dcss_list);
324 rc = seg->vm_segtype;
325 *addr = seg->start_addr; 350 *addr = seg->start_addr;
326 *end = seg->end; 351 *end = seg->end;
327 if (do_nonshared) 352 if (do_nonshared)
@@ -329,12 +354,16 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
329 "type %s in non-shared mode\n", name, 354 "type %s in non-shared mode\n", name,
330 (void*)seg->start_addr, (void*)seg->end, 355 (void*)seg->start_addr, (void*)seg->end,
331 segtype_string[seg->vm_segtype]); 356 segtype_string[seg->vm_segtype]);
332 else 357 else {
333 PRINT_INFO ("segment_load: loaded segment %s range %p .. %p " 358 PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
334 "type %s in shared mode\n", name, 359 "type %s in shared mode\n", name,
335 (void*)seg->start_addr, (void*)seg->end, 360 (void*)seg->start_addr, (void*)seg->end,
336 segtype_string[seg->vm_segtype]); 361 segtype_string[seg->vm_segtype]);
362 }
337 goto out; 363 goto out;
364 out_resource:
365 release_resource(seg->res);
366 kfree(seg->res);
338 out_shared: 367 out_shared:
339 remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); 368 remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
340 out_free: 369 out_free:
@@ -401,6 +430,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr,
401 * -ENOENT : no such segment (segment gone!) 430 * -ENOENT : no such segment (segment gone!)
402 * -EAGAIN : segment is in use by other exploiters, try later 431 * -EAGAIN : segment is in use by other exploiters, try later
403 * -EINVAL : no segment with the given name is currently loaded - name invalid 432 * -EINVAL : no segment with the given name is currently loaded - name invalid
433 * -EBUSY : segment can temporarily not be used (overlaps with dcss)
404 * 0 : operation succeeded 434 * 0 : operation succeeded
405 */ 435 */
406int 436int
@@ -428,12 +458,24 @@ segment_modify_shared (char *name, int do_nonshared)
428 rc = -EAGAIN; 458 rc = -EAGAIN;
429 goto out_unlock; 459 goto out_unlock;
430 } 460 }
431 dcss_diag(DCSS_PURGESEG, seg->dcss_name, 461 release_resource(seg->res);
432 &dummy, &dummy); 462 if (do_nonshared) {
433 if (do_nonshared)
434 dcss_command = DCSS_LOADNSR; 463 dcss_command = DCSS_LOADNSR;
435 else 464 seg->res->flags &= ~IORESOURCE_READONLY;
436 dcss_command = DCSS_LOADNOLY; 465 } else {
466 dcss_command = DCSS_LOADNOLY;
467 if (seg->vm_segtype == SEG_TYPE_SR ||
468 seg->vm_segtype == SEG_TYPE_ER)
469 seg->res->flags |= IORESOURCE_READONLY;
470 }
471 if (request_resource(&iomem_resource, seg->res)) {
472 PRINT_WARN("segment_modify_shared: could not reload segment %s"
473 " - overlapping resources\n", name);
474 rc = -EBUSY;
475 kfree(seg->res);
476 goto out_del;
477 }
478 dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
437 diag_cc = dcss_diag(dcss_command, seg->dcss_name, 479 diag_cc = dcss_diag(dcss_command, seg->dcss_name,
438 &seg->start_addr, &seg->end); 480 &seg->start_addr, &seg->end);
439 if (diag_cc > 1) { 481 if (diag_cc > 1) {
@@ -446,9 +488,9 @@ segment_modify_shared (char *name, int do_nonshared)
446 rc = 0; 488 rc = 0;
447 goto out_unlock; 489 goto out_unlock;
448 out_del: 490 out_del:
491 remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
449 list_del(&seg->list); 492 list_del(&seg->list);
450 dcss_diag(DCSS_PURGESEG, seg->dcss_name, 493 dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
451 &dummy, &dummy);
452 kfree(seg); 494 kfree(seg);
453 out_unlock: 495 out_unlock:
454 mutex_unlock(&dcss_lock); 496 mutex_unlock(&dcss_lock);
@@ -478,6 +520,8 @@ segment_unload(char *name)
478 } 520 }
479 if (atomic_dec_return(&seg->ref_count) != 0) 521 if (atomic_dec_return(&seg->ref_count) != 0)
480 goto out_unlock; 522 goto out_unlock;
523 release_resource(seg->res);
524 kfree(seg->res);
481 remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); 525 remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
482 list_del(&seg->list); 526 list_del(&seg->list);
483 dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); 527 dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);