hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/arch/s390/mm/extmem.c
....@@ -16,24 +16,20 @@
1616 #include <linux/list.h>
1717 #include <linux/slab.h>
1818 #include <linux/export.h>
19
-#include <linux/bootmem.h>
19
+#include <linux/memblock.h>
2020 #include <linux/ctype.h>
2121 #include <linux/ioport.h>
22
+#include <linux/refcount.h>
23
+#include <linux/pgtable.h>
2224 #include <asm/diag.h>
2325 #include <asm/page.h>
24
-#include <asm/pgtable.h>
2526 #include <asm/ebcdic.h>
2627 #include <asm/errno.h>
2728 #include <asm/extmem.h>
2829 #include <asm/cpcmd.h>
2930 #include <asm/setup.h>
3031
31
-#define DCSS_LOADSHR 0x00
32
-#define DCSS_LOADNSR 0x04
3332 #define DCSS_PURGESEG 0x08
34
-#define DCSS_FINDSEG 0x0c
35
-#define DCSS_LOADNOLY 0x10
36
-#define DCSS_SEGEXT 0x18
3733 #define DCSS_LOADSHRX 0x20
3834 #define DCSS_LOADNSRX 0x24
3935 #define DCSS_FINDSEGX 0x2c
....@@ -53,20 +49,6 @@
5349 struct qrange range[6];
5450 };
5551
56
-struct qrange_old {
57
- unsigned int start; /* last byte type */
58
- unsigned int end; /* last byte reserved */
59
-};
60
-
61
-/* output area format for the Diag x'64' old subcode x'18' */
62
-struct qout64_old {
63
- int segstart;
64
- int segend;
65
- int segcnt;
66
- int segrcnt;
67
- struct qrange_old range[6];
68
-};
69
-
7052 struct qin64 {
7153 char qopcode;
7254 char rsrv1[3];
....@@ -83,7 +65,7 @@
8365 char res_name[16];
8466 unsigned long start_addr;
8567 unsigned long end;
86
- atomic_t ref_count;
68
+ refcount_t ref_count;
8769 int do_nonshared;
8870 unsigned int vm_segtype;
8971 struct qrange range[6];
....@@ -95,52 +77,10 @@
9577 static LIST_HEAD(dcss_list);
9678 static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
9779 "EW/EN-MIXED" };
98
-static int loadshr_scode, loadnsr_scode;
99
-static int segext_scode, purgeseg_scode;
100
-static int scode_set;
101
-
102
-/* set correct Diag x'64' subcodes. */
103
-static int
104
-dcss_set_subcodes(void)
105
-{
106
- char *name = kmalloc(8, GFP_KERNEL | GFP_DMA);
107
- unsigned long rx, ry;
108
- int rc;
109
-
110
- if (name == NULL)
111
- return -ENOMEM;
112
-
113
- rx = (unsigned long) name;
114
- ry = DCSS_FINDSEGX;
115
-
116
- strcpy(name, "dummy");
117
- diag_stat_inc(DIAG_STAT_X064);
118
- asm volatile(
119
- " diag %0,%1,0x64\n"
120
- "0: ipm %2\n"
121
- " srl %2,28\n"
122
- " j 2f\n"
123
- "1: la %2,3\n"
124
- "2:\n"
125
- EX_TABLE(0b, 1b)
126
- : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc", "memory");
127
-
128
- kfree(name);
129
- /* Diag x'64' new subcodes are supported, set to new subcodes */
130
- if (rc != 3) {
131
- loadshr_scode = DCSS_LOADSHRX;
132
- loadnsr_scode = DCSS_LOADNSRX;
133
- purgeseg_scode = DCSS_PURGESEG;
134
- segext_scode = DCSS_SEGEXTX;
135
- return 0;
136
- }
137
- /* Diag x'64' new subcodes are not supported, set to old subcodes */
138
- loadshr_scode = DCSS_LOADNOLY;
139
- loadnsr_scode = DCSS_LOADNSR;
140
- purgeseg_scode = DCSS_PURGESEG;
141
- segext_scode = DCSS_SEGEXT;
142
- return 0;
143
-}
80
+static int loadshr_scode = DCSS_LOADSHRX;
81
+static int loadnsr_scode = DCSS_LOADNSRX;
82
+static int purgeseg_scode = DCSS_PURGESEG;
83
+static int segext_scode = DCSS_SEGEXTX;
14484
14585 /*
14686 * Create the 8 bytes, ebcdic VM segment name from
....@@ -196,32 +136,15 @@
196136 unsigned long rx, ry;
197137 int rc;
198138
199
- if (scode_set == 0) {
200
- rc = dcss_set_subcodes();
201
- if (rc < 0)
202
- return rc;
203
- scode_set = 1;
204
- }
205139 rx = (unsigned long) parameter;
206140 ry = (unsigned long) *func;
207141
208
- /* 64-bit Diag x'64' new subcode, keep in 64-bit addressing mode */
209142 diag_stat_inc(DIAG_STAT_X064);
210
- if (*func > DCSS_SEGEXT)
211
- asm volatile(
212
- " diag %0,%1,0x64\n"
213
- " ipm %2\n"
214
- " srl %2,28\n"
215
- : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
216
- /* 31-bit Diag x'64' old subcode, switch to 31-bit addressing mode */
217
- else
218
- asm volatile(
219
- " sam31\n"
220
- " diag %0,%1,0x64\n"
221
- " sam64\n"
222
- " ipm %2\n"
223
- " srl %2,28\n"
224
- : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
143
+ asm volatile(
144
+ " diag %0,%1,0x64\n"
145
+ " ipm %2\n"
146
+ " srl %2,28\n"
147
+ : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
225148 *ret1 = rx;
226149 *ret2 = ry;
227150 return rc;
....@@ -271,31 +194,6 @@
271194 goto out_free;
272195 }
273196
274
- /* Only old format of output area of Diagnose x'64' is supported,
275
- copy data for the new format. */
276
- if (segext_scode == DCSS_SEGEXT) {
277
- struct qout64_old *qout_old;
278
- qout_old = kzalloc(sizeof(*qout_old), GFP_KERNEL | GFP_DMA);
279
- if (qout_old == NULL) {
280
- rc = -ENOMEM;
281
- goto out_free;
282
- }
283
- memcpy(qout_old, qout, sizeof(struct qout64_old));
284
- qout->segstart = (unsigned long) qout_old->segstart;
285
- qout->segend = (unsigned long) qout_old->segend;
286
- qout->segcnt = qout_old->segcnt;
287
- qout->segrcnt = qout_old->segrcnt;
288
-
289
- if (qout->segcnt > 6)
290
- qout->segrcnt = 6;
291
- for (i = 0; i < qout->segrcnt; i++) {
292
- qout->range[i].start =
293
- (unsigned long) qout_old->range[i].start;
294
- qout->range[i].end =
295
- (unsigned long) qout_old->range[i].end;
296
- }
297
- kfree(qout_old);
298
- }
299197 if (qout->segcnt > 6) {
300198 rc = -EOPNOTSUPP;
301199 goto out_free;
....@@ -391,15 +289,17 @@
391289
392290 /*
393291 * real segment loading function, called from segment_load
292
+ * Must return either an error code < 0, or the segment type code >= 0
394293 */
395294 static int
396295 __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end)
397296 {
398297 unsigned long start_addr, end_addr, dummy;
399298 struct dcss_segment *seg;
400
- int rc, diag_cc;
299
+ int rc, diag_cc, segtype;
401300
402301 start_addr = end_addr = 0;
302
+ segtype = -1;
403303 seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA);
404304 if (seg == NULL) {
405305 rc = -ENOMEM;
....@@ -410,22 +310,15 @@
410310 if (rc < 0)
411311 goto out_free;
412312
413
- if (loadshr_scode == DCSS_LOADSHRX) {
414
- if (segment_overlaps_others(seg)) {
415
- rc = -EBUSY;
416
- goto out_free;
417
- }
418
- }
419
-
420
- rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
421
-
422
- if (rc)
313
+ if (segment_overlaps_others(seg)) {
314
+ rc = -EBUSY;
423315 goto out_free;
316
+ }
424317
425318 seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL);
426319 if (seg->res == NULL) {
427320 rc = -ENOMEM;
428
- goto out_shared;
321
+ goto out_free;
429322 }
430323 seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
431324 seg->res->start = seg->start_addr;
....@@ -435,15 +328,20 @@
435328 seg->res_name[8] = '\0';
436329 strlcat(seg->res_name, " (DCSS)", sizeof(seg->res_name));
437330 seg->res->name = seg->res_name;
438
- rc = seg->vm_segtype;
439
- if (rc == SEG_TYPE_SC ||
440
- ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
331
+ segtype = seg->vm_segtype;
332
+ if (segtype == SEG_TYPE_SC ||
333
+ ((segtype == SEG_TYPE_SR || segtype == SEG_TYPE_ER) && !do_nonshared))
441334 seg->res->flags |= IORESOURCE_READONLY;
335
+
336
+ /* Check for overlapping resources before adding the mapping. */
442337 if (request_resource(&iomem_resource, seg->res)) {
443338 rc = -EBUSY;
444
- kfree(seg->res);
445
- goto out_shared;
339
+ goto out_free_resource;
446340 }
341
+
342
+ rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
343
+ if (rc)
344
+ goto out_resource;
447345
448346 if (do_nonshared)
449347 diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name,
....@@ -455,41 +353,42 @@
455353 dcss_diag(&purgeseg_scode, seg->dcss_name,
456354 &dummy, &dummy);
457355 rc = diag_cc;
458
- goto out_resource;
356
+ goto out_mapping;
459357 }
460358 if (diag_cc > 1) {
461359 pr_warn("Loading DCSS %s failed with rc=%ld\n", name, end_addr);
462360 rc = dcss_diag_translate_rc(end_addr);
463361 dcss_diag(&purgeseg_scode, seg->dcss_name,
464362 &dummy, &dummy);
465
- goto out_resource;
363
+ goto out_mapping;
466364 }
467365 seg->start_addr = start_addr;
468366 seg->end = end_addr;
469367 seg->do_nonshared = do_nonshared;
470
- atomic_set(&seg->ref_count, 1);
368
+ refcount_set(&seg->ref_count, 1);
471369 list_add(&seg->list, &dcss_list);
472370 *addr = seg->start_addr;
473371 *end = seg->end;
474372 if (do_nonshared)
475
- pr_info("DCSS %s of range %p to %p and type %s loaded as "
373
+ pr_info("DCSS %s of range %px to %px and type %s loaded as "
476374 "exclusive-writable\n", name, (void*) seg->start_addr,
477375 (void*) seg->end, segtype_string[seg->vm_segtype]);
478376 else {
479
- pr_info("DCSS %s of range %p to %p and type %s loaded in "
377
+ pr_info("DCSS %s of range %px to %px and type %s loaded in "
480378 "shared access mode\n", name, (void*) seg->start_addr,
481379 (void*) seg->end, segtype_string[seg->vm_segtype]);
482380 }
483381 goto out;
382
+ out_mapping:
383
+ vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
484384 out_resource:
485385 release_resource(seg->res);
386
+ out_free_resource:
486387 kfree(seg->res);
487
- out_shared:
488
- vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
489388 out_free:
490389 kfree(seg);
491390 out:
492
- return rc;
391
+ return rc < 0 ? rc : segtype;
493392 }
494393
495394 /*
....@@ -504,8 +403,7 @@
504403 * -EIO : could not perform query or load diagnose
505404 * -ENOENT : no such segment
506405 * -EOPNOTSUPP: multi-part segment cannot be used with linux
507
- * -ENOSPC : segment cannot be used (overlaps with storage)
508
- * -EBUSY : segment can temporarily not be used (overlaps with dcss)
406
+ * -EBUSY : segment cannot be used (overlaps with dcss or storage)
509407 * -ERANGE : segment cannot be used (exceeds kernel mapping range)
510408 * -EPERM : segment is currently loaded with incompatible permissions
511409 * -ENOMEM : out of memory
....@@ -527,7 +425,7 @@
527425 rc = __segment_load (name, do_nonshared, addr, end);
528426 else {
529427 if (do_nonshared == seg->do_nonshared) {
530
- atomic_inc(&seg->ref_count);
428
+ refcount_inc(&seg->ref_count);
531429 *addr = seg->start_addr;
532430 *end = seg->end;
533431 rc = seg->vm_segtype;
....@@ -573,7 +471,7 @@
573471 rc = 0;
574472 goto out_unlock;
575473 }
576
- if (atomic_read (&seg->ref_count) != 1) {
474
+ if (refcount_read(&seg->ref_count) != 1) {
577475 pr_warn("DCSS %s is in use and cannot be reloaded\n", name);
578476 rc = -EAGAIN;
579477 goto out_unlock;
....@@ -649,7 +547,7 @@
649547 pr_err("Unloading unknown DCSS %s failed\n", name);
650548 goto out_unlock;
651549 }
652
- if (atomic_dec_return(&seg->ref_count) != 0)
550
+ if (!refcount_dec_and_test(&seg->ref_count))
653551 goto out_unlock;
654552 release_resource(seg->res);
655553 kfree(seg->res);
....@@ -729,10 +627,6 @@
729627 case -EOPNOTSUPP:
730628 pr_err("DCSS %s has multiple page ranges and cannot be "
731629 "loaded or queried\n", seg_name);
732
- break;
733
- case -ENOSPC:
734
- pr_err("DCSS %s overlaps with used storage and cannot "
735
- "be loaded\n", seg_name);
736630 break;
737631 case -EBUSY:
738632 pr_err("%s needs used memory resources and cannot be "