aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/char')
-rw-r--r--drivers/s390/char/sclp_cmd.c48
1 files changed, 46 insertions, 2 deletions
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 6e14999f9e8f..7be782116dab 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -315,10 +315,29 @@ static int sclp_mem_change_state(unsigned long start, unsigned long size,
315 rc |= sclp_assign_storage(incr->rn); 315 rc |= sclp_assign_storage(incr->rn);
316 else 316 else
317 sclp_unassign_storage(incr->rn); 317 sclp_unassign_storage(incr->rn);
318 if (rc == 0)
319 incr->standby = online ? 0 : 1;
318 } 320 }
319 return rc ? -EIO : 0; 321 return rc ? -EIO : 0;
320} 322}
321 323
324static bool contains_standby_increment(unsigned long start, unsigned long end)
325{
326 struct memory_increment *incr;
327 unsigned long istart;
328
329 list_for_each_entry(incr, &sclp_mem_list, list) {
330 istart = rn2addr(incr->rn);
331 if (end - 1 < istart)
332 continue;
333 if (start > istart + sclp_rzm - 1)
334 continue;
335 if (incr->standby)
336 return true;
337 }
338 return false;
339}
340
322static int sclp_mem_notifier(struct notifier_block *nb, 341static int sclp_mem_notifier(struct notifier_block *nb,
323 unsigned long action, void *data) 342 unsigned long action, void *data)
324{ 343{
@@ -334,8 +353,16 @@ static int sclp_mem_notifier(struct notifier_block *nb,
334 for_each_clear_bit(id, sclp_storage_ids, sclp_max_storage_id + 1) 353 for_each_clear_bit(id, sclp_storage_ids, sclp_max_storage_id + 1)
335 sclp_attach_storage(id); 354 sclp_attach_storage(id);
336 switch (action) { 355 switch (action) {
337 case MEM_ONLINE:
338 case MEM_GOING_OFFLINE: 356 case MEM_GOING_OFFLINE:
357 /*
358 * We do not allow to set memory blocks offline that contain
359 * standby memory. This is done to simplify the "memory online"
360 * case.
361 */
362 if (contains_standby_increment(start, start + size))
363 rc = -EPERM;
364 break;
365 case MEM_ONLINE:
339 case MEM_CANCEL_OFFLINE: 366 case MEM_CANCEL_OFFLINE:
340 break; 367 break;
341 case MEM_GOING_ONLINE: 368 case MEM_GOING_ONLINE:
@@ -361,6 +388,21 @@ static struct notifier_block sclp_mem_nb = {
361 .notifier_call = sclp_mem_notifier, 388 .notifier_call = sclp_mem_notifier,
362}; 389};
363 390
391static void __init align_to_block_size(unsigned long long *start,
392 unsigned long long *size)
393{
394 unsigned long long start_align, size_align, alignment;
395
396 alignment = memory_block_size_bytes();
397 start_align = roundup(*start, alignment);
398 size_align = rounddown(*start + *size, alignment) - start_align;
399
400 pr_info("Standby memory at 0x%llx (%lluM of %lluM usable)\n",
401 *start, size_align >> 20, *size >> 20);
402 *start = start_align;
403 *size = size_align;
404}
405
364static void __init add_memory_merged(u16 rn) 406static void __init add_memory_merged(u16 rn)
365{ 407{
366 static u16 first_rn, num; 408 static u16 first_rn, num;
@@ -382,7 +424,9 @@ static void __init add_memory_merged(u16 rn)
382 goto skip_add; 424 goto skip_add;
383 if (memory_end_set && (start + size > memory_end)) 425 if (memory_end_set && (start + size > memory_end))
384 size = memory_end - start; 426 size = memory_end - start;
385 add_memory(0, start, size); 427 align_to_block_size(&start, &size);
428 if (size)
429 add_memory(0, start, size);
386skip_add: 430skip_add:
387 first_rn = rn; 431 first_rn = rn;
388 num = 1; 432 num = 1;