--- zzzz-none-000/linux-3.10.107/drivers/s390/char/sclp_cmd.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/s390/char/sclp_cmd.c 2021-02-04 17:41:59.000000000 +0000 @@ -25,169 +25,10 @@ #include #include #include +#include #include "sclp.h" -#define SCLP_CMDW_READ_SCP_INFO 0x00020001 -#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 - -struct read_info_sccb { - struct sccb_header header; /* 0-7 */ - u16 rnmax; /* 8-9 */ - u8 rnsize; /* 10 */ - u8 _reserved0[24 - 11]; /* 11-15 */ - u8 loadparm[8]; /* 24-31 */ - u8 _reserved1[48 - 32]; /* 32-47 */ - u64 facilities; /* 48-55 */ - u8 _reserved2[84 - 56]; /* 56-83 */ - u8 fac84; /* 84 */ - u8 fac85; /* 85 */ - u8 _reserved3[91 - 86]; /* 86-90 */ - u8 flags; /* 91 */ - u8 _reserved4[100 - 92]; /* 92-99 */ - u32 rnsize2; /* 100-103 */ - u64 rnmax2; /* 104-111 */ - u8 _reserved5[4096 - 112]; /* 112-4095 */ -} __attribute__((packed, aligned(PAGE_SIZE))); - -static struct init_sccb __initdata early_event_mask_sccb __aligned(PAGE_SIZE); -static struct read_info_sccb __initdata early_read_info_sccb; -static int __initdata early_read_info_sccb_valid; - -u64 sclp_facilities; -static u8 sclp_fac84; -static unsigned long long rzm; -static unsigned long long rnmax; - -static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb) -{ - int rc; - - __ctl_set_bit(0, 9); - rc = sclp_service_call(cmd, sccb); - if (rc) - goto out; - __load_psw_mask(PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | - PSW_MASK_BA | PSW_MASK_EXT | PSW_MASK_WAIT); - local_irq_disable(); -out: - /* Contents of the sccb might have changed. */ - barrier(); - __ctl_clear_bit(0, 9); - return rc; -} - -static void __init sclp_read_info_early(void) -{ - int rc; - int i; - struct read_info_sccb *sccb; - sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, - SCLP_CMDW_READ_SCP_INFO}; - - sccb = &early_read_info_sccb; - for (i = 0; i < ARRAY_SIZE(commands); i++) { - do { - memset(sccb, 0, sizeof(*sccb)); - sccb->header.length = sizeof(*sccb); - sccb->header.function_code = 0x80; - sccb->header.control_mask[2] = 0x80; - rc = sclp_cmd_sync_early(commands[i], sccb); - } while (rc == -EBUSY); - - if (rc) - break; - if (sccb->header.response_code == 0x10) { - early_read_info_sccb_valid = 1; - break; - } - if (sccb->header.response_code != 0x1f0) - break; - } -} - -static void __init sclp_event_mask_early(void) -{ - struct init_sccb *sccb = &early_event_mask_sccb; - int rc; - - do { - memset(sccb, 0, sizeof(*sccb)); - sccb->header.length = sizeof(*sccb); - sccb->mask_length = sizeof(sccb_mask_t); - rc = sclp_cmd_sync_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb); - } while (rc == -EBUSY); -} - -void __init sclp_facilities_detect(void) -{ - struct read_info_sccb *sccb; - - sclp_read_info_early(); - if (!early_read_info_sccb_valid) - return; - - sccb = &early_read_info_sccb; - sclp_facilities = sccb->facilities; - sclp_fac84 = sccb->fac84; - if (sccb->fac85 & 0x02) - S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; - rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; - rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; - rzm <<= 20; - - sclp_event_mask_early(); -} - -bool __init sclp_has_linemode(void) -{ - struct init_sccb *sccb = &early_event_mask_sccb; - - if (sccb->header.response_code != 0x20) - return 0; - if (sccb->sclp_send_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)) - return 1; - return 0; -} - -bool __init sclp_has_vt220(void) -{ - struct init_sccb *sccb = &early_event_mask_sccb; - - if (sccb->header.response_code != 0x20) - return 0; - if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK) - return 1; - return 0; -} - -unsigned long long sclp_get_rnmax(void) -{ - return rnmax; -} - -unsigned long long sclp_get_rzm(void) -{ - return rzm; -} - -/* - * This function will be called after sclp_facilities_detect(), which gets - * called from early.c code. Therefore the sccb should have valid contents. - */ -void __init sclp_get_ipl_info(struct sclp_ipl_info *info) -{ - struct read_info_sccb *sccb; - - if (!early_read_info_sccb_valid) - return; - sccb = &early_read_info_sccb; - info->is_valid = 1; - if (sccb->flags & 0x2) - info->has_dump = 1; - memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN); -} - static void sclp_sync_callback(struct sclp_req *req, void *data) { struct completion *completion = data; @@ -195,7 +36,12 @@ complete(completion); } -static int do_sync_request(sclp_cmdw_t cmd, void *sccb) +int sclp_sync_request(sclp_cmdw_t cmd, void *sccb) +{ + return sclp_sync_request_timeout(cmd, sccb, 0); +} + +int sclp_sync_request_timeout(sclp_cmdw_t cmd, void *sccb, int timeout) { struct completion completion; struct sclp_req *request; @@ -204,6 +50,8 @@ request = kzalloc(sizeof(*request), GFP_KERNEL); if (!request) return -ENOMEM; + if (timeout) + request->queue_timeout = timeout; request->command = cmd; request->sccb = sccb; request->status = SCLP_REQ_FILLED; @@ -245,8 +93,8 @@ u8 reserved[4096 - 16]; } __attribute__((packed, aligned(PAGE_SIZE))); -static void sclp_fill_cpu_info(struct sclp_cpu_info *info, - struct read_cpu_info_sccb *sccb) +static void sclp_fill_core_info(struct sclp_core_info *info, + struct read_cpu_info_sccb *sccb) { char *page = (char *) sccb; @@ -254,12 +102,11 @@ info->configured = sccb->nr_configured; info->standby = sccb->nr_standby; info->combined = sccb->nr_configured + sccb->nr_standby; - info->has_cpu_type = sclp_fac84 & 0x1; - memcpy(&info->cpu, page + sccb->offset_configured, - info->combined * sizeof(struct sclp_cpu_entry)); + memcpy(&info->core, page + sccb->offset_configured, + info->combined * sizeof(struct sclp_core_entry)); } -int sclp_get_cpu_info(struct sclp_cpu_info *info) +int sclp_get_core_info(struct sclp_core_info *info) { int rc; struct read_cpu_info_sccb *sccb; @@ -270,7 +117,8 @@ if (!sccb) return -ENOMEM; sccb->header.length = sizeof(*sccb); - rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb); + rc = sclp_sync_request_timeout(SCLP_CMDW_READ_CPU_INFO, sccb, + SCLP_QUEUE_INTERVAL); if (rc) goto out; if (sccb->header.response_code != 0x0010) { @@ -279,7 +127,7 @@ rc = -EIO; goto out; } - sclp_fill_cpu_info(info, sccb); + sclp_fill_core_info(info, sccb); out: free_page((unsigned long) sccb); return rc; @@ -289,7 +137,7 @@ struct sccb_header header; } __attribute__((packed, aligned(8))); -static int do_cpu_configure(sclp_cmdw_t cmd) +static int do_core_configure(sclp_cmdw_t cmd) { struct cpu_configure_sccb *sccb; int rc; @@ -304,7 +152,7 @@ if (!sccb) return -ENOMEM; sccb->header.length = sizeof(*sccb); - rc = do_sync_request(cmd, sccb); + rc = sclp_sync_request_timeout(cmd, sccb, SCLP_QUEUE_INTERVAL); if (rc) goto out; switch (sccb->header.response_code) { @@ -323,14 +171,14 @@ return rc; } -int sclp_cpu_configure(u8 cpu) +int sclp_core_configure(u8 core) { - return do_cpu_configure(SCLP_CMDW_CONFIGURE_CPU | cpu << 8); + return do_core_configure(SCLP_CMDW_CONFIGURE_CPU | core << 8); } -int sclp_cpu_deconfigure(u8 cpu) +int sclp_core_deconfigure(u8 core) { - return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8); + return do_core_configure(SCLP_CMDW_DECONFIGURE_CPU | core << 8); } #ifdef CONFIG_MEMORY_HOTPLUG @@ -338,7 +186,7 @@ static DEFINE_MUTEX(sclp_mem_mutex); static LIST_HEAD(sclp_mem_list); static u8 sclp_max_storage_id; -static unsigned long sclp_storage_ids[256 / BITS_PER_LONG]; +static DECLARE_BITMAP(sclp_storage_ids, 256); static int sclp_mem_state_changed; struct memory_increment { @@ -354,14 +202,14 @@ int arch_get_memory_phys_device(unsigned long start_pfn) { - if (!rzm) + if (!sclp.rzm) return 0; - return PFN_PHYS(start_pfn) >> ilog2(rzm); + return PFN_PHYS(start_pfn) >> ilog2(sclp.rzm); } static unsigned long long rn2addr(u16 rn) { - return (unsigned long long) (rn - 1) * rzm; + return (unsigned long long) (rn - 1) * sclp.rzm; } static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) @@ -374,7 +222,7 @@ return -ENOMEM; sccb->header.length = PAGE_SIZE; sccb->rn = rn; - rc = do_sync_request(cmd, sccb); + rc = sclp_sync_request_timeout(cmd, sccb, SCLP_QUEUE_INTERVAL); if (rc) goto out; switch (sccb->header.response_code) { @@ -402,7 +250,7 @@ if (rc) return rc; start = rn2addr(rn); - storage_key_init_range(start, start + rzm); + storage_key_init_range(start, start + sclp.rzm); return 0; } @@ -429,7 +277,8 @@ if (!sccb) return -ENOMEM; sccb->header.length = PAGE_SIZE; - rc = do_sync_request(0x00080001 | id << 8, sccb); + rc = sclp_sync_request_timeout(0x00080001 | id << 8, sccb, + SCLP_QUEUE_INTERVAL); if (rc) goto out; switch (sccb->header.response_code) { @@ -460,16 +309,35 @@ istart = rn2addr(incr->rn); if (start + size - 1 < istart) break; - if (start > istart + rzm - 1) + if (start > istart + sclp.rzm - 1) continue; if (online) rc |= sclp_assign_storage(incr->rn); else sclp_unassign_storage(incr->rn); + if (rc == 0) + incr->standby = online ? 0 : 1; } return rc ? -EIO : 0; } +static bool contains_standby_increment(unsigned long start, unsigned long end) +{ + struct memory_increment *incr; + unsigned long istart; + + list_for_each_entry(incr, &sclp_mem_list, list) { + istart = rn2addr(incr->rn); + if (end - 1 < istart) + continue; + if (start > istart + sclp.rzm - 1) + continue; + if (incr->standby) + return true; + } + return false; +} + static int sclp_mem_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -485,8 +353,16 @@ for_each_clear_bit(id, sclp_storage_ids, sclp_max_storage_id + 1) sclp_attach_storage(id); switch (action) { - case MEM_ONLINE: case MEM_GOING_OFFLINE: + /* + * We do not allow to set memory blocks offline that contain + * standby memory. This is done to simplify the "memory online" + * case. + */ + if (contains_standby_increment(start, start + size)) + rc = -EPERM; + break; + case MEM_ONLINE: case MEM_CANCEL_OFFLINE: break; case MEM_GOING_ONLINE: @@ -512,10 +388,25 @@ .notifier_call = sclp_mem_notifier, }; +static void __init align_to_block_size(unsigned long long *start, + unsigned long long *size, + unsigned long long alignment) +{ + unsigned long long start_align, size_align; + + start_align = roundup(*start, alignment); + size_align = rounddown(*start + *size, alignment) - start_align; + + pr_info("Standby memory at 0x%llx (%lluM of %lluM usable)\n", + *start, size_align >> 20, *size >> 20); + *start = start_align; + *size = size_align; +} + static void __init add_memory_merged(u16 rn) { + unsigned long long start, size, addr, block_size; static u16 first_rn, num; - unsigned long long start, size; if (rn && first_rn && (first_rn + num == rn)) { num++; @@ -524,7 +415,7 @@ if (!first_rn) goto skip_add; start = rn2addr(first_rn); - size = (unsigned long long ) num * rzm; + size = (unsigned long long) num * sclp.rzm; if (start >= VMEM_MAX_PHYS) goto skip_add; if (start + size > VMEM_MAX_PHYS) @@ -533,7 +424,12 @@ goto skip_add; if (memory_end_set && (start + size > memory_end)) size = memory_end - start; - add_memory(0, start, size); + block_size = memory_block_size_bytes(); + align_to_block_size(&start, &size, block_size); + if (!size) + goto skip_add; + for (addr = start; addr < start + size; addr += block_size) + add_memory(numa_pfn_to_nid(PFN_DOWN(addr)), addr, block_size); skip_add: first_rn = rn; num = 1; @@ -572,7 +468,7 @@ } if (!assigned) new_incr->rn = last_rn + 1; - if (new_incr->rn > rnmax) { + if (new_incr->rn > sclp.rnmax) { kfree(new_incr); return; } @@ -615,9 +511,7 @@ if (OLDMEM_BASE) /* No standby memory in kdump mode */ return 0; - if (!early_read_info_sccb_valid) - return 0; - if ((sclp_facilities & 0xe00000000000ULL) != 0xe00000000000ULL) + if ((sclp.facilities & 0xe00000000000ULL) != 0xe00000000000ULL) return 0; rc = -ENOMEM; sccb = (void *) __get_free_page(GFP_KERNEL | GFP_DMA); @@ -627,7 +521,7 @@ for (id = 0; id <= sclp_max_storage_id; id++) { memset(sccb, 0, PAGE_SIZE); sccb->header.length = PAGE_SIZE; - rc = do_sync_request(0x00040001 | id << 8, sccb); + rc = sclp_sync_request(0x00040001 | id << 8, sccb); if (rc) goto out; switch (sccb->header.response_code) { @@ -659,7 +553,7 @@ } if (rc || list_empty(&sclp_mem_list)) goto out; - for (i = 1; i <= rnmax - assigned; i++) + for (i = 1; i <= sclp.rnmax - assigned; i++) insert_increment(0, 1, 0); rc = register_memory_notifier(&sclp_mem_nb); if (rc) @@ -668,7 +562,7 @@ if (rc) goto out; sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0); - rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; + rc = PTR_ERR_OR_ZERO(sclp_pdev); if (rc) goto out_driver; sclp_add_standby_memory(); @@ -714,7 +608,7 @@ sccb->header.length = PAGE_SIZE; sccb->atype = SCLP_RECONFIG_PCI_ATPYE; sccb->aid = fid; - rc = do_sync_request(cmd, sccb); + rc = sclp_sync_request(cmd, sccb); if (rc) goto out; switch (sccb->header.response_code) { @@ -771,7 +665,7 @@ if (!sccb) return -ENOMEM; sccb->header.length = sizeof(*sccb); - rc = do_sync_request(cmd, sccb); + rc = sclp_sync_request(cmd, sccb); if (rc) goto out; switch (sccb->header.response_code) { @@ -846,7 +740,7 @@ if (!sccb) return -ENOMEM; sccb->header.length = sizeof(*sccb); - rc = do_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb); + rc = sclp_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb); if (rc) goto out; if (sccb->header.response_code != 0x0010) {