Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/s390/kernel/lgr.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Linux Guest Relocation (LGR) detection
4
*
5
* Copyright IBM Corp. 2012
6
* Author(s): Michael Holzheu <[email protected]>
7
*/
8
9
#include <linux/init.h>
10
#include <linux/export.h>
11
#include <linux/timer.h>
12
#include <linux/slab.h>
13
#include <asm/facility.h>
14
#include <asm/sysinfo.h>
15
#include <asm/ebcdic.h>
16
#include <asm/debug.h>
17
#include <asm/ipl.h>
18
19
#define LGR_TIMER_INTERVAL_SECS (30 * 60)
20
#define VM_LEVEL_MAX 2 /* Maximum is 8, but we only record two levels */
21
22
/*
23
* LGR info: Contains stfle and stsi data
24
*/
25
struct lgr_info {
26
/* Bit field with facility information: 4 DWORDs are stored */
27
u64 stfle_fac_list[4];
28
/* Level of system (1 = CEC, 2 = LPAR, 3 = z/VM */
29
u32 level;
30
/* Level 1: CEC info (stsi 1.1.1) */
31
char manufacturer[16];
32
char type[4];
33
char sequence[16];
34
char plant[4];
35
char model[16];
36
/* Level 2: LPAR info (stsi 2.2.2) */
37
u16 lpar_number;
38
char name[8];
39
/* Level 3: VM info (stsi 3.2.2) */
40
u8 vm_count;
41
struct {
42
char name[8];
43
char cpi[16];
44
} vm[VM_LEVEL_MAX];
45
} __packed __aligned(8);
46
47
/*
48
* LGR globals
49
*/
50
static char lgr_page[PAGE_SIZE] __aligned(PAGE_SIZE);
51
static struct lgr_info lgr_info_last;
52
static struct lgr_info lgr_info_cur;
53
static struct debug_info *lgr_dbf;
54
55
/*
56
* Copy buffer and then convert it to ASCII
57
*/
58
static void cpascii(char *dst, char *src, int size)
59
{
60
memcpy(dst, src, size);
61
EBCASC(dst, size);
62
}
63
64
/*
65
* Fill LGR info with 1.1.1 stsi data
66
*/
67
static void lgr_stsi_1_1_1(struct lgr_info *lgr_info)
68
{
69
struct sysinfo_1_1_1 *si = (void *) lgr_page;
70
71
if (stsi(si, 1, 1, 1))
72
return;
73
cpascii(lgr_info->manufacturer, si->manufacturer,
74
sizeof(si->manufacturer));
75
cpascii(lgr_info->type, si->type, sizeof(si->type));
76
cpascii(lgr_info->model, si->model, sizeof(si->model));
77
cpascii(lgr_info->sequence, si->sequence, sizeof(si->sequence));
78
cpascii(lgr_info->plant, si->plant, sizeof(si->plant));
79
}
80
81
/*
82
* Fill LGR info with 2.2.2 stsi data
83
*/
84
static void lgr_stsi_2_2_2(struct lgr_info *lgr_info)
85
{
86
struct sysinfo_2_2_2 *si = (void *) lgr_page;
87
88
if (stsi(si, 2, 2, 2))
89
return;
90
cpascii(lgr_info->name, si->name, sizeof(si->name));
91
lgr_info->lpar_number = si->lpar_number;
92
}
93
94
/*
95
* Fill LGR info with 3.2.2 stsi data
96
*/
97
static void lgr_stsi_3_2_2(struct lgr_info *lgr_info)
98
{
99
struct sysinfo_3_2_2 *si = (void *) lgr_page;
100
int i;
101
102
if (stsi(si, 3, 2, 2))
103
return;
104
for (i = 0; i < min_t(u8, si->count, VM_LEVEL_MAX); i++) {
105
cpascii(lgr_info->vm[i].name, si->vm[i].name,
106
sizeof(si->vm[i].name));
107
cpascii(lgr_info->vm[i].cpi, si->vm[i].cpi,
108
sizeof(si->vm[i].cpi));
109
}
110
lgr_info->vm_count = si->count;
111
}
112
113
/*
114
* Fill LGR info with current data
115
*/
116
static void lgr_info_get(struct lgr_info *lgr_info)
117
{
118
int level;
119
120
memset(lgr_info, 0, sizeof(*lgr_info));
121
stfle(lgr_info->stfle_fac_list, ARRAY_SIZE(lgr_info->stfle_fac_list));
122
level = stsi(NULL, 0, 0, 0);
123
lgr_info->level = level;
124
if (level >= 1)
125
lgr_stsi_1_1_1(lgr_info);
126
if (level >= 2)
127
lgr_stsi_2_2_2(lgr_info);
128
if (level >= 3)
129
lgr_stsi_3_2_2(lgr_info);
130
}
131
132
/*
133
* Check if LGR info has changed and if yes log new LGR info to s390dbf
134
*/
135
void lgr_info_log(void)
136
{
137
static DEFINE_SPINLOCK(lgr_info_lock);
138
unsigned long flags;
139
140
if (!spin_trylock_irqsave(&lgr_info_lock, flags))
141
return;
142
lgr_info_get(&lgr_info_cur);
143
if (memcmp(&lgr_info_last, &lgr_info_cur, sizeof(lgr_info_cur)) != 0) {
144
debug_event(lgr_dbf, 1, &lgr_info_cur, sizeof(lgr_info_cur));
145
lgr_info_last = lgr_info_cur;
146
}
147
spin_unlock_irqrestore(&lgr_info_lock, flags);
148
}
149
EXPORT_SYMBOL_GPL(lgr_info_log);
150
151
static void lgr_timer_set(void);
152
153
/*
154
* LGR timer callback
155
*/
156
static void lgr_timer_fn(struct timer_list *unused)
157
{
158
lgr_info_log();
159
lgr_timer_set();
160
}
161
162
static struct timer_list lgr_timer;
163
164
/*
165
* Setup next LGR timer
166
*/
167
static void lgr_timer_set(void)
168
{
169
mod_timer(&lgr_timer, jiffies + secs_to_jiffies(LGR_TIMER_INTERVAL_SECS));
170
}
171
172
/*
173
* Initialize LGR: Add s390dbf, write initial lgr_info and setup timer
174
*/
175
static int __init lgr_init(void)
176
{
177
lgr_dbf = debug_register("lgr", 1, 1, sizeof(struct lgr_info));
178
if (!lgr_dbf)
179
return -ENOMEM;
180
debug_register_view(lgr_dbf, &debug_hex_ascii_view);
181
lgr_info_get(&lgr_info_last);
182
debug_event(lgr_dbf, 1, &lgr_info_last, sizeof(lgr_info_last));
183
timer_setup(&lgr_timer, lgr_timer_fn, TIMER_DEFERRABLE);
184
lgr_timer_set();
185
return 0;
186
}
187
device_initcall(lgr_init);
188
189