forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-11 6778948f9de86c3cfaf36725a7c87dcff9ba247f
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;
....@@ -410,22 +308,15 @@
410308 if (rc < 0)
411309 goto out_free;
412310
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)
311
+ if (segment_overlaps_others(seg)) {
312
+ rc = -EBUSY;
423313 goto out_free;
314
+ }
424315
425316 seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL);
426317 if (seg->res == NULL) {
427318 rc = -ENOMEM;
428
- goto out_shared;
319
+ goto out_free;
429320 }
430321 seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
431322 seg->res->start = seg->start_addr;
....@@ -439,11 +330,16 @@
439330 if (rc == SEG_TYPE_SC ||
440331 ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
441332 seg->res->flags |= IORESOURCE_READONLY;
333
+
334
+ /* Check for overlapping resources before adding the mapping. */
442335 if (request_resource(&iomem_resource, seg->res)) {
443336 rc = -EBUSY;
444
- kfree(seg->res);
445
- goto out_shared;
337
+ goto out_free_resource;
446338 }
339
+
340
+ rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
341
+ if (rc)
342
+ goto out_resource;
447343
448344 if (do_nonshared)
449345 diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name,
....@@ -455,37 +351,38 @@
455351 dcss_diag(&purgeseg_scode, seg->dcss_name,
456352 &dummy, &dummy);
457353 rc = diag_cc;
458
- goto out_resource;
354
+ goto out_mapping;
459355 }
460356 if (diag_cc > 1) {
461357 pr_warn("Loading DCSS %s failed with rc=%ld\n", name, end_addr);
462358 rc = dcss_diag_translate_rc(end_addr);
463359 dcss_diag(&purgeseg_scode, seg->dcss_name,
464360 &dummy, &dummy);
465
- goto out_resource;
361
+ goto out_mapping;
466362 }
467363 seg->start_addr = start_addr;
468364 seg->end = end_addr;
469365 seg->do_nonshared = do_nonshared;
470
- atomic_set(&seg->ref_count, 1);
366
+ refcount_set(&seg->ref_count, 1);
471367 list_add(&seg->list, &dcss_list);
472368 *addr = seg->start_addr;
473369 *end = seg->end;
474370 if (do_nonshared)
475
- pr_info("DCSS %s of range %p to %p and type %s loaded as "
371
+ pr_info("DCSS %s of range %px to %px and type %s loaded as "
476372 "exclusive-writable\n", name, (void*) seg->start_addr,
477373 (void*) seg->end, segtype_string[seg->vm_segtype]);
478374 else {
479
- pr_info("DCSS %s of range %p to %p and type %s loaded in "
375
+ pr_info("DCSS %s of range %px to %px and type %s loaded in "
480376 "shared access mode\n", name, (void*) seg->start_addr,
481377 (void*) seg->end, segtype_string[seg->vm_segtype]);
482378 }
483379 goto out;
380
+ out_mapping:
381
+ vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
484382 out_resource:
485383 release_resource(seg->res);
384
+ out_free_resource:
486385 kfree(seg->res);
487
- out_shared:
488
- vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
489386 out_free:
490387 kfree(seg);
491388 out:
....@@ -504,8 +401,7 @@
504401 * -EIO : could not perform query or load diagnose
505402 * -ENOENT : no such segment
506403 * -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)
404
+ * -EBUSY : segment cannot be used (overlaps with dcss or storage)
509405 * -ERANGE : segment cannot be used (exceeds kernel mapping range)
510406 * -EPERM : segment is currently loaded with incompatible permissions
511407 * -ENOMEM : out of memory
....@@ -527,7 +423,7 @@
527423 rc = __segment_load (name, do_nonshared, addr, end);
528424 else {
529425 if (do_nonshared == seg->do_nonshared) {
530
- atomic_inc(&seg->ref_count);
426
+ refcount_inc(&seg->ref_count);
531427 *addr = seg->start_addr;
532428 *end = seg->end;
533429 rc = seg->vm_segtype;
....@@ -573,7 +469,7 @@
573469 rc = 0;
574470 goto out_unlock;
575471 }
576
- if (atomic_read (&seg->ref_count) != 1) {
472
+ if (refcount_read(&seg->ref_count) != 1) {
577473 pr_warn("DCSS %s is in use and cannot be reloaded\n", name);
578474 rc = -EAGAIN;
579475 goto out_unlock;
....@@ -649,7 +545,7 @@
649545 pr_err("Unloading unknown DCSS %s failed\n", name);
650546 goto out_unlock;
651547 }
652
- if (atomic_dec_return(&seg->ref_count) != 0)
548
+ if (!refcount_dec_and_test(&seg->ref_count))
653549 goto out_unlock;
654550 release_resource(seg->res);
655551 kfree(seg->res);
....@@ -729,10 +625,6 @@
729625 case -EOPNOTSUPP:
730626 pr_err("DCSS %s has multiple page ranges and cannot be "
731627 "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);
736628 break;
737629 case -EBUSY:
738630 pr_err("%s needs used memory resources and cannot be "