11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Author(s)......: Carsten Otte <cotte@de.ibm.com> 31da177e4SLinus Torvalds * Rob M van der Heij <rvdheij@nl.ibm.com> 41da177e4SLinus Torvalds * Steven Shultz <shultzss@us.ibm.com> 51da177e4SLinus Torvalds * Bugreports.to..: <Linux390@de.ibm.com> 6a53c8fabSHeiko Carstens * Copyright IBM Corp. 2002, 2004 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 993098bf0SHongjie Yang #define KMSG_COMPONENT "extmem" 1093098bf0SHongjie Yang #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 1193098bf0SHongjie Yang 121da177e4SLinus Torvalds #include <linux/kernel.h> 131da177e4SLinus Torvalds #include <linux/string.h> 141da177e4SLinus Torvalds #include <linux/spinlock.h> 151da177e4SLinus Torvalds #include <linux/list.h> 161da177e4SLinus Torvalds #include <linux/slab.h> 171da177e4SLinus Torvalds #include <linux/module.h> 181da177e4SLinus Torvalds #include <linux/bootmem.h> 1936a2bd42SHeiko Carstens #include <linux/ctype.h> 20444f0e54SGerald Schaefer #include <linux/ioport.h> 211ec2772eSMartin Schwidefsky #include <asm/diag.h> 221da177e4SLinus Torvalds #include <asm/page.h> 23f4eb07c1SHeiko Carstens #include <asm/pgtable.h> 241da177e4SLinus Torvalds #include <asm/ebcdic.h> 251da177e4SLinus Torvalds #include <asm/errno.h> 261da177e4SLinus Torvalds #include <asm/extmem.h> 271da177e4SLinus Torvalds #include <asm/cpcmd.h> 2836a2bd42SHeiko Carstens #include <asm/setup.h> 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #define DCSS_LOADSHR 0x00 311da177e4SLinus Torvalds #define DCSS_LOADNSR 0x04 321da177e4SLinus Torvalds #define DCSS_PURGESEG 0x08 331da177e4SLinus Torvalds #define DCSS_FINDSEG 0x0c 341da177e4SLinus Torvalds #define DCSS_LOADNOLY 0x10 351da177e4SLinus Torvalds #define DCSS_SEGEXT 0x18 36b2300b9eSHongjie Yang #define DCSS_LOADSHRX 0x20 37b2300b9eSHongjie Yang #define DCSS_LOADNSRX 0x24 38b2300b9eSHongjie Yang #define DCSS_FINDSEGX 0x2c 39b2300b9eSHongjie Yang #define DCSS_SEGEXTX 0x38 401da177e4SLinus Torvalds #define DCSS_FINDSEGA 0x0c 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds struct qrange { 43b2300b9eSHongjie Yang unsigned long start; /* last byte type */ 44b2300b9eSHongjie Yang unsigned long end; /* last byte reserved */ 451da177e4SLinus Torvalds }; 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds struct qout64 { 48b2300b9eSHongjie Yang unsigned long segstart; 49b2300b9eSHongjie Yang unsigned long segend; 501da177e4SLinus Torvalds int segcnt; 511da177e4SLinus Torvalds int segrcnt; 521da177e4SLinus Torvalds struct qrange range[6]; 531da177e4SLinus Torvalds }; 541da177e4SLinus Torvalds 55b2300b9eSHongjie Yang struct qrange_old { 56b2300b9eSHongjie Yang unsigned int start; /* last byte type */ 57b2300b9eSHongjie Yang unsigned int end; /* last byte reserved */ 58b2300b9eSHongjie Yang }; 59b2300b9eSHongjie Yang 60b2300b9eSHongjie Yang /* output area format for the Diag x'64' old subcode x'18' */ 61b2300b9eSHongjie Yang struct qout64_old { 62b2300b9eSHongjie Yang int segstart; 63b2300b9eSHongjie Yang int segend; 64b2300b9eSHongjie Yang int segcnt; 65b2300b9eSHongjie Yang int segrcnt; 66b2300b9eSHongjie Yang struct qrange_old range[6]; 67b2300b9eSHongjie Yang }; 68b2300b9eSHongjie Yang 691da177e4SLinus Torvalds struct qin64 { 701da177e4SLinus Torvalds char qopcode; 711da177e4SLinus Torvalds char rsrv1[3]; 721da177e4SLinus Torvalds char qrcode; 731da177e4SLinus Torvalds char rsrv2[3]; 741da177e4SLinus Torvalds char qname[8]; 751da177e4SLinus Torvalds unsigned int qoutptr; 761da177e4SLinus Torvalds short int qoutlen; 771da177e4SLinus Torvalds }; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds struct dcss_segment { 801da177e4SLinus Torvalds struct list_head list; 811da177e4SLinus Torvalds char dcss_name[8]; 82444f0e54SGerald Schaefer char res_name[15]; 831da177e4SLinus Torvalds unsigned long start_addr; 841da177e4SLinus Torvalds unsigned long end; 851da177e4SLinus Torvalds atomic_t ref_count; 861da177e4SLinus Torvalds int do_nonshared; 871da177e4SLinus Torvalds unsigned int vm_segtype; 881da177e4SLinus Torvalds struct qrange range[6]; 891da177e4SLinus Torvalds int segcnt; 90444f0e54SGerald Schaefer struct resource *res; 911da177e4SLinus Torvalds }; 921da177e4SLinus Torvalds 9309252e77SHeiko Carstens static DEFINE_MUTEX(dcss_lock); 94c11ca97eSDenis Cheng static LIST_HEAD(dcss_list); 951da177e4SLinus Torvalds static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", 961da177e4SLinus Torvalds "EW/EN-MIXED" }; 97b2300b9eSHongjie Yang static int loadshr_scode, loadnsr_scode, findseg_scode; 98b2300b9eSHongjie Yang static int segext_scode, purgeseg_scode; 99b2300b9eSHongjie Yang static int scode_set; 100b2300b9eSHongjie Yang 101b2300b9eSHongjie Yang /* set correct Diag x'64' subcodes. */ 102b2300b9eSHongjie Yang static int 103b2300b9eSHongjie Yang dcss_set_subcodes(void) 104b2300b9eSHongjie Yang { 105c2f0e8c8SHeiko Carstens char *name = kmalloc(8 * sizeof(char), GFP_KERNEL | GFP_DMA); 106b2300b9eSHongjie Yang unsigned long rx, ry; 107b2300b9eSHongjie Yang int rc; 108b2300b9eSHongjie Yang 109b2300b9eSHongjie Yang if (name == NULL) 110b2300b9eSHongjie Yang return -ENOMEM; 111b2300b9eSHongjie Yang 112b2300b9eSHongjie Yang rx = (unsigned long) name; 113b2300b9eSHongjie Yang ry = DCSS_FINDSEGX; 114b2300b9eSHongjie Yang 115b2300b9eSHongjie Yang strcpy(name, "dummy"); 1161ec2772eSMartin Schwidefsky diag_stat_inc(DIAG_STAT_X064); 117b2300b9eSHongjie Yang asm volatile( 118b2300b9eSHongjie Yang " diag %0,%1,0x64\n" 119b2300b9eSHongjie Yang "0: ipm %2\n" 120b2300b9eSHongjie Yang " srl %2,28\n" 121b2300b9eSHongjie Yang " j 2f\n" 122b2300b9eSHongjie Yang "1: la %2,3\n" 123b2300b9eSHongjie Yang "2:\n" 124b2300b9eSHongjie Yang EX_TABLE(0b, 1b) 125b2300b9eSHongjie Yang : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); 126b2300b9eSHongjie Yang 127b2300b9eSHongjie Yang kfree(name); 128b2300b9eSHongjie Yang /* Diag x'64' new subcodes are supported, set to new subcodes */ 129b2300b9eSHongjie Yang if (rc != 3) { 130b2300b9eSHongjie Yang loadshr_scode = DCSS_LOADSHRX; 131b2300b9eSHongjie Yang loadnsr_scode = DCSS_LOADNSRX; 132b2300b9eSHongjie Yang purgeseg_scode = DCSS_PURGESEG; 133b2300b9eSHongjie Yang findseg_scode = DCSS_FINDSEGX; 134b2300b9eSHongjie Yang segext_scode = DCSS_SEGEXTX; 135b2300b9eSHongjie Yang return 0; 136b2300b9eSHongjie Yang } 137b2300b9eSHongjie Yang /* Diag x'64' new subcodes are not supported, set to old subcodes */ 138b2300b9eSHongjie Yang loadshr_scode = DCSS_LOADNOLY; 139b2300b9eSHongjie Yang loadnsr_scode = DCSS_LOADNSR; 140b2300b9eSHongjie Yang purgeseg_scode = DCSS_PURGESEG; 141b2300b9eSHongjie Yang findseg_scode = DCSS_FINDSEG; 142b2300b9eSHongjie Yang segext_scode = DCSS_SEGEXT; 143b2300b9eSHongjie Yang return 0; 144b2300b9eSHongjie Yang } 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds /* 1471da177e4SLinus Torvalds * Create the 8 bytes, ebcdic VM segment name from 1481da177e4SLinus Torvalds * an ascii name. 1491da177e4SLinus Torvalds */ 1504d284cacSHeiko Carstens static void 1511da177e4SLinus Torvalds dcss_mkname(char *name, char *dcss_name) 1521da177e4SLinus Torvalds { 1531da177e4SLinus Torvalds int i; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds for (i = 0; i < 8; i++) { 1561da177e4SLinus Torvalds if (name[i] == '\0') 1571da177e4SLinus Torvalds break; 1581da177e4SLinus Torvalds dcss_name[i] = toupper(name[i]); 1591da177e4SLinus Torvalds }; 1601da177e4SLinus Torvalds for (; i < 8; i++) 1611da177e4SLinus Torvalds dcss_name[i] = ' '; 1621da177e4SLinus Torvalds ASCEBC(dcss_name, 8); 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds /* 1671da177e4SLinus Torvalds * search all segments in dcss_list, and return the one 1681da177e4SLinus Torvalds * namend *name. If not found, return NULL. 1691da177e4SLinus Torvalds */ 1701da177e4SLinus Torvalds static struct dcss_segment * 1711da177e4SLinus Torvalds segment_by_name (char *name) 1721da177e4SLinus Torvalds { 1731da177e4SLinus Torvalds char dcss_name[9]; 1741da177e4SLinus Torvalds struct list_head *l; 1751da177e4SLinus Torvalds struct dcss_segment *tmp, *retval = NULL; 1761da177e4SLinus Torvalds 17709252e77SHeiko Carstens BUG_ON(!mutex_is_locked(&dcss_lock)); 1781da177e4SLinus Torvalds dcss_mkname (name, dcss_name); 1791da177e4SLinus Torvalds list_for_each (l, &dcss_list) { 1801da177e4SLinus Torvalds tmp = list_entry (l, struct dcss_segment, list); 1811da177e4SLinus Torvalds if (memcmp(tmp->dcss_name, dcss_name, 8) == 0) { 1821da177e4SLinus Torvalds retval = tmp; 1831da177e4SLinus Torvalds break; 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds } 1861da177e4SLinus Torvalds return retval; 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds /* 1911da177e4SLinus Torvalds * Perform a function on a dcss segment. 1921da177e4SLinus Torvalds */ 1931da177e4SLinus Torvalds static inline int 194b2300b9eSHongjie Yang dcss_diag(int *func, void *parameter, 1951da177e4SLinus Torvalds unsigned long *ret1, unsigned long *ret2) 1961da177e4SLinus Torvalds { 1971da177e4SLinus Torvalds unsigned long rx, ry; 1981da177e4SLinus Torvalds int rc; 1991da177e4SLinus Torvalds 200b2300b9eSHongjie Yang if (scode_set == 0) { 201b2300b9eSHongjie Yang rc = dcss_set_subcodes(); 202b2300b9eSHongjie Yang if (rc < 0) 203b2300b9eSHongjie Yang return rc; 204b2300b9eSHongjie Yang scode_set = 1; 205b2300b9eSHongjie Yang } 2061da177e4SLinus Torvalds rx = (unsigned long) parameter; 207b2300b9eSHongjie Yang ry = (unsigned long) *func; 208b2300b9eSHongjie Yang 209b2300b9eSHongjie Yang /* 64-bit Diag x'64' new subcode, keep in 64-bit addressing mode */ 2101ec2772eSMartin Schwidefsky diag_stat_inc(DIAG_STAT_X064); 211b2300b9eSHongjie Yang if (*func > DCSS_SEGEXT) 212b2300b9eSHongjie Yang asm volatile( 2131da177e4SLinus Torvalds " diag %0,%1,0x64\n" 2141da177e4SLinus Torvalds " ipm %2\n" 2151da177e4SLinus Torvalds " srl %2,28\n" 2161da177e4SLinus Torvalds : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); 217b2300b9eSHongjie Yang /* 31-bit Diag x'64' old subcode, switch to 31-bit addressing mode */ 218b2300b9eSHongjie Yang else 219b2300b9eSHongjie Yang asm volatile( 220b2300b9eSHongjie Yang " sam31\n" 221b2300b9eSHongjie Yang " diag %0,%1,0x64\n" 222b2300b9eSHongjie Yang " sam64\n" 223b2300b9eSHongjie Yang " ipm %2\n" 224b2300b9eSHongjie Yang " srl %2,28\n" 225b2300b9eSHongjie Yang : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); 2261da177e4SLinus Torvalds *ret1 = rx; 2271da177e4SLinus Torvalds *ret2 = ry; 2281da177e4SLinus Torvalds return rc; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds static inline int 2321da177e4SLinus Torvalds dcss_diag_translate_rc (int vm_rc) { 2331da177e4SLinus Torvalds if (vm_rc == 44) 2341da177e4SLinus Torvalds return -ENOENT; 2351da177e4SLinus Torvalds return -EIO; 2361da177e4SLinus Torvalds } 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds /* do a diag to get info about a segment. 2401da177e4SLinus Torvalds * fills start_address, end and vm_segtype fields 2411da177e4SLinus Torvalds */ 2421da177e4SLinus Torvalds static int 2431da177e4SLinus Torvalds query_segment_type (struct dcss_segment *seg) 2441da177e4SLinus Torvalds { 2451da177e4SLinus Torvalds unsigned long dummy, vmrc; 246c2f0e8c8SHeiko Carstens int diag_cc, rc, i; 247c2f0e8c8SHeiko Carstens struct qout64 *qout; 248c2f0e8c8SHeiko Carstens struct qin64 *qin; 2491da177e4SLinus Torvalds 250c2f0e8c8SHeiko Carstens qin = kmalloc(sizeof(*qin), GFP_KERNEL | GFP_DMA); 251c2f0e8c8SHeiko Carstens qout = kmalloc(sizeof(*qout), GFP_KERNEL | GFP_DMA); 2521da177e4SLinus Torvalds if ((qin == NULL) || (qout == NULL)) { 2531da177e4SLinus Torvalds rc = -ENOMEM; 2541da177e4SLinus Torvalds goto out_free; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds /* initialize diag input parameters */ 2581da177e4SLinus Torvalds qin->qopcode = DCSS_FINDSEGA; 2591da177e4SLinus Torvalds qin->qoutptr = (unsigned long) qout; 2601da177e4SLinus Torvalds qin->qoutlen = sizeof(struct qout64); 2611da177e4SLinus Torvalds memcpy (qin->qname, seg->dcss_name, 8); 2621da177e4SLinus Torvalds 263b2300b9eSHongjie Yang diag_cc = dcss_diag(&segext_scode, qin, &dummy, &vmrc); 2641da177e4SLinus Torvalds 265b2300b9eSHongjie Yang if (diag_cc < 0) { 266b2300b9eSHongjie Yang rc = diag_cc; 267b2300b9eSHongjie Yang goto out_free; 268b2300b9eSHongjie Yang } 2691da177e4SLinus Torvalds if (diag_cc > 1) { 27093098bf0SHongjie Yang pr_warning("Querying a DCSS type failed with rc=%ld\n", vmrc); 2711da177e4SLinus Torvalds rc = dcss_diag_translate_rc (vmrc); 2721da177e4SLinus Torvalds goto out_free; 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds 275b2300b9eSHongjie Yang /* Only old format of output area of Diagnose x'64' is supported, 276b2300b9eSHongjie Yang copy data for the new format. */ 277b2300b9eSHongjie Yang if (segext_scode == DCSS_SEGEXT) { 278b2300b9eSHongjie Yang struct qout64_old *qout_old; 279c2f0e8c8SHeiko Carstens qout_old = kzalloc(sizeof(*qout_old), GFP_KERNEL | GFP_DMA); 280b2300b9eSHongjie Yang if (qout_old == NULL) { 281b2300b9eSHongjie Yang rc = -ENOMEM; 282b2300b9eSHongjie Yang goto out_free; 283b2300b9eSHongjie Yang } 284b2300b9eSHongjie Yang memcpy(qout_old, qout, sizeof(struct qout64_old)); 285b2300b9eSHongjie Yang qout->segstart = (unsigned long) qout_old->segstart; 286b2300b9eSHongjie Yang qout->segend = (unsigned long) qout_old->segend; 287b2300b9eSHongjie Yang qout->segcnt = qout_old->segcnt; 288b2300b9eSHongjie Yang qout->segrcnt = qout_old->segrcnt; 289b2300b9eSHongjie Yang 290b2300b9eSHongjie Yang if (qout->segcnt > 6) 291b2300b9eSHongjie Yang qout->segrcnt = 6; 292b2300b9eSHongjie Yang for (i = 0; i < qout->segrcnt; i++) { 293b2300b9eSHongjie Yang qout->range[i].start = 294b2300b9eSHongjie Yang (unsigned long) qout_old->range[i].start; 295b2300b9eSHongjie Yang qout->range[i].end = 296b2300b9eSHongjie Yang (unsigned long) qout_old->range[i].end; 297b2300b9eSHongjie Yang } 298b2300b9eSHongjie Yang kfree(qout_old); 299b2300b9eSHongjie Yang } 3001da177e4SLinus Torvalds if (qout->segcnt > 6) { 301b8e660b8SHeiko Carstens rc = -EOPNOTSUPP; 3021da177e4SLinus Torvalds goto out_free; 3031da177e4SLinus Torvalds } 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds if (qout->segcnt == 1) { 3061da177e4SLinus Torvalds seg->vm_segtype = qout->range[0].start & 0xff; 3071da177e4SLinus Torvalds } else { 3081da177e4SLinus Torvalds /* multi-part segment. only one type supported here: 3091da177e4SLinus Torvalds - all parts are contiguous 3101da177e4SLinus Torvalds - all parts are either EW or EN type 3111da177e4SLinus Torvalds - maximum 6 parts allowed */ 3121da177e4SLinus Torvalds unsigned long start = qout->segstart >> PAGE_SHIFT; 3131da177e4SLinus Torvalds for (i=0; i<qout->segcnt; i++) { 3141da177e4SLinus Torvalds if (((qout->range[i].start & 0xff) != SEG_TYPE_EW) && 3151da177e4SLinus Torvalds ((qout->range[i].start & 0xff) != SEG_TYPE_EN)) { 316b8e660b8SHeiko Carstens rc = -EOPNOTSUPP; 3171da177e4SLinus Torvalds goto out_free; 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds if (start != qout->range[i].start >> PAGE_SHIFT) { 320b8e660b8SHeiko Carstens rc = -EOPNOTSUPP; 3211da177e4SLinus Torvalds goto out_free; 3221da177e4SLinus Torvalds } 3231da177e4SLinus Torvalds start = (qout->range[i].end >> PAGE_SHIFT) + 1; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds seg->vm_segtype = SEG_TYPE_EWEN; 3261da177e4SLinus Torvalds } 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds /* analyze diag output and update seg */ 3291da177e4SLinus Torvalds seg->start_addr = qout->segstart; 3301da177e4SLinus Torvalds seg->end = qout->segend; 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds memcpy (seg->range, qout->range, 6*sizeof(struct qrange)); 3331da177e4SLinus Torvalds seg->segcnt = qout->segcnt; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds rc = 0; 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds out_free: 338b2325fe1SJesper Juhl kfree(qin); 339b2325fe1SJesper Juhl kfree(qout); 3401da177e4SLinus Torvalds return rc; 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds /* 3441da177e4SLinus Torvalds * get info about a segment 3451da177e4SLinus Torvalds * possible return values: 3461da177e4SLinus Torvalds * -ENOSYS : we are not running on VM 3471da177e4SLinus Torvalds * -EIO : could not perform query diagnose 3481da177e4SLinus Torvalds * -ENOENT : no such segment 349b8e660b8SHeiko Carstens * -EOPNOTSUPP: multi-part segment cannot be used with linux 3501da177e4SLinus Torvalds * -ENOMEM : out of memory 3511da177e4SLinus Torvalds * 0 .. 6 : type of segment as defined in include/asm-s390/extmem.h 3521da177e4SLinus Torvalds */ 3531da177e4SLinus Torvalds int 3541da177e4SLinus Torvalds segment_type (char* name) 3551da177e4SLinus Torvalds { 3561da177e4SLinus Torvalds int rc; 3571da177e4SLinus Torvalds struct dcss_segment seg; 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds if (!MACHINE_IS_VM) 3601da177e4SLinus Torvalds return -ENOSYS; 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds dcss_mkname(name, seg.dcss_name); 3631da177e4SLinus Torvalds rc = query_segment_type (&seg); 3641da177e4SLinus Torvalds if (rc < 0) 3651da177e4SLinus Torvalds return rc; 3661da177e4SLinus Torvalds return seg.vm_segtype; 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds /* 370b2300b9eSHongjie Yang * check if segment collides with other segments that are currently loaded 371b2300b9eSHongjie Yang * returns 1 if this is the case, 0 if no collision was found 372b2300b9eSHongjie Yang */ 373b2300b9eSHongjie Yang static int 374b2300b9eSHongjie Yang segment_overlaps_others (struct dcss_segment *seg) 375b2300b9eSHongjie Yang { 376b2300b9eSHongjie Yang struct list_head *l; 377b2300b9eSHongjie Yang struct dcss_segment *tmp; 378b2300b9eSHongjie Yang 379b2300b9eSHongjie Yang BUG_ON(!mutex_is_locked(&dcss_lock)); 380b2300b9eSHongjie Yang list_for_each(l, &dcss_list) { 381b2300b9eSHongjie Yang tmp = list_entry(l, struct dcss_segment, list); 382b2300b9eSHongjie Yang if ((tmp->start_addr >> 20) > (seg->end >> 20)) 383b2300b9eSHongjie Yang continue; 384b2300b9eSHongjie Yang if ((tmp->end >> 20) < (seg->start_addr >> 20)) 385b2300b9eSHongjie Yang continue; 386b2300b9eSHongjie Yang if (seg == tmp) 387b2300b9eSHongjie Yang continue; 388b2300b9eSHongjie Yang return 1; 389b2300b9eSHongjie Yang } 390b2300b9eSHongjie Yang return 0; 391b2300b9eSHongjie Yang } 392b2300b9eSHongjie Yang 393b2300b9eSHongjie Yang /* 3941da177e4SLinus Torvalds * real segment loading function, called from segment_load 3951da177e4SLinus Torvalds */ 3961da177e4SLinus Torvalds static int 3971da177e4SLinus Torvalds __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end) 3981da177e4SLinus Torvalds { 399b2300b9eSHongjie Yang unsigned long start_addr, end_addr, dummy; 400c2f0e8c8SHeiko Carstens struct dcss_segment *seg; 401c2f0e8c8SHeiko Carstens int rc, diag_cc; 4021da177e4SLinus Torvalds 40389db4df1SHeiko Carstens start_addr = end_addr = 0; 404c2f0e8c8SHeiko Carstens seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA); 4051da177e4SLinus Torvalds if (seg == NULL) { 4061da177e4SLinus Torvalds rc = -ENOMEM; 4071da177e4SLinus Torvalds goto out; 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds dcss_mkname (name, seg->dcss_name); 4101da177e4SLinus Torvalds rc = query_segment_type (seg); 4111da177e4SLinus Torvalds if (rc < 0) 4121da177e4SLinus Torvalds goto out_free; 413f4eb07c1SHeiko Carstens 414b2300b9eSHongjie Yang if (loadshr_scode == DCSS_LOADSHRX) { 415b2300b9eSHongjie Yang if (segment_overlaps_others(seg)) { 416b2300b9eSHongjie Yang rc = -EBUSY; 417b2300b9eSHongjie Yang goto out_free; 418b2300b9eSHongjie Yang } 419b2300b9eSHongjie Yang } 420b2300b9eSHongjie Yang 42117f34580SHeiko Carstens rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1); 422f4eb07c1SHeiko Carstens 423ca68305bSMartin Schwidefsky if (rc) 424f4eb07c1SHeiko Carstens goto out_free; 425f4eb07c1SHeiko Carstens 426444f0e54SGerald Schaefer seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL); 427444f0e54SGerald Schaefer if (seg->res == NULL) { 428444f0e54SGerald Schaefer rc = -ENOMEM; 429444f0e54SGerald Schaefer goto out_shared; 430444f0e54SGerald Schaefer } 431444f0e54SGerald Schaefer seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; 432444f0e54SGerald Schaefer seg->res->start = seg->start_addr; 433444f0e54SGerald Schaefer seg->res->end = seg->end; 434444f0e54SGerald Schaefer memcpy(&seg->res_name, seg->dcss_name, 8); 435444f0e54SGerald Schaefer EBCASC(seg->res_name, 8); 436444f0e54SGerald Schaefer seg->res_name[8] = '\0'; 437444f0e54SGerald Schaefer strncat(seg->res_name, " (DCSS)", 7); 438444f0e54SGerald Schaefer seg->res->name = seg->res_name; 439444f0e54SGerald Schaefer rc = seg->vm_segtype; 440444f0e54SGerald Schaefer if (rc == SEG_TYPE_SC || 441444f0e54SGerald Schaefer ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared)) 442444f0e54SGerald Schaefer seg->res->flags |= IORESOURCE_READONLY; 443444f0e54SGerald Schaefer if (request_resource(&iomem_resource, seg->res)) { 444444f0e54SGerald Schaefer rc = -EBUSY; 445444f0e54SGerald Schaefer kfree(seg->res); 446444f0e54SGerald Schaefer goto out_shared; 447444f0e54SGerald Schaefer } 448444f0e54SGerald Schaefer 4491da177e4SLinus Torvalds if (do_nonshared) 450b2300b9eSHongjie Yang diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name, 451b2300b9eSHongjie Yang &start_addr, &end_addr); 4521da177e4SLinus Torvalds else 453b2300b9eSHongjie Yang diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name, 454b2300b9eSHongjie Yang &start_addr, &end_addr); 455b2300b9eSHongjie Yang if (diag_cc < 0) { 456b2300b9eSHongjie Yang dcss_diag(&purgeseg_scode, seg->dcss_name, 457b2300b9eSHongjie Yang &dummy, &dummy); 458b2300b9eSHongjie Yang rc = diag_cc; 459444f0e54SGerald Schaefer goto out_resource; 4601da177e4SLinus Torvalds } 461b2300b9eSHongjie Yang if (diag_cc > 1) { 46293098bf0SHongjie Yang pr_warning("Loading DCSS %s failed with rc=%ld\n", name, 46393098bf0SHongjie Yang end_addr); 464b2300b9eSHongjie Yang rc = dcss_diag_translate_rc(end_addr); 465b2300b9eSHongjie Yang dcss_diag(&purgeseg_scode, seg->dcss_name, 466b2300b9eSHongjie Yang &dummy, &dummy); 467b2300b9eSHongjie Yang goto out_resource; 468b2300b9eSHongjie Yang } 469b2300b9eSHongjie Yang seg->start_addr = start_addr; 470b2300b9eSHongjie Yang seg->end = end_addr; 4711da177e4SLinus Torvalds seg->do_nonshared = do_nonshared; 4721da177e4SLinus Torvalds atomic_set(&seg->ref_count, 1); 4731da177e4SLinus Torvalds list_add(&seg->list, &dcss_list); 4741da177e4SLinus Torvalds *addr = seg->start_addr; 4751da177e4SLinus Torvalds *end = seg->end; 4761da177e4SLinus Torvalds if (do_nonshared) 47793098bf0SHongjie Yang pr_info("DCSS %s of range %p to %p and type %s loaded as " 47893098bf0SHongjie Yang "exclusive-writable\n", name, (void*) seg->start_addr, 47993098bf0SHongjie Yang (void*) seg->end, segtype_string[seg->vm_segtype]); 480444f0e54SGerald Schaefer else { 48193098bf0SHongjie Yang pr_info("DCSS %s of range %p to %p and type %s loaded in " 48293098bf0SHongjie Yang "shared access mode\n", name, (void*) seg->start_addr, 48393098bf0SHongjie Yang (void*) seg->end, segtype_string[seg->vm_segtype]); 484444f0e54SGerald Schaefer } 4851da177e4SLinus Torvalds goto out; 486444f0e54SGerald Schaefer out_resource: 487444f0e54SGerald Schaefer release_resource(seg->res); 488444f0e54SGerald Schaefer kfree(seg->res); 489f4eb07c1SHeiko Carstens out_shared: 49017f34580SHeiko Carstens vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1); 4911da177e4SLinus Torvalds out_free: 4921da177e4SLinus Torvalds kfree(seg); 4931da177e4SLinus Torvalds out: 4941da177e4SLinus Torvalds return rc; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds /* 4981da177e4SLinus Torvalds * this function loads a DCSS segment 4991da177e4SLinus Torvalds * name : name of the DCSS 5001da177e4SLinus Torvalds * do_nonshared : 0 indicates that the dcss should be shared with other linux images 5011da177e4SLinus Torvalds * 1 indicates that the dcss should be exclusive for this linux image 5021da177e4SLinus Torvalds * addr : will be filled with start address of the segment 5031da177e4SLinus Torvalds * end : will be filled with end address of the segment 5041da177e4SLinus Torvalds * return values: 5051da177e4SLinus Torvalds * -ENOSYS : we are not running on VM 5061da177e4SLinus Torvalds * -EIO : could not perform query or load diagnose 5071da177e4SLinus Torvalds * -ENOENT : no such segment 508b8e660b8SHeiko Carstens * -EOPNOTSUPP: multi-part segment cannot be used with linux 5091da177e4SLinus Torvalds * -ENOSPC : segment cannot be used (overlaps with storage) 5101da177e4SLinus Torvalds * -EBUSY : segment can temporarily not be used (overlaps with dcss) 5111da177e4SLinus Torvalds * -ERANGE : segment cannot be used (exceeds kernel mapping range) 5121da177e4SLinus Torvalds * -EPERM : segment is currently loaded with incompatible permissions 5131da177e4SLinus Torvalds * -ENOMEM : out of memory 5141da177e4SLinus Torvalds * 0 .. 6 : type of segment as defined in include/asm-s390/extmem.h 5151da177e4SLinus Torvalds */ 5161da177e4SLinus Torvalds int 5171da177e4SLinus Torvalds segment_load (char *name, int do_nonshared, unsigned long *addr, 5181da177e4SLinus Torvalds unsigned long *end) 5191da177e4SLinus Torvalds { 5201da177e4SLinus Torvalds struct dcss_segment *seg; 5211da177e4SLinus Torvalds int rc; 5221da177e4SLinus Torvalds 5231da177e4SLinus Torvalds if (!MACHINE_IS_VM) 5241da177e4SLinus Torvalds return -ENOSYS; 5251da177e4SLinus Torvalds 52609252e77SHeiko Carstens mutex_lock(&dcss_lock); 5271da177e4SLinus Torvalds seg = segment_by_name (name); 5281da177e4SLinus Torvalds if (seg == NULL) 5291da177e4SLinus Torvalds rc = __segment_load (name, do_nonshared, addr, end); 5301da177e4SLinus Torvalds else { 5311da177e4SLinus Torvalds if (do_nonshared == seg->do_nonshared) { 5321da177e4SLinus Torvalds atomic_inc(&seg->ref_count); 5331da177e4SLinus Torvalds *addr = seg->start_addr; 5341da177e4SLinus Torvalds *end = seg->end; 5351da177e4SLinus Torvalds rc = seg->vm_segtype; 5361da177e4SLinus Torvalds } else { 5371da177e4SLinus Torvalds *addr = *end = 0; 5381da177e4SLinus Torvalds rc = -EPERM; 5391da177e4SLinus Torvalds } 5401da177e4SLinus Torvalds } 54109252e77SHeiko Carstens mutex_unlock(&dcss_lock); 5421da177e4SLinus Torvalds return rc; 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds 5451da177e4SLinus Torvalds /* 5461da177e4SLinus Torvalds * this function modifies the shared state of a DCSS segment. note that 5471da177e4SLinus Torvalds * name : name of the DCSS 5481da177e4SLinus Torvalds * do_nonshared : 0 indicates that the dcss should be shared with other linux images 5491da177e4SLinus Torvalds * 1 indicates that the dcss should be exclusive for this linux image 5501da177e4SLinus Torvalds * return values: 5511da177e4SLinus Torvalds * -EIO : could not perform load diagnose (segment gone!) 5521da177e4SLinus Torvalds * -ENOENT : no such segment (segment gone!) 5531da177e4SLinus Torvalds * -EAGAIN : segment is in use by other exploiters, try later 5541da177e4SLinus Torvalds * -EINVAL : no segment with the given name is currently loaded - name invalid 555444f0e54SGerald Schaefer * -EBUSY : segment can temporarily not be used (overlaps with dcss) 5561da177e4SLinus Torvalds * 0 : operation succeeded 5571da177e4SLinus Torvalds */ 5581da177e4SLinus Torvalds int 5591da177e4SLinus Torvalds segment_modify_shared (char *name, int do_nonshared) 5601da177e4SLinus Torvalds { 5611da177e4SLinus Torvalds struct dcss_segment *seg; 562b2300b9eSHongjie Yang unsigned long start_addr, end_addr, dummy; 563b2300b9eSHongjie Yang int rc, diag_cc; 5641da177e4SLinus Torvalds 56589db4df1SHeiko Carstens start_addr = end_addr = 0; 56609252e77SHeiko Carstens mutex_lock(&dcss_lock); 5671da177e4SLinus Torvalds seg = segment_by_name (name); 5681da177e4SLinus Torvalds if (seg == NULL) { 5691da177e4SLinus Torvalds rc = -EINVAL; 5701da177e4SLinus Torvalds goto out_unlock; 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds if (do_nonshared == seg->do_nonshared) { 57393098bf0SHongjie Yang pr_info("DCSS %s is already in the requested access " 57493098bf0SHongjie Yang "mode\n", name); 5751da177e4SLinus Torvalds rc = 0; 5761da177e4SLinus Torvalds goto out_unlock; 5771da177e4SLinus Torvalds } 5781da177e4SLinus Torvalds if (atomic_read (&seg->ref_count) != 1) { 57993098bf0SHongjie Yang pr_warning("DCSS %s is in use and cannot be reloaded\n", 58093098bf0SHongjie Yang name); 5811da177e4SLinus Torvalds rc = -EAGAIN; 5821da177e4SLinus Torvalds goto out_unlock; 5831da177e4SLinus Torvalds } 584444f0e54SGerald Schaefer release_resource(seg->res); 585b2300b9eSHongjie Yang if (do_nonshared) 586444f0e54SGerald Schaefer seg->res->flags &= ~IORESOURCE_READONLY; 587b2300b9eSHongjie Yang else 588444f0e54SGerald Schaefer if (seg->vm_segtype == SEG_TYPE_SR || 589444f0e54SGerald Schaefer seg->vm_segtype == SEG_TYPE_ER) 590444f0e54SGerald Schaefer seg->res->flags |= IORESOURCE_READONLY; 591b2300b9eSHongjie Yang 592444f0e54SGerald Schaefer if (request_resource(&iomem_resource, seg->res)) { 59393098bf0SHongjie Yang pr_warning("DCSS %s overlaps with used memory resources " 59493098bf0SHongjie Yang "and cannot be reloaded\n", name); 595444f0e54SGerald Schaefer rc = -EBUSY; 596444f0e54SGerald Schaefer kfree(seg->res); 597b2300b9eSHongjie Yang goto out_del_mem; 598444f0e54SGerald Schaefer } 599b2300b9eSHongjie Yang 600b2300b9eSHongjie Yang dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); 601b2300b9eSHongjie Yang if (do_nonshared) 602b2300b9eSHongjie Yang diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name, 603b2300b9eSHongjie Yang &start_addr, &end_addr); 604b2300b9eSHongjie Yang else 605b2300b9eSHongjie Yang diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name, 606b2300b9eSHongjie Yang &start_addr, &end_addr); 607b2300b9eSHongjie Yang if (diag_cc < 0) { 608b2300b9eSHongjie Yang rc = diag_cc; 609b2300b9eSHongjie Yang goto out_del_res; 610b2300b9eSHongjie Yang } 6111da177e4SLinus Torvalds if (diag_cc > 1) { 61293098bf0SHongjie Yang pr_warning("Reloading DCSS %s failed with rc=%ld\n", name, 61393098bf0SHongjie Yang end_addr); 614b2300b9eSHongjie Yang rc = dcss_diag_translate_rc(end_addr); 615b2300b9eSHongjie Yang goto out_del_res; 6161da177e4SLinus Torvalds } 617b2300b9eSHongjie Yang seg->start_addr = start_addr; 618b2300b9eSHongjie Yang seg->end = end_addr; 6191da177e4SLinus Torvalds seg->do_nonshared = do_nonshared; 6201da177e4SLinus Torvalds rc = 0; 6211da177e4SLinus Torvalds goto out_unlock; 622b2300b9eSHongjie Yang out_del_res: 623b2300b9eSHongjie Yang release_resource(seg->res); 624b2300b9eSHongjie Yang kfree(seg->res); 625b2300b9eSHongjie Yang out_del_mem: 62617f34580SHeiko Carstens vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1); 6271da177e4SLinus Torvalds list_del(&seg->list); 628b2300b9eSHongjie Yang dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); 6291da177e4SLinus Torvalds kfree(seg); 6301da177e4SLinus Torvalds out_unlock: 63109252e77SHeiko Carstens mutex_unlock(&dcss_lock); 6321da177e4SLinus Torvalds return rc; 6331da177e4SLinus Torvalds } 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds /* 6361da177e4SLinus Torvalds * Decrease the use count of a DCSS segment and remove 6371da177e4SLinus Torvalds * it from the address space if nobody is using it 6381da177e4SLinus Torvalds * any longer. 6391da177e4SLinus Torvalds */ 6401da177e4SLinus Torvalds void 6411da177e4SLinus Torvalds segment_unload(char *name) 6421da177e4SLinus Torvalds { 6431da177e4SLinus Torvalds unsigned long dummy; 6441da177e4SLinus Torvalds struct dcss_segment *seg; 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds if (!MACHINE_IS_VM) 6471da177e4SLinus Torvalds return; 6481da177e4SLinus Torvalds 64909252e77SHeiko Carstens mutex_lock(&dcss_lock); 6501da177e4SLinus Torvalds seg = segment_by_name (name); 6511da177e4SLinus Torvalds if (seg == NULL) { 65293098bf0SHongjie Yang pr_err("Unloading unknown DCSS %s failed\n", name); 6531da177e4SLinus Torvalds goto out_unlock; 6541da177e4SLinus Torvalds } 655f4eb07c1SHeiko Carstens if (atomic_dec_return(&seg->ref_count) != 0) 656f4eb07c1SHeiko Carstens goto out_unlock; 657444f0e54SGerald Schaefer release_resource(seg->res); 658444f0e54SGerald Schaefer kfree(seg->res); 65917f34580SHeiko Carstens vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1); 6601da177e4SLinus Torvalds list_del(&seg->list); 661b2300b9eSHongjie Yang dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); 6621da177e4SLinus Torvalds kfree(seg); 6631da177e4SLinus Torvalds out_unlock: 66409252e77SHeiko Carstens mutex_unlock(&dcss_lock); 6651da177e4SLinus Torvalds } 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds /* 6681da177e4SLinus Torvalds * save segment content permanently 6691da177e4SLinus Torvalds */ 6701da177e4SLinus Torvalds void 6711da177e4SLinus Torvalds segment_save(char *name) 6721da177e4SLinus Torvalds { 6731da177e4SLinus Torvalds struct dcss_segment *seg; 6741da177e4SLinus Torvalds char cmd1[160]; 6751da177e4SLinus Torvalds char cmd2[80]; 6769b5dec1aSGerald Schaefer int i, response; 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds if (!MACHINE_IS_VM) 6791da177e4SLinus Torvalds return; 6801da177e4SLinus Torvalds 68109252e77SHeiko Carstens mutex_lock(&dcss_lock); 6821da177e4SLinus Torvalds seg = segment_by_name (name); 6831da177e4SLinus Torvalds 6841da177e4SLinus Torvalds if (seg == NULL) { 68593098bf0SHongjie Yang pr_err("Saving unknown DCSS %s failed\n", name); 6866b4044bdSHeiko Carstens goto out; 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds sprintf(cmd1, "DEFSEG %s", name); 6901da177e4SLinus Torvalds for (i=0; i<seg->segcnt; i++) { 691b2300b9eSHongjie Yang sprintf(cmd1+strlen(cmd1), " %lX-%lX %s", 6921da177e4SLinus Torvalds seg->range[i].start >> PAGE_SHIFT, 6931da177e4SLinus Torvalds seg->range[i].end >> PAGE_SHIFT, 6941da177e4SLinus Torvalds segtype_string[seg->range[i].start & 0xff]); 6951da177e4SLinus Torvalds } 6961da177e4SLinus Torvalds sprintf(cmd2, "SAVESEG %s", name); 6979b5dec1aSGerald Schaefer response = 0; 6989b5dec1aSGerald Schaefer cpcmd(cmd1, NULL, 0, &response); 6999b5dec1aSGerald Schaefer if (response) { 70093098bf0SHongjie Yang pr_err("Saving a DCSS failed with DEFSEG response code " 70193098bf0SHongjie Yang "%i\n", response); 7029b5dec1aSGerald Schaefer goto out; 7039b5dec1aSGerald Schaefer } 7049b5dec1aSGerald Schaefer cpcmd(cmd2, NULL, 0, &response); 7059b5dec1aSGerald Schaefer if (response) { 70693098bf0SHongjie Yang pr_err("Saving a DCSS failed with SAVESEG response code " 70793098bf0SHongjie Yang "%i\n", response); 7089b5dec1aSGerald Schaefer goto out; 7099b5dec1aSGerald Schaefer } 7109b5dec1aSGerald Schaefer out: 71109252e77SHeiko Carstens mutex_unlock(&dcss_lock); 7121da177e4SLinus Torvalds } 7131da177e4SLinus Torvalds 714ca68305bSMartin Schwidefsky /* 715ca68305bSMartin Schwidefsky * print appropriate error message for segment_load()/segment_type() 716ca68305bSMartin Schwidefsky * return code 717ca68305bSMartin Schwidefsky */ 718ca68305bSMartin Schwidefsky void segment_warning(int rc, char *seg_name) 719ca68305bSMartin Schwidefsky { 720ca68305bSMartin Schwidefsky switch (rc) { 721ca68305bSMartin Schwidefsky case -ENOENT: 72293098bf0SHongjie Yang pr_err("DCSS %s cannot be loaded or queried\n", seg_name); 723ca68305bSMartin Schwidefsky break; 724ca68305bSMartin Schwidefsky case -ENOSYS: 72593098bf0SHongjie Yang pr_err("DCSS %s cannot be loaded or queried without " 72693098bf0SHongjie Yang "z/VM\n", seg_name); 727ca68305bSMartin Schwidefsky break; 728ca68305bSMartin Schwidefsky case -EIO: 72993098bf0SHongjie Yang pr_err("Loading or querying DCSS %s resulted in a " 730ca68305bSMartin Schwidefsky "hardware error\n", seg_name); 731ca68305bSMartin Schwidefsky break; 732b8e660b8SHeiko Carstens case -EOPNOTSUPP: 73393098bf0SHongjie Yang pr_err("DCSS %s has multiple page ranges and cannot be " 73493098bf0SHongjie Yang "loaded or queried\n", seg_name); 735ca68305bSMartin Schwidefsky break; 736ca68305bSMartin Schwidefsky case -ENOSPC: 73793098bf0SHongjie Yang pr_err("DCSS %s overlaps with used storage and cannot " 73893098bf0SHongjie Yang "be loaded\n", seg_name); 739ca68305bSMartin Schwidefsky break; 740ca68305bSMartin Schwidefsky case -EBUSY: 74193098bf0SHongjie Yang pr_err("%s needs used memory resources and cannot be " 74293098bf0SHongjie Yang "loaded or queried\n", seg_name); 743ca68305bSMartin Schwidefsky break; 744ca68305bSMartin Schwidefsky case -EPERM: 74593098bf0SHongjie Yang pr_err("DCSS %s is already loaded in a different access " 74693098bf0SHongjie Yang "mode\n", seg_name); 747ca68305bSMartin Schwidefsky break; 748ca68305bSMartin Schwidefsky case -ENOMEM: 74993098bf0SHongjie Yang pr_err("There is not enough memory to load or query " 75093098bf0SHongjie Yang "DCSS %s\n", seg_name); 751ca68305bSMartin Schwidefsky break; 752ca68305bSMartin Schwidefsky case -ERANGE: 75393098bf0SHongjie Yang pr_err("DCSS %s exceeds the kernel mapping range (%lu) " 75493098bf0SHongjie Yang "and cannot be loaded\n", seg_name, VMEM_MAX_PHYS); 755ca68305bSMartin Schwidefsky break; 756ca68305bSMartin Schwidefsky default: 757ca68305bSMartin Schwidefsky break; 758ca68305bSMartin Schwidefsky } 759ca68305bSMartin Schwidefsky } 760ca68305bSMartin Schwidefsky 7611da177e4SLinus Torvalds EXPORT_SYMBOL(segment_load); 7621da177e4SLinus Torvalds EXPORT_SYMBOL(segment_unload); 7631da177e4SLinus Torvalds EXPORT_SYMBOL(segment_save); 7641da177e4SLinus Torvalds EXPORT_SYMBOL(segment_type); 7651da177e4SLinus Torvalds EXPORT_SYMBOL(segment_modify_shared); 766ca68305bSMartin Schwidefsky EXPORT_SYMBOL(segment_warning); 767