aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/Kconfig1
-rw-r--r--arch/s390/hypfs/hypfs_diag.c3
-rw-r--r--arch/s390/include/asm/qdio.h78
-rw-r--r--arch/s390/kernel/suspend.c118
-rw-r--r--arch/s390/kernel/swsusp_asm64.S3
-rw-r--r--arch/s390/kernel/time.c13
6 files changed, 207 insertions, 9 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index ed5cb5af5281..6b99fc3f9b63 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -91,6 +91,7 @@ config S390
91 select HAVE_ARCH_MUTEX_CPU_RELAX 91 select HAVE_ARCH_MUTEX_CPU_RELAX
92 select HAVE_ARCH_JUMP_LABEL if !MARCH_G5 92 select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
93 select HAVE_RCU_TABLE_FREE if SMP 93 select HAVE_RCU_TABLE_FREE if SMP
94 select ARCH_SAVE_PAGE_KEYS if HIBERNATION
94 select ARCH_INLINE_SPIN_TRYLOCK 95 select ARCH_INLINE_SPIN_TRYLOCK
95 select ARCH_INLINE_SPIN_TRYLOCK_BH 96 select ARCH_INLINE_SPIN_TRYLOCK_BH
96 select ARCH_INLINE_SPIN_LOCK 97 select ARCH_INLINE_SPIN_LOCK
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c
index 6023c6dc1fb7..74c8f5e76ce4 100644
--- a/arch/s390/hypfs/hypfs_diag.c
+++ b/arch/s390/hypfs/hypfs_diag.c
@@ -562,10 +562,9 @@ static int dbfs_d204_create(void **data, void **data_free_ptr, size_t *size)
562 void *base; 562 void *base;
563 563
564 buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr); 564 buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr);
565 base = vmalloc(buf_size); 565 base = vzalloc(buf_size);
566 if (!base) 566 if (!base)
567 return -ENOMEM; 567 return -ENOMEM;
568 memset(base, 0, buf_size);
569 d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr); 568 d204 = page_align_ptr(base + sizeof(d204->hdr)) - sizeof(d204->hdr);
570 rc = diag204_do_store(d204->buf, diag204_buf_pages); 569 rc = diag204_do_store(d204->buf, diag204_buf_pages);
571 if (rc) { 570 if (rc) {
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h
index 15c97625df8d..21993623da9a 100644
--- a/arch/s390/include/asm/qdio.h
+++ b/arch/s390/include/asm/qdio.h
@@ -123,6 +123,40 @@ struct slibe {
123}; 123};
124 124
125/** 125/**
126 * struct qaob - queue asynchronous operation block
127 * @res0: reserved parameters
128 * @res1: reserved parameter
129 * @res2: reserved parameter
130 * @res3: reserved parameter
131 * @aorc: asynchronous operation return code
132 * @flags: internal flags
133 * @cbtbs: control block type
134 * @sb_count: number of storage blocks
135 * @sba: storage block element addresses
136 * @dcount: size of storage block elements
137 * @user0: user defineable value
138 * @res4: reserved paramater
139 * @user1: user defineable value
140 * @user2: user defineable value
141 */
142struct qaob {
143 u64 res0[6];
144 u8 res1;
145 u8 res2;
146 u8 res3;
147 u8 aorc;
148 u8 flags;
149 u16 cbtbs;
150 u8 sb_count;
151 u64 sba[QDIO_MAX_ELEMENTS_PER_BUFFER];
152 u16 dcount[QDIO_MAX_ELEMENTS_PER_BUFFER];
153 u64 user0;
154 u64 res4[2];
155 u64 user1;
156 u64 user2;
157} __attribute__ ((packed, aligned(256)));
158
159/**
126 * struct slib - storage list information block (SLIB) 160 * struct slib - storage list information block (SLIB)
127 * @nsliba: next SLIB address (if any) 161 * @nsliba: next SLIB address (if any)
128 * @sla: SL address 162 * @sla: SL address
@@ -225,6 +259,41 @@ struct slsb {
225#define CHSC_AC2_DATA_DIV_AVAILABLE 0x0010 259#define CHSC_AC2_DATA_DIV_AVAILABLE 0x0010
226#define CHSC_AC2_DATA_DIV_ENABLED 0x0002 260#define CHSC_AC2_DATA_DIV_ENABLED 0x0002
227 261
262/**
263 * struct qdio_outbuf_state - SBAL related asynchronous operation information
264 * (for communication with upper layer programs)
265 * (only required for use with completion queues)
266 * @flags: flags indicating state of buffer
267 * @aob: pointer to QAOB used for the particular SBAL
268 * @user: pointer to upper layer program's state information related to SBAL
269 * (stored in user1 data of QAOB)
270 */
271struct qdio_outbuf_state {
272 u8 flags;
273 struct qaob *aob;
274 void *user;
275};
276
277#define QDIO_OUTBUF_STATE_FLAG_NONE 0x00
278#define QDIO_OUTBUF_STATE_FLAG_PENDING 0x01
279
280#define CHSC_AC1_INITIATE_INPUTQ 0x80
281
282
283/* qdio adapter-characteristics-1 flag */
284#define AC1_SIGA_INPUT_NEEDED 0x40 /* process input queues */
285#define AC1_SIGA_OUTPUT_NEEDED 0x20 /* process output queues */
286#define AC1_SIGA_SYNC_NEEDED 0x10 /* ask hypervisor to sync */
287#define AC1_AUTOMATIC_SYNC_ON_THININT 0x08 /* set by hypervisor */
288#define AC1_AUTOMATIC_SYNC_ON_OUT_PCI 0x04 /* set by hypervisor */
289#define AC1_SC_QEBSM_AVAILABLE 0x02 /* available for subchannel */
290#define AC1_SC_QEBSM_ENABLED 0x01 /* enabled for subchannel */
291
292#define CHSC_AC2_DATA_DIV_AVAILABLE 0x0010
293#define CHSC_AC2_DATA_DIV_ENABLED 0x0002
294
295#define CHSC_AC3_FORMAT2_CQ_AVAILABLE 0x8000
296
228struct qdio_ssqd_desc { 297struct qdio_ssqd_desc {
229 u8 flags; 298 u8 flags;
230 u8:8; 299 u8:8;
@@ -243,8 +312,7 @@ struct qdio_ssqd_desc {
243 u64 sch_token; 312 u64 sch_token;
244 u8 mro; 313 u8 mro;
245 u8 mri; 314 u8 mri;
246 u8:8; 315 u16 qdioac3;
247 u8 sbalic;
248 u16:16; 316 u16:16;
249 u8:8; 317 u8:8;
250 u8 mmwc; 318 u8 mmwc;
@@ -280,9 +348,11 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int,
280 * @no_output_qs: number of output queues 348 * @no_output_qs: number of output queues
281 * @input_handler: handler to be called for input queues 349 * @input_handler: handler to be called for input queues
282 * @output_handler: handler to be called for output queues 350 * @output_handler: handler to be called for output queues
351 * @queue_start_poll: polling handlers (one per input queue or NULL)
283 * @int_parm: interruption parameter 352 * @int_parm: interruption parameter
284 * @input_sbal_addr_array: address of no_input_qs * 128 pointers 353 * @input_sbal_addr_array: address of no_input_qs * 128 pointers
285 * @output_sbal_addr_array: address of no_output_qs * 128 pointers 354 * @output_sbal_addr_array: address of no_output_qs * 128 pointers
355 * @output_sbal_state_array: no_output_qs * 128 state info (for CQ or NULL)
286 */ 356 */
287struct qdio_initialize { 357struct qdio_initialize {
288 struct ccw_device *cdev; 358 struct ccw_device *cdev;
@@ -297,11 +367,12 @@ struct qdio_initialize {
297 unsigned int no_output_qs; 367 unsigned int no_output_qs;
298 qdio_handler_t *input_handler; 368 qdio_handler_t *input_handler;
299 qdio_handler_t *output_handler; 369 qdio_handler_t *output_handler;
300 void (*queue_start_poll) (struct ccw_device *, int, unsigned long); 370 void (**queue_start_poll) (struct ccw_device *, int, unsigned long);
301 int scan_threshold; 371 int scan_threshold;
302 unsigned long int_parm; 372 unsigned long int_parm;
303 void **input_sbal_addr_array; 373 void **input_sbal_addr_array;
304 void **output_sbal_addr_array; 374 void **output_sbal_addr_array;
375 struct qdio_outbuf_state *output_sbal_state_array;
305}; 376};
306 377
307#define QDIO_STATE_INACTIVE 0x00000002 /* after qdio_cleanup */ 378#define QDIO_STATE_INACTIVE 0x00000002 /* after qdio_cleanup */
@@ -316,6 +387,7 @@ struct qdio_initialize {
316extern int qdio_allocate(struct qdio_initialize *); 387extern int qdio_allocate(struct qdio_initialize *);
317extern int qdio_establish(struct qdio_initialize *); 388extern int qdio_establish(struct qdio_initialize *);
318extern int qdio_activate(struct ccw_device *); 389extern int qdio_activate(struct ccw_device *);
390extern void qdio_release_aob(struct qaob *);
319extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int, 391extern int do_QDIO(struct ccw_device *, unsigned int, int, unsigned int,
320 unsigned int); 392 unsigned int);
321extern int qdio_start_irq(struct ccw_device *, int); 393extern int qdio_start_irq(struct ccw_device *, int);
diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c
index cf9e5c6d5527..b6f9afed74ec 100644
--- a/arch/s390/kernel/suspend.c
+++ b/arch/s390/kernel/suspend.c
@@ -7,6 +7,7 @@
7 */ 7 */
8 8
9#include <linux/pfn.h> 9#include <linux/pfn.h>
10#include <linux/mm.h>
10#include <asm/system.h> 11#include <asm/system.h>
11 12
12/* 13/*
@@ -14,6 +15,123 @@
14 */ 15 */
15extern const void __nosave_begin, __nosave_end; 16extern const void __nosave_begin, __nosave_end;
16 17
18/*
19 * The restore of the saved pages in an hibernation image will set
20 * the change and referenced bits in the storage key for each page.
21 * Overindication of the referenced bits after an hibernation cycle
22 * does not cause any harm but the overindication of the change bits
23 * would cause trouble.
24 * Use the ARCH_SAVE_PAGE_KEYS hooks to save the storage key of each
25 * page to the most significant byte of the associated page frame
26 * number in the hibernation image.
27 */
28
29/*
30 * Key storage is allocated as a linked list of pages.
31 * The size of the keys array is (PAGE_SIZE - sizeof(long))
32 */
33struct page_key_data {
34 struct page_key_data *next;
35 unsigned char data[];
36};
37
38#define PAGE_KEY_DATA_SIZE (PAGE_SIZE - sizeof(struct page_key_data *))
39
40static struct page_key_data *page_key_data;
41static struct page_key_data *page_key_rp, *page_key_wp;
42static unsigned long page_key_rx, page_key_wx;
43
44/*
45 * For each page in the hibernation image one additional byte is
46 * stored in the most significant byte of the page frame number.
47 * On suspend no additional memory is required but on resume the
48 * keys need to be memorized until the page data has been restored.
49 * Only then can the storage keys be set to their old state.
50 */
51unsigned long page_key_additional_pages(unsigned long pages)
52{
53 return DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE);
54}
55
56/*
57 * Free page_key_data list of arrays.
58 */
59void page_key_free(void)
60{
61 struct page_key_data *pkd;
62
63 while (page_key_data) {
64 pkd = page_key_data;
65 page_key_data = pkd->next;
66 free_page((unsigned long) pkd);
67 }
68}
69
70/*
71 * Allocate page_key_data list of arrays with enough room to store
72 * one byte for each page in the hibernation image.
73 */
74int page_key_alloc(unsigned long pages)
75{
76 struct page_key_data *pk;
77 unsigned long size;
78
79 size = DIV_ROUND_UP(pages, PAGE_KEY_DATA_SIZE);
80 while (size--) {
81 pk = (struct page_key_data *) get_zeroed_page(GFP_KERNEL);
82 if (!pk) {
83 page_key_free();
84 return -ENOMEM;
85 }
86 pk->next = page_key_data;
87 page_key_data = pk;
88 }
89 page_key_rp = page_key_wp = page_key_data;
90 page_key_rx = page_key_wx = 0;
91 return 0;
92}
93
94/*
95 * Save the storage key into the upper 8 bits of the page frame number.
96 */
97void page_key_read(unsigned long *pfn)
98{
99 unsigned long addr;
100
101 addr = (unsigned long) page_address(pfn_to_page(*pfn));
102 *(unsigned char *) pfn = (unsigned char) page_get_storage_key(addr);
103}
104
105/*
106 * Extract the storage key from the upper 8 bits of the page frame number
107 * and store it in the page_key_data list of arrays.
108 */
109void page_key_memorize(unsigned long *pfn)
110{
111 page_key_wp->data[page_key_wx] = *(unsigned char *) pfn;
112 *(unsigned char *) pfn = 0;
113 if (++page_key_wx < PAGE_KEY_DATA_SIZE)
114 return;
115 page_key_wp = page_key_wp->next;
116 page_key_wx = 0;
117}
118
119/*
120 * Get the next key from the page_key_data list of arrays and set the
121 * storage key of the page referred by @address. If @address refers to
122 * a "safe" page the swsusp_arch_resume code will transfer the storage
123 * key from the buffer page to the original page.
124 */
125void page_key_write(void *address)
126{
127 page_set_storage_key((unsigned long) address,
128 page_key_rp->data[page_key_rx], 0);
129 if (++page_key_rx >= PAGE_KEY_DATA_SIZE)
130 return;
131 page_key_rp = page_key_rp->next;
132 page_key_rx = 0;
133}
134
17int pfn_is_nosave(unsigned long pfn) 135int pfn_is_nosave(unsigned long pfn)
18{ 136{
19 unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin)); 137 unsigned long nosave_begin_pfn = PFN_DOWN(__pa(&__nosave_begin));
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S
index 51bcdb50a230..acb78cdee896 100644
--- a/arch/s390/kernel/swsusp_asm64.S
+++ b/arch/s390/kernel/swsusp_asm64.S
@@ -136,11 +136,14 @@ ENTRY(swsusp_arch_resume)
1360: 1360:
137 lg %r2,8(%r1) 137 lg %r2,8(%r1)
138 lg %r4,0(%r1) 138 lg %r4,0(%r1)
139 iske %r0,%r4
139 lghi %r3,PAGE_SIZE 140 lghi %r3,PAGE_SIZE
140 lghi %r5,PAGE_SIZE 141 lghi %r5,PAGE_SIZE
1411: 1421:
142 mvcle %r2,%r4,0 143 mvcle %r2,%r4,0
143 jo 1b 144 jo 1b
145 lg %r2,8(%r1)
146 sske %r0,%r2
144 lg %r1,16(%r1) 147 lg %r1,16(%r1)
145 ltgr %r1,%r1 148 ltgr %r1,%r1
146 jnz 0b 149 jnz 0b
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index dff933065ab6..8d65bd0383fc 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -109,10 +109,14 @@ static void fixup_clock_comparator(unsigned long long delta)
109 set_clock_comparator(S390_lowcore.clock_comparator); 109 set_clock_comparator(S390_lowcore.clock_comparator);
110} 110}
111 111
112static int s390_next_event(unsigned long delta, 112static int s390_next_ktime(ktime_t expires,
113 struct clock_event_device *evt) 113 struct clock_event_device *evt)
114{ 114{
115 S390_lowcore.clock_comparator = get_clock() + delta; 115 u64 nsecs;
116
117 nsecs = ktime_to_ns(ktime_sub(expires, ktime_get_monotonic_offset()));
118 do_div(nsecs, 125);
119 S390_lowcore.clock_comparator = TOD_UNIX_EPOCH + (nsecs << 9);
116 set_clock_comparator(S390_lowcore.clock_comparator); 120 set_clock_comparator(S390_lowcore.clock_comparator);
117 return 0; 121 return 0;
118} 122}
@@ -137,14 +141,15 @@ void init_cpu_timer(void)
137 cpu = smp_processor_id(); 141 cpu = smp_processor_id();
138 cd = &per_cpu(comparators, cpu); 142 cd = &per_cpu(comparators, cpu);
139 cd->name = "comparator"; 143 cd->name = "comparator";
140 cd->features = CLOCK_EVT_FEAT_ONESHOT; 144 cd->features = CLOCK_EVT_FEAT_ONESHOT |
145 CLOCK_EVT_FEAT_KTIME;
141 cd->mult = 16777; 146 cd->mult = 16777;
142 cd->shift = 12; 147 cd->shift = 12;
143 cd->min_delta_ns = 1; 148 cd->min_delta_ns = 1;
144 cd->max_delta_ns = LONG_MAX; 149 cd->max_delta_ns = LONG_MAX;
145 cd->rating = 400; 150 cd->rating = 400;
146 cd->cpumask = cpumask_of(cpu); 151 cd->cpumask = cpumask_of(cpu);
147 cd->set_next_event = s390_next_event; 152 cd->set_next_ktime = s390_next_ktime;
148 cd->set_mode = s390_set_mode; 153 cd->set_mode = s390_set_mode;
149 154
150 clockevents_register_device(cd); 155 clockevents_register_device(cd);