Blame view

arch/s390/kernel/lgr.c 4.34 KB
a17ae4c3a   Greg Kroah-Hartman   s390: kernel: add...
1
  // SPDX-License-Identifier: GPL-2.0
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
2
3
4
5
6
7
  /*
   * Linux Guest Relocation (LGR) detection
   *
   * Copyright IBM Corp. 2012
   * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
   */
8ba8b05f5   Paul Gortmaker   s390: kernel: mak...
8
9
  #include <linux/init.h>
  #include <linux/export.h>
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
10
11
  #include <linux/timer.h>
  #include <linux/slab.h>
1e3cab2f2   Heiko Carstens   [S390] Fix build ...
12
  #include <asm/facility.h>
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
13
14
  #include <asm/sysinfo.h>
  #include <asm/ebcdic.h>
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  #include <asm/debug.h>
  #include <asm/ipl.h>
  
  #define LGR_TIMER_INTERVAL_SECS (30 * 60)
  #define VM_LEVEL_MAX 2 /* Maximum is 8, but we only record two levels */
  
  /*
   * LGR info: Contains stfle and stsi data
   */
  struct lgr_info {
  	/* Bit field with facility information: 4 DWORDs are stored */
  	u64 stfle_fac_list[4];
  	/* Level of system (1 = CEC, 2 = LPAR, 3 = z/VM */
  	u32 level;
  	/* Level 1: CEC info (stsi 1.1.1) */
  	char manufacturer[16];
  	char type[4];
  	char sequence[16];
  	char plant[4];
  	char model[16];
  	/* Level 2: LPAR info (stsi 2.2.2) */
  	u16 lpar_number;
  	char name[8];
  	/* Level 3: VM info (stsi 3.2.2) */
  	u8 vm_count;
  	struct {
  		char name[8];
  		char cpi[16];
  	} vm[VM_LEVEL_MAX];
  } __packed __aligned(8);
  
  /*
   * LGR globals
   */
2b7547578   Michael Holzheu   s390/lgr: Add ini...
49
  static char lgr_page[PAGE_SIZE] __aligned(PAGE_SIZE);
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
50
51
52
53
54
  static struct lgr_info lgr_info_last;
  static struct lgr_info lgr_info_cur;
  static struct debug_info *lgr_dbf;
  
  /*
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
55
56
57
58
59
60
61
62
63
64
65
66
67
   * Copy buffer and then convert it to ASCII
   */
  static void cpascii(char *dst, char *src, int size)
  {
  	memcpy(dst, src, size);
  	EBCASC(dst, size);
  }
  
  /*
   * Fill LGR info with 1.1.1 stsi data
   */
  static void lgr_stsi_1_1_1(struct lgr_info *lgr_info)
  {
2b7547578   Michael Holzheu   s390/lgr: Add ini...
68
  	struct sysinfo_1_1_1 *si = (void *) lgr_page;
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
69

caf757c60   Heiko Carstens   s390/sysinfo,stsi...
70
  	if (stsi(si, 1, 1, 1))
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  		return;
  	cpascii(lgr_info->manufacturer, si->manufacturer,
  		sizeof(si->manufacturer));
  	cpascii(lgr_info->type, si->type, sizeof(si->type));
  	cpascii(lgr_info->model, si->model, sizeof(si->model));
  	cpascii(lgr_info->sequence, si->sequence, sizeof(si->sequence));
  	cpascii(lgr_info->plant, si->plant, sizeof(si->plant));
  }
  
  /*
   * Fill LGR info with 2.2.2 stsi data
   */
  static void lgr_stsi_2_2_2(struct lgr_info *lgr_info)
  {
2b7547578   Michael Holzheu   s390/lgr: Add ini...
85
  	struct sysinfo_2_2_2 *si = (void *) lgr_page;
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
86

caf757c60   Heiko Carstens   s390/sysinfo,stsi...
87
  	if (stsi(si, 2, 2, 2))
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
88
89
90
91
92
93
94
95
96
97
98
  		return;
  	cpascii(lgr_info->name, si->name, sizeof(si->name));
  	memcpy(&lgr_info->lpar_number, &si->lpar_number,
  	       sizeof(lgr_info->lpar_number));
  }
  
  /*
   * Fill LGR info with 3.2.2 stsi data
   */
  static void lgr_stsi_3_2_2(struct lgr_info *lgr_info)
  {
2b7547578   Michael Holzheu   s390/lgr: Add ini...
99
  	struct sysinfo_3_2_2 *si = (void *) lgr_page;
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
100
  	int i;
caf757c60   Heiko Carstens   s390/sysinfo,stsi...
101
  	if (stsi(si, 3, 2, 2))
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  		return;
  	for (i = 0; i < min_t(u8, si->count, VM_LEVEL_MAX); i++) {
  		cpascii(lgr_info->vm[i].name, si->vm[i].name,
  			sizeof(si->vm[i].name));
  		cpascii(lgr_info->vm[i].cpi, si->vm[i].cpi,
  			sizeof(si->vm[i].cpi));
  	}
  	lgr_info->vm_count = si->count;
  }
  
  /*
   * Fill LGR info with current data
   */
  static void lgr_info_get(struct lgr_info *lgr_info)
  {
caf757c60   Heiko Carstens   s390/sysinfo,stsi...
117
  	int level;
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
118
119
  	memset(lgr_info, 0, sizeof(*lgr_info));
  	stfle(lgr_info->stfle_fac_list, ARRAY_SIZE(lgr_info->stfle_fac_list));
caf757c60   Heiko Carstens   s390/sysinfo,stsi...
120
121
122
  	level = stsi(NULL, 0, 0, 0);
  	lgr_info->level = level;
  	if (level >= 1)
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
123
  		lgr_stsi_1_1_1(lgr_info);
caf757c60   Heiko Carstens   s390/sysinfo,stsi...
124
  	if (level >= 2)
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
125
  		lgr_stsi_2_2_2(lgr_info);
caf757c60   Heiko Carstens   s390/sysinfo,stsi...
126
  	if (level >= 3)
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  		lgr_stsi_3_2_2(lgr_info);
  }
  
  /*
   * Check if LGR info has changed and if yes log new LGR info to s390dbf
   */
  void lgr_info_log(void)
  {
  	static DEFINE_SPINLOCK(lgr_info_lock);
  	unsigned long flags;
  
  	if (!spin_trylock_irqsave(&lgr_info_lock, flags))
  		return;
  	lgr_info_get(&lgr_info_cur);
  	if (memcmp(&lgr_info_last, &lgr_info_cur, sizeof(lgr_info_cur)) != 0) {
  		debug_event(lgr_dbf, 1, &lgr_info_cur, sizeof(lgr_info_cur));
  		lgr_info_last = lgr_info_cur;
  	}
  	spin_unlock_irqrestore(&lgr_info_lock, flags);
  }
  EXPORT_SYMBOL_GPL(lgr_info_log);
  
  static void lgr_timer_set(void);
  
  /*
   * LGR timer callback
   */
5cd79d6ab   Kees Cook   timer: Remove use...
154
  static void lgr_timer_fn(struct timer_list *unused)
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
155
156
157
158
  {
  	lgr_info_log();
  	lgr_timer_set();
  }
5cd79d6ab   Kees Cook   timer: Remove use...
159
  static struct timer_list lgr_timer;
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
160
161
162
163
164
165
  
  /*
   * Setup next LGR timer
   */
  static void lgr_timer_set(void)
  {
0188d08a4   Sven Schnelle   s390: convert to ...
166
  	mod_timer(&lgr_timer, jiffies + msecs_to_jiffies(LGR_TIMER_INTERVAL_SECS * MSEC_PER_SEC));
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
167
168
169
170
171
172
173
  }
  
  /*
   * Initialize LGR: Add s390dbf, write initial lgr_info and setup timer
   */
  static int __init lgr_init(void)
  {
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
174
  	lgr_dbf = debug_register("lgr", 1, 1, sizeof(struct lgr_info));
2b7547578   Michael Holzheu   s390/lgr: Add ini...
175
  	if (!lgr_dbf)
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
176
  		return -ENOMEM;
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
177
178
179
  	debug_register_view(lgr_dbf, &debug_hex_ascii_view);
  	lgr_info_get(&lgr_info_last);
  	debug_event(lgr_dbf, 1, &lgr_info_last, sizeof(lgr_info_last));
5cd79d6ab   Kees Cook   timer: Remove use...
180
  	timer_setup(&lgr_timer, lgr_timer_fn, TIMER_DEFERRABLE);
3ab121ab1   Michael Holzheu   [S390] kernel: Ad...
181
182
183
  	lgr_timer_set();
  	return 0;
  }
8ba8b05f5   Paul Gortmaker   s390: kernel: mak...
184
  device_initcall(lgr_init);