Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/platforms/pseries/hvcserver.c
10818 views
1
/*
2
* hvcserver.c
3
* Copyright (C) 2004 Ryan S Arnold, IBM Corporation
4
*
5
* PPC64 virtual I/O console server support.
6
*
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
11
*
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
16
*
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
*/
21
22
#include <linux/kernel.h>
23
#include <linux/list.h>
24
#include <linux/module.h>
25
#include <linux/slab.h>
26
27
#include <asm/hvcall.h>
28
#include <asm/hvcserver.h>
29
#include <asm/io.h>
30
31
#define HVCS_ARCH_VERSION "1.0.0"
32
33
MODULE_AUTHOR("Ryan S. Arnold <[email protected]>");
34
MODULE_DESCRIPTION("IBM hvcs ppc64 API");
35
MODULE_LICENSE("GPL");
36
MODULE_VERSION(HVCS_ARCH_VERSION);
37
38
/*
39
* Convert arch specific return codes into relevant errnos. The hvcs
40
* functions aren't performance sensitive, so this conversion isn't an
41
* issue.
42
*/
43
static int hvcs_convert(long to_convert)
44
{
45
switch (to_convert) {
46
case H_SUCCESS:
47
return 0;
48
case H_PARAMETER:
49
return -EINVAL;
50
case H_HARDWARE:
51
return -EIO;
52
case H_BUSY:
53
case H_LONG_BUSY_ORDER_1_MSEC:
54
case H_LONG_BUSY_ORDER_10_MSEC:
55
case H_LONG_BUSY_ORDER_100_MSEC:
56
case H_LONG_BUSY_ORDER_1_SEC:
57
case H_LONG_BUSY_ORDER_10_SEC:
58
case H_LONG_BUSY_ORDER_100_SEC:
59
return -EBUSY;
60
case H_FUNCTION: /* fall through */
61
default:
62
return -EPERM;
63
}
64
}
65
66
/**
67
* hvcs_free_partner_info - free pi allocated by hvcs_get_partner_info
68
* @head: list_head pointer for an allocated list of partner info structs to
69
* free.
70
*
71
* This function is used to free the partner info list that was returned by
72
* calling hvcs_get_partner_info().
73
*/
74
int hvcs_free_partner_info(struct list_head *head)
75
{
76
struct hvcs_partner_info *pi;
77
struct list_head *element;
78
79
if (!head)
80
return -EINVAL;
81
82
while (!list_empty(head)) {
83
element = head->next;
84
pi = list_entry(element, struct hvcs_partner_info, node);
85
list_del(element);
86
kfree(pi);
87
}
88
89
return 0;
90
}
91
EXPORT_SYMBOL(hvcs_free_partner_info);
92
93
/* Helper function for hvcs_get_partner_info */
94
static int hvcs_next_partner(uint32_t unit_address,
95
unsigned long last_p_partition_ID,
96
unsigned long last_p_unit_address, unsigned long *pi_buff)
97
98
{
99
long retval;
100
retval = plpar_hcall_norets(H_VTERM_PARTNER_INFO, unit_address,
101
last_p_partition_ID,
102
last_p_unit_address, virt_to_phys(pi_buff));
103
return hvcs_convert(retval);
104
}
105
106
/**
107
* hvcs_get_partner_info - Get all of the partner info for a vty-server adapter
108
* @unit_address: The unit_address of the vty-server adapter for which this
109
* function is fetching partner info.
110
* @head: An initialized list_head pointer to an empty list to use to return the
111
* list of partner info fetched from the hypervisor to the caller.
112
* @pi_buff: A page sized buffer pre-allocated prior to calling this function
113
* that is to be used to be used by firmware as an iterator to keep track
114
* of the partner info retrieval.
115
*
116
* This function returns non-zero on success, or if there is no partner info.
117
*
118
* The pi_buff is pre-allocated prior to calling this function because this
119
* function may be called with a spin_lock held and kmalloc of a page is not
120
* recommended as GFP_ATOMIC.
121
*
122
* The first long of this buffer is used to store a partner unit address. The
123
* second long is used to store a partner partition ID and starting at
124
* pi_buff[2] is the 79 character Converged Location Code (diff size than the
125
* unsigned longs, hence the casting mumbo jumbo you see later).
126
*
127
* Invocation of this function should always be followed by an invocation of
128
* hvcs_free_partner_info() using a pointer to the SAME list head instance
129
* that was passed as a parameter to this function.
130
*/
131
int hvcs_get_partner_info(uint32_t unit_address, struct list_head *head,
132
unsigned long *pi_buff)
133
{
134
/*
135
* Dealt with as longs because of the hcall interface even though the
136
* values are uint32_t.
137
*/
138
unsigned long last_p_partition_ID;
139
unsigned long last_p_unit_address;
140
struct hvcs_partner_info *next_partner_info = NULL;
141
int more = 1;
142
int retval;
143
144
memset(pi_buff, 0x00, PAGE_SIZE);
145
/* invalid parameters */
146
if (!head || !pi_buff)
147
return -EINVAL;
148
149
last_p_partition_ID = last_p_unit_address = ~0UL;
150
INIT_LIST_HEAD(head);
151
152
do {
153
retval = hvcs_next_partner(unit_address, last_p_partition_ID,
154
last_p_unit_address, pi_buff);
155
if (retval) {
156
/*
157
* Don't indicate that we've failed if we have
158
* any list elements.
159
*/
160
if (!list_empty(head))
161
return 0;
162
return retval;
163
}
164
165
last_p_partition_ID = pi_buff[0];
166
last_p_unit_address = pi_buff[1];
167
168
/* This indicates that there are no further partners */
169
if (last_p_partition_ID == ~0UL
170
&& last_p_unit_address == ~0UL)
171
break;
172
173
/* This is a very small struct and will be freed soon in
174
* hvcs_free_partner_info(). */
175
next_partner_info = kmalloc(sizeof(struct hvcs_partner_info),
176
GFP_ATOMIC);
177
178
if (!next_partner_info) {
179
printk(KERN_WARNING "HVCONSOLE: kmalloc() failed to"
180
" allocate partner info struct.\n");
181
hvcs_free_partner_info(head);
182
return -ENOMEM;
183
}
184
185
next_partner_info->unit_address
186
= (unsigned int)last_p_unit_address;
187
next_partner_info->partition_ID
188
= (unsigned int)last_p_partition_ID;
189
190
/* copy the Null-term char too */
191
strncpy(&next_partner_info->location_code[0],
192
(char *)&pi_buff[2],
193
strlen((char *)&pi_buff[2]) + 1);
194
195
list_add_tail(&(next_partner_info->node), head);
196
next_partner_info = NULL;
197
198
} while (more);
199
200
return 0;
201
}
202
EXPORT_SYMBOL(hvcs_get_partner_info);
203
204
/**
205
* hvcs_register_connection - establish a connection between this vty-server and
206
* a vty.
207
* @unit_address: The unit address of the vty-server adapter that is to be
208
* establish a connection.
209
* @p_partition_ID: The partition ID of the vty adapter that is to be connected.
210
* @p_unit_address: The unit address of the vty adapter to which the vty-server
211
* is to be connected.
212
*
213
* If this function is called once and -EINVAL is returned it may
214
* indicate that the partner info needs to be refreshed for the
215
* target unit address at which point the caller must invoke
216
* hvcs_get_partner_info() and then call this function again. If,
217
* for a second time, -EINVAL is returned then it indicates that
218
* there is probably already a partner connection registered to a
219
* different vty-server adapter. It is also possible that a second
220
* -EINVAL may indicate that one of the parms is not valid, for
221
* instance if the link was removed between the vty-server adapter
222
* and the vty adapter that you are trying to open. Don't shoot the
223
* messenger. Firmware implemented it this way.
224
*/
225
int hvcs_register_connection( uint32_t unit_address,
226
uint32_t p_partition_ID, uint32_t p_unit_address)
227
{
228
long retval;
229
retval = plpar_hcall_norets(H_REGISTER_VTERM, unit_address,
230
p_partition_ID, p_unit_address);
231
return hvcs_convert(retval);
232
}
233
EXPORT_SYMBOL(hvcs_register_connection);
234
235
/**
236
* hvcs_free_connection - free the connection between a vty-server and vty
237
* @unit_address: The unit address of the vty-server that is to have its
238
* connection severed.
239
*
240
* This function is used to free the partner connection between a vty-server
241
* adapter and a vty adapter.
242
*
243
* If -EBUSY is returned continue to call this function until 0 is returned.
244
*/
245
int hvcs_free_connection(uint32_t unit_address)
246
{
247
long retval;
248
retval = plpar_hcall_norets(H_FREE_VTERM, unit_address);
249
return hvcs_convert(retval);
250
}
251
EXPORT_SYMBOL(hvcs_free_connection);
252
253