Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | /* |
2 | * ========== Copyright Header Begin ========================================== | |
3 | * | |
4 | * Hypervisor Software File: res_network.c | |
5 | * | |
6 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
7 | * | |
8 | * - Do no alter or remove copyright notices | |
9 | * | |
10 | * - Redistribution and use of this software in source and binary forms, with | |
11 | * or without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistribution of source code must retain the above copyright notice, | |
15 | * this list of conditions and the following disclaimer. | |
16 | * | |
17 | * - Redistribution in binary form must reproduce the above copyright notice, | |
18 | * this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * | |
21 | * Neither the name of Sun Microsystems, Inc. or the names of contributors | |
22 | * may be used to endorse or promote products derived from this software | |
23 | * without specific prior written permission. | |
24 | * | |
25 | * This software is provided "AS IS," without a warranty of any kind. | |
26 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, | |
27 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
28 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN | |
29 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR | |
30 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
31 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN | |
32 | * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR | |
33 | * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE | |
34 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, | |
35 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF | |
36 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
37 | * | |
38 | * You acknowledge that this software is not designed, licensed or | |
39 | * intended for use in the design, construction, operation or maintenance of | |
40 | * any nuclear facility. | |
41 | * | |
42 | * ========== Copyright Header End ============================================ | |
43 | */ | |
44 | /* | |
45 | * Copyright 2007 Sun Microsystems, Inc. All rights reserved. | |
46 | * Use is subject to license terms. | |
47 | */ | |
48 | ||
49 | #pragma ident "@(#)res_network.c 1.3 07/06/07 SMI" | |
50 | ||
51 | ||
52 | /* | |
53 | * (re)-configuration code to handle HV network resources | |
54 | */ | |
55 | ||
56 | #include <stdarg.h> | |
57 | #include <sys/htypes.h> | |
58 | #include <hypervisor.h> | |
59 | #include <traps.h> | |
60 | #include <cache.h> | |
61 | #include <mmu.h> | |
62 | #include <sun4v/asi.h> | |
63 | #include <vdev_intr.h> | |
64 | #include <ncs.h> | |
65 | #include <cyclic.h> | |
66 | #include <support.h> | |
67 | #include <strand.h> | |
68 | #include <vcpu.h> | |
69 | #include <guest.h> | |
70 | #include <network.h> | |
71 | #include <vdev_ops.h> | |
72 | #include <config.h> | |
73 | #include <offsets.h> | |
74 | #include <hvctl.h> | |
75 | #include <md.h> | |
76 | #include <abort.h> | |
77 | #include <proto.h> | |
78 | #include <debug.h> | |
79 | ||
80 | #ifdef STANDALONE_NET_DEVICES | |
81 | ||
82 | /* | |
83 | * resource processing support | |
84 | */ | |
85 | static void res_network_device_commit_config(int i); | |
86 | static void res_network_device_commit_unconfig(int i); | |
87 | static hvctl_status_t res_network_device_parse_1(bin_md_t *mdp, | |
88 | md_element_t *network_device_nodep, | |
89 | hvctl_res_error_t *fail_codep, int *fail_res_idp); | |
90 | ||
91 | void config_a_guest_network_device(network_device_t *netp); | |
92 | void unconfig_a_guest_network_device(network_device_t *netp); | |
93 | ||
94 | void | |
95 | res_network_device_prep() | |
96 | { | |
97 | int i; | |
98 | network_device_t *netp; | |
99 | ||
100 | netp = (network_device_t *)config.network_devices; | |
101 | ||
102 | /* if the device is configured mark it for unconfiguring */ | |
103 | for (i = 0; i < NUM_NETWORK_DEVICES; i++) { | |
104 | netp[i].pip.res.flags = | |
105 | netp[i].guestp == NULL ? RESF_Noop : RESF_Unconfig; | |
106 | } | |
107 | } | |
108 | ||
109 | ||
110 | hvctl_status_t | |
111 | res_network_device_parse(bin_md_t *mdp, hvctl_res_error_t *fail_codep, | |
112 | md_element_t **failnodepp, int *fail_res_idp) | |
113 | { | |
114 | md_element_t *mdep, *net_nodep, *rootnodep; | |
115 | uint64_t arc_token; | |
116 | uint64_t name_token; | |
117 | ||
118 | mdp = (bin_md_t *)config.parse_hvmd; | |
119 | ||
120 | rootnodep = md_find_node(mdp, NULL, MDNAME(root)); | |
121 | if (rootnodep == NULL) { | |
122 | DBG(c_printf("Missing root node in HVMD\n")); | |
123 | goto fail; | |
124 | } | |
125 | DBGNET(c_printf("Network configuration:\n")); | |
126 | ||
127 | arc_token = MDARC(MDNAME(fwd)); | |
128 | name_token = MDNODE(MDNAME(devices)); | |
129 | ||
130 | if (md_find_node_by_arc(mdp, rootnodep, arc_token, name_token, | |
131 | &mdep) == NULL) { | |
132 | DBGNET(c_printf("Missing devices node in HVMD\n")); | |
133 | fail:; | |
134 | *failnodepp = NULL; | |
135 | *fail_res_idp = 0; | |
136 | return (HVctl_st_badmd); | |
137 | } | |
138 | ||
139 | DBGNET(md_dump_node(mdp, mdep)); | |
140 | ||
141 | name_token = MDNODE(MDNAME(network_device)); | |
142 | ||
143 | while (NULL != (mdep = md_find_node_by_arc(mdp, mdep, | |
144 | arc_token, name_token, &net_nodep))) { | |
145 | hvctl_status_t status; | |
146 | ||
147 | status = res_network_device_parse_1(mdp, net_nodep, fail_codep, | |
148 | fail_res_idp); | |
149 | if (status != HVctl_st_ok) { | |
150 | *failnodepp = net_nodep; | |
151 | return (status); | |
152 | } | |
153 | } | |
154 | return (HVctl_st_ok); | |
155 | } | |
156 | ||
157 | ||
158 | hvctl_status_t | |
159 | res_network_device_parse_1(bin_md_t *mdp, md_element_t *net_nodep, | |
160 | hvctl_res_error_t *fail_codep, int *fail_res_idp) | |
161 | { | |
162 | network_device_t *netp; | |
163 | uint64_t id; | |
164 | uint64_t guestid; | |
165 | uint64_t cfg_handle; | |
166 | md_element_t *guestnodep; | |
167 | ||
168 | DBGNET(c_printf("Parse network node\n")); | |
169 | ||
170 | DBGNET(md_dump_node(mdp, net_nodep)); | |
171 | ||
172 | if (!md_node_get_val(mdp, net_nodep, MDNAME(resource_id), &id)) { | |
173 | DBGNET(c_printf("Missing id in network node\n")); | |
174 | *fail_res_idp = 0; | |
175 | *fail_codep = HVctl_e_network_missing_prop; | |
176 | return (HVctl_st_badmd); | |
177 | } | |
178 | if (!md_node_get_val(mdp, net_nodep, MDNAME(cfghandle), &cfg_handle)) { | |
179 | DBGNET(c_printf("Missing cfg-handle in network node\n")); | |
180 | *fail_res_idp = 0; | |
181 | *fail_codep = HVctl_e_network_missing_prop; | |
182 | return (HVctl_st_badmd); | |
183 | } | |
184 | ||
185 | if (id >= NUM_NETWORK_DEVICES) { | |
186 | DBGNET(c_printf("Invalid id 0x%x in network node\n", id)); | |
187 | *fail_res_idp = 0; | |
188 | ill_prop: | |
189 | *fail_codep = HVctl_e_network_illegal_prop; | |
190 | return (HVctl_st_badmd); | |
191 | } | |
192 | ||
193 | DBGNET(c_printf("\tNetwork device 0x%x :\n", id)); | |
194 | ||
195 | if (NULL == md_find_node_by_arc(mdp, net_nodep, | |
196 | MDARC(MDNAME(back)), MDNODE(MDNAME(guest)), &guestnodep)) { | |
197 | DBGNET(c_printf("Missing back arc to guest node in " | |
198 | "network node\n")); | |
199 | *fail_codep = HVctl_e_network_missing_guest; | |
200 | goto ill_prop; | |
201 | } | |
202 | if (!md_node_get_val(mdp, guestnodep, MDNAME(resource_id), &guestid)) { | |
203 | DBGNET(c_printf("Missing resource_id in guest node\n")); | |
204 | *fail_codep = HVctl_e_guest_missing_id; | |
205 | goto ill_prop; | |
206 | } | |
207 | if (guestid >= NGUESTS) { | |
208 | DBGNET(c_printf("Invalid resource_id %d in guest node\n", | |
209 | guestid)); | |
210 | *fail_codep = HVctl_e_guest_invalid_id; | |
211 | goto ill_prop; | |
212 | } | |
213 | ||
214 | netp = config.network_devices; | |
215 | netp = &(netp[id]); | |
216 | netp->cfg_handle = cfg_handle; | |
217 | netp->id = id; | |
218 | ||
219 | /* Possible sanity checks on guest validity */ | |
220 | if (netp->guestp == NULL) { | |
221 | netp->pip.res.flags = RESF_Config; | |
222 | netp->pip.guestid = guestid; | |
223 | DBGNET(c_printf("\tElected to config network device\n")); | |
224 | } else { | |
225 | guest_t *guestp; | |
226 | ||
227 | guestp = config.guests; | |
228 | if (&(guestp[guestid]) != netp->guestp) { | |
229 | DBGNET(c_printf( | |
230 | "Cannot rebind/modify a network device\n")); | |
231 | *fail_codep = HVctl_e_network_rebind_na; | |
232 | return (HVctl_st_eillegal); | |
233 | } | |
234 | DBGNET(c_printf("Elected to ignore network device\n")); | |
235 | netp->pip.res.flags = RESF_Noop; | |
236 | } | |
237 | ||
238 | return (HVctl_st_ok); | |
239 | } | |
240 | ||
241 | ||
242 | hvctl_status_t | |
243 | res_network_device_postparse(hvctl_res_error_t *res_error, int *fail_res_id) | |
244 | { | |
245 | return (HVctl_st_ok); | |
246 | } | |
247 | ||
248 | ||
249 | void | |
250 | res_network_device_commit(int flag) | |
251 | { | |
252 | int i; | |
253 | network_device_t *network_devices; | |
254 | ||
255 | network_devices = (network_device_t *)config.network_devices; | |
256 | ||
257 | for (i = 0; i < NUM_NETWORK_DEVICES; i++) { | |
258 | network_device_t *netp; | |
259 | ||
260 | netp = &(network_devices[i]); | |
261 | ||
262 | /* if not this ops turn move on */ | |
263 | if (netp->pip.res.flags != flag) continue; | |
264 | ||
265 | switch (netp->pip.res.flags) { | |
266 | case RESF_Noop: | |
267 | DBGNET(c_printf("network 0x%x : noop\n", i)); | |
268 | break; | |
269 | case RESF_Unconfig: | |
270 | res_network_device_commit_unconfig(i); | |
271 | break; | |
272 | case RESF_Config: | |
273 | res_network_device_commit_config(i); | |
274 | break; | |
275 | case RESF_Rebind: | |
276 | DBGNET(c_printf("network 0x%x : rebind\n", i)); | |
277 | ASSERT(0); /* not supported */ | |
278 | break; | |
279 | case RESF_Modify: | |
280 | DBGNET(c_printf("Network 0x%x : modify\n", i)); | |
281 | ASSERT(0); /* not supported */ | |
282 | break; | |
283 | default: | |
284 | ASSERT(0); | |
285 | } | |
286 | ||
287 | netp->pip.res.flags = RESF_Noop; /* cleanup */ | |
288 | } | |
289 | } | |
290 | ||
291 | ||
292 | void | |
293 | res_network_device_commit_config(int devid) | |
294 | { | |
295 | network_device_t *netp; | |
296 | guest_t *guestp; | |
297 | ||
298 | netp = (network_device_t *)config.network_devices; | |
299 | guestp = (guest_t *)config.guests; | |
300 | ||
301 | netp = &(netp[devid]); | |
302 | ||
303 | ASSERT(netp->guestp == NULL); | |
304 | ||
305 | DBGNET(c_printf("\tnetwork device 0x%x configuring for guest 0x%x\n", | |
306 | devid, netp->pip.guestid)); | |
307 | ||
308 | guestp = &(guestp[netp->pip.guestid]); | |
309 | ||
310 | netp->guestp = guestp; | |
311 | ||
312 | config_a_guest_network_device(netp); | |
313 | } | |
314 | ||
315 | ||
316 | void | |
317 | res_network_device_commit_unconfig(int devid) | |
318 | { | |
319 | network_device_t *netp; | |
320 | ||
321 | netp = (network_device_t *)config.network_devices; | |
322 | netp = &(netp[devid]); | |
323 | ||
324 | ASSERT(netp->guestp != NULL); | |
325 | ||
326 | /* | |
327 | * If the owning guest is still live we have a problem. | |
328 | * We would like to reset the network device as part of the | |
329 | * unconfigure, but the reset delay could cause a mondo timeout | |
330 | * on the hvctl channel vcpu. | |
331 | * | |
332 | * So we assume that since we can't DR network devices, that | |
333 | * the guest must be stopped before this can be done. | |
334 | */ | |
335 | if (netp->guestp->state != GUEST_STATE_STOPPED) { | |
336 | DBGNET(c_printf( | |
337 | "\tWARNING: network device unconfigure should reset " | |
338 | "network device 0x%x\n", devid)); | |
339 | } | |
340 | ||
341 | DBGNET(c_printf("\tnetwork device 0x%x unconfigured\n", devid)); | |
342 | unconfig_a_guest_network_device(netp); | |
343 | netp->guestp = NULL; | |
344 | } | |
345 | ||
346 | #endif /* STANDALONE_NET_DEVICES */ |