Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/xen/io/xpvd.c
+++ new/usr/src/uts/common/xen/io/xpvd.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26 /*
27 27 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
28 28 */
29 29
30 30 /*
31 31 * Host to hypervisor virtual devices nexus driver
32 32 *
33 33 * TODO:
34 34 * - Add watchpoints on vbd/vif and enumerate/offline on watch callback
35 35 * - Add DR IOCTLs
36 36 * - Filter/restrict property lookups into xenstore
37 37 */
38 38
39 39 #include <sys/conf.h>
40 40 #include <sys/kmem.h>
41 41 #include <sys/debug.h>
42 42 #include <sys/modctl.h>
43 43 #include <sys/autoconf.h>
44 44 #include <sys/ddi_impldefs.h>
45 45 #include <sys/ddi_subrdefs.h>
46 46 #include <sys/ddi.h>
47 47 #include <sys/sunddi.h>
48 48 #include <sys/sunndi.h>
49 49 #include <sys/avintr.h>
50 50 #include <sys/psm.h>
51 51 #include <sys/spl.h>
52 52 #include <sys/promif.h>
53 53 #include <sys/list.h>
54 54 #include <sys/bootconf.h>
55 55 #include <sys/bootsvcs.h>
56 56 #include <util/sscanf.h>
57 57 #include <sys/mach_intr.h>
58 58 #include <sys/bootinfo.h>
59 59 #ifdef XPV_HVM_DRIVER
60 60 #include <sys/xpv_support.h>
61 61 #include <sys/hypervisor.h>
62 62 #include <sys/archsystm.h>
63 63 #include <sys/cpu.h>
64 64 #include <public/xen.h>
65 65 #include <public/event_channel.h>
66 66 #include <public/io/xenbus.h>
67 67 #else
68 68 #include <sys/hypervisor.h>
69 69 #include <sys/evtchn_impl.h>
70 70 #include <sys/xen_mmu.h>
71 71 #endif
72 72 #include <xen/sys/xenbus_impl.h>
73 73 #include <xen/sys/xendev.h>
74 74
75 75 /*
76 76 * DDI dev_ops entrypoints
77 77 */
78 78 static int xpvd_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
79 79 static int xpvd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
80 80 static int xpvd_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
81 81
82 82
83 83 /*
84 84 * NDI bus_ops entrypoints
85 85 */
86 86 static int xpvd_ctlops(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *,
87 87 void *);
88 88 static int xpvd_intr_ops(dev_info_t *, dev_info_t *, ddi_intr_op_t,
89 89 ddi_intr_handle_impl_t *, void *);
90 90 static int xpvd_prop_op(dev_t, dev_info_t *, dev_info_t *, ddi_prop_op_t,
91 91 int, char *, caddr_t, int *);
92 92 static int xpvd_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t,
93 93 void *, dev_info_t **);
94 94 static int xpvd_bus_unconfig(dev_info_t *, uint_t, ddi_bus_config_op_t,
95 95 void *);
96 96 static int xpvd_get_eventcookie(dev_info_t *, dev_info_t *,
97 97 char *, ddi_eventcookie_t *);
98 98 static int xpvd_add_eventcall(dev_info_t *, dev_info_t *,
99 99 ddi_eventcookie_t, void (*)(dev_info_t *,
100 100 ddi_eventcookie_t, void *, void *),
101 101 void *, ddi_callback_id_t *);
102 102 static int xpvd_remove_eventcall(dev_info_t *, ddi_callback_id_t);
103 103 static int xpvd_post_event(dev_info_t *, dev_info_t *,
104 104 ddi_eventcookie_t, void *);
105 105
106 106 /*
107 107 * misc functions
108 108 */
109 109 static int xpvd_enable_intr(dev_info_t *, ddi_intr_handle_impl_t *, int);
110 110 static void xpvd_disable_intr(dev_info_t *, ddi_intr_handle_impl_t *, int);
111 111 static int xpvd_removechild(dev_info_t *);
112 112 static int xpvd_initchild(dev_info_t *);
113 113 static int xpvd_name_child(dev_info_t *, char *, int);
114 114 static boolean_t i_xpvd_parse_devname(char *, xendev_devclass_t *,
115 115 domid_t *, int *);
116 116
117 117
118 118 /* Extern declarations */
119 119 extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
120 120 psm_intr_op_t, int *);
121 121
122 122 struct bus_ops xpvd_bus_ops = {
123 123 BUSO_REV,
124 124 i_ddi_bus_map,
125 125 NULL,
126 126 NULL,
127 127 NULL,
128 128 i_ddi_map_fault,
129 129 NULL,
130 130 ddi_dma_allochdl,
131 131 ddi_dma_freehdl,
132 132 ddi_dma_bindhdl,
133 133 ddi_dma_unbindhdl,
134 134 ddi_dma_flush,
135 135 ddi_dma_win,
136 136 ddi_dma_mctl,
137 137 xpvd_ctlops,
138 138 xpvd_prop_op,
139 139 xpvd_get_eventcookie,
140 140 xpvd_add_eventcall,
141 141 xpvd_remove_eventcall,
142 142 xpvd_post_event,
143 143 0, /* (*bus_intr_ctl)(); */
144 144 xpvd_bus_config,
145 145 xpvd_bus_unconfig,
146 146 NULL, /* (*bus_fm_init)(); */
147 147 NULL, /* (*bus_fm_fini)(); */
148 148 NULL, /* (*bus_fm_access_enter)(); */
149 149 NULL, /* (*bus_fm_access_exit)(); */
150 150 NULL, /* (*bus_power)(); */
151 151 xpvd_intr_ops /* (*bus_intr_op)(); */
152 152 };
153 153
154 154 struct dev_ops xpvd_ops = {
155 155 DEVO_REV, /* devo_rev */
156 156 0, /* refcnt */
157 157 xpvd_info, /* info */
158 158 nulldev, /* identify */
159 159 nulldev, /* probe */
160 160 xpvd_attach, /* attach */
161 161 xpvd_detach, /* detach */
162 162 nulldev, /* reset */
163 163 (struct cb_ops *)0, /* driver operations */
164 164 &xpvd_bus_ops, /* bus operations */
165 165 NULL, /* power */
166 166 ddi_quiesce_not_needed, /* quiesce */
167 167 };
168 168
169 169
170 170 dev_info_t *xpvd_dip;
171 171
172 172 #define CF_DBG 0x1
173 173 #define ALL_DBG 0xff
174 174
175 175 static ndi_event_definition_t xpvd_ndi_event_defs[] = {
176 176 { 0, XS_OE_STATE, EPL_KERNEL, NDI_EVENT_POST_TO_TGT },
177 177 { 1, XS_HP_STATE, EPL_KERNEL, NDI_EVENT_POST_TO_TGT },
178 178 };
179 179
180 180 #define XENDEV_N_NDI_EVENTS \
181 181 (sizeof (xpvd_ndi_event_defs) / sizeof (xpvd_ndi_event_defs[0]))
182 182
183 183 static ndi_event_set_t xpvd_ndi_events = {
184 184 NDI_EVENTS_REV1, XENDEV_N_NDI_EVENTS, xpvd_ndi_event_defs
185 185 };
186 186
187 187 static ndi_event_hdl_t xpvd_ndi_event_handle;
188 188
189 189 /*
190 190 * Hypervisor interrupt capabilities
191 191 */
192 192 #define XENDEV_INTR_CAPABILITIES \
193 193 (DDI_INTR_FLAG_EDGE | DDI_INTR_FLAG_MASKABLE | DDI_INTR_FLAG_PENDING)
194 194
195 195 /*
196 196 * Module linkage information for the kernel.
↓ open down ↓ |
196 lines elided |
↑ open up ↑ |
197 197 */
198 198
199 199 static struct modldrv modldrv = {
200 200 &mod_driverops, /* Type of module */
201 201 "virtual device nexus driver",
202 202 &xpvd_ops, /* driver ops */
203 203 };
204 204
205 205 static struct modlinkage modlinkage = {
206 206 MODREV_1,
207 - (void *)&modldrv,
208 - NULL
207 + { (void *)&modldrv, NULL }
209 208 };
210 209
211 210 int
212 211 _init(void)
213 212 {
214 213 return (mod_install(&modlinkage));
215 214 }
216 215
217 216 int
218 217 _fini(void)
219 218 {
220 219 return (mod_remove(&modlinkage));
221 220 }
222 221
223 222 int
224 223 _info(struct modinfo *modinfop)
225 224 {
226 225 return (mod_info(&modlinkage, modinfop));
227 226 }
228 227
229 228 /* ARGSUSED */
230 229 static int
231 230 xpvd_info(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
232 231 {
233 232 switch (cmd) {
234 233 default:
235 234 return (DDI_FAILURE);
236 235
237 236 case DDI_INFO_DEVT2INSTANCE:
238 237 *result = (void *)0;
239 238 return (DDI_SUCCESS);
240 239
241 240 case DDI_INFO_DEVT2DEVINFO:
242 241 *result = (void *)xpvd_dip;
243 242 return (DDI_SUCCESS);
244 243 }
245 244 }
246 245
247 246 /*ARGSUSED*/
248 247 static int
249 248 xpvd_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
250 249 {
251 250 extern void xvdi_watch_devices(int);
252 251 #ifdef XPV_HVM_DRIVER
253 252 extern dev_info_t *xpv_dip;
254 253
255 254 if (xpv_dip == NULL) {
256 255 if (ddi_hold_installed_driver(ddi_name_to_major("xpv")) ==
257 256 NULL) {
258 257 cmn_err(CE_WARN, "Couldn't initialize xpv framework");
259 258 return (DDI_FAILURE);
260 259 }
261 260 }
262 261 #endif /* XPV_HVM_DRIVER */
263 262
264 263 if (ndi_event_alloc_hdl(devi, 0, &xpvd_ndi_event_handle,
265 264 NDI_SLEEP) != NDI_SUCCESS) {
266 265 xpvd_dip = NULL;
267 266 return (DDI_FAILURE);
268 267 }
269 268 if (ndi_event_bind_set(xpvd_ndi_event_handle, &xpvd_ndi_events,
270 269 NDI_SLEEP) != NDI_SUCCESS) {
271 270 (void) ndi_event_free_hdl(xpvd_ndi_event_handle);
272 271 xpvd_dip = NULL;
273 272 return (DDI_FAILURE);
274 273 }
275 274
276 275 #ifdef XPV_HVM_DRIVER
277 276 (void) ddi_prop_update_int(DDI_DEV_T_NONE, devi, DDI_NO_AUTODETACH, 1);
278 277
279 278 /*
280 279 * Report our version to dom0.
281 280 */
282 281 if (xenbus_printf(XBT_NULL, "guest/xpvd", "version", "%d",
283 282 HVMPV_XPVD_VERS))
284 283 cmn_err(CE_WARN, "xpvd: couldn't write version\n");
285 284 #endif /* XPV_HVM_DRIVER */
286 285
287 286 /* watch both frontend and backend for new devices */
288 287 if (DOMAIN_IS_INITDOMAIN(xen_info))
289 288 (void) xs_register_xenbus_callback(xvdi_watch_devices);
290 289 else
291 290 xvdi_watch_devices(XENSTORE_UP);
292 291
293 292 xpvd_dip = devi;
294 293 ddi_report_dev(devi);
295 294
296 295 return (DDI_SUCCESS);
297 296 }
298 297
299 298 /*ARGSUSED*/
300 299 static int
301 300 xpvd_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
302 301 {
303 302 return (DDI_FAILURE);
304 303 }
305 304
306 305 /*
307 306 * xpvd_prop_op()
308 307 *
309 308 * Query xenstore for the value of properties if DDI_PROP_NOTPROM
310 309 * is not set. Xenstore property values are represented as ascii strings.
311 310 */
312 311 static int
313 312 xpvd_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
314 313 ddi_prop_op_t prop_op, int mod_flags, char *name, caddr_t valuep,
315 314 int *lengthp)
316 315 {
317 316 caddr_t buff;
318 317 struct xendev_ppd *pdp;
319 318 void *prop_str;
320 319 size_t prop_len;
321 320 unsigned int len;
322 321 int rv;
323 322
324 323 pdp = (struct xendev_ppd *)ddi_get_parent_data(ch_dip);
325 324
326 325 if ((pdp == NULL) || !(mod_flags & (DDI_PROP_CANSLEEP)) ||
327 326 (mod_flags & DDI_PROP_NOTPROM) || (pdp->xd_xsdev.nodename == NULL))
328 327 goto toss_off;
329 328 /*
330 329 * First try reading the property off the the frontend. if that
331 330 * fails, try and read it from the backend node. If that
332 331 * also fails, pass the request on the DDI framework
333 332 */
334 333 prop_str = NULL;
335 334 if ((xenbus_read(XBT_NULL, pdp->xd_xsdev.nodename, name, &prop_str,
336 335 &len) == 0) && (prop_str != NULL) && (strlen(prop_str) != 0))
337 336 goto got_xs_prop;
338 337
339 338 prop_str = NULL;
340 339 if ((pdp->xd_xsdev.otherend != NULL) &&
341 340 (xenbus_read(XBT_NULL, pdp->xd_xsdev.otherend, name, &prop_str,
342 341 &len) == 0) && (prop_str != NULL) && (strlen(prop_str) != 0))
343 342 goto got_xs_prop;
344 343
345 344 toss_off:
346 345 return (ddi_bus_prop_op(dev, dip, ch_dip, prop_op,
347 346 mod_flags | DDI_PROP_NOTPROM, name, valuep, lengthp));
348 347
349 348 got_xs_prop:
350 349 prop_len = strlen(prop_str) + 1;
351 350 rv = DDI_PROP_SUCCESS;
352 351
353 352 switch (prop_op) {
354 353 case PROP_LEN:
355 354 *lengthp = prop_len;
356 355 break;
357 356
358 357 case PROP_LEN_AND_VAL_ALLOC:
359 358 buff = kmem_alloc((size_t)prop_len, KM_SLEEP);
360 359 *(caddr_t *)valuep = (caddr_t)buff;
361 360 break;
362 361 case PROP_LEN_AND_VAL_BUF:
363 362 buff = (caddr_t)valuep;
364 363 if (*lengthp < prop_len)
365 364 rv = DDI_PROP_BUF_TOO_SMALL;
366 365 break;
367 366 default:
368 367 rv = DDI_PROP_INVAL_ARG;
369 368 break;
370 369 }
371 370
372 371 if ((rv == DDI_PROP_SUCCESS) && (prop_len > 0)) {
373 372 bcopy(prop_str, buff, prop_len);
374 373 *lengthp = prop_len;
375 374 }
376 375 kmem_free(prop_str, len);
377 376 return (rv);
378 377 }
379 378
380 379
381 380 /*
382 381 * return address of the device's interrupt spec structure.
383 382 */
384 383 /*ARGSUSED*/
385 384 struct intrspec *
386 385 xpvd_get_ispec(dev_info_t *rdip, uint_t inumber)
387 386 {
388 387 struct xendev_ppd *pdp;
389 388
390 389 ASSERT(inumber == 0);
391 390
392 391 if ((pdp = ddi_get_parent_data(rdip)) == NULL)
393 392 return (NULL);
394 393
395 394 return (&pdp->xd_ispec);
396 395 }
397 396
398 397 /*
399 398 * return (and determine) the interrupt priority of the device.
400 399 */
401 400 /*ARGSUSED*/
402 401 static int
403 402 xpvd_get_priority(dev_info_t *dip, int inum, int *pri)
404 403 {
405 404 struct xendev_ppd *pdp;
406 405 struct intrspec *ispec;
407 406 int *intpriorities;
408 407 uint_t num_intpriorities;
409 408
410 409 DDI_INTR_NEXDBG((CE_CONT, "xpvd_get_priority: dip = 0x%p\n",
411 410 (void *)dip));
412 411
413 412 ASSERT(inum == 0);
414 413
415 414 if ((pdp = ddi_get_parent_data(dip)) == NULL)
416 415 return (DDI_FAILURE);
417 416
418 417 ispec = &pdp->xd_ispec;
419 418
420 419 /*
421 420 * Set the default priority based on the device class. The
422 421 * "interrupt-priorities" property can be used to override
423 422 * the default.
424 423 */
425 424 if (ispec->intrspec_pri == 0) {
426 425 ispec->intrspec_pri = xendev_devclass_ipl(pdp->xd_devclass);
427 426 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
428 427 DDI_PROP_NOTPROM | DDI_PROP_DONTPASS,
429 428 "interrupt-priorities", &intpriorities,
430 429 &num_intpriorities) == DDI_PROP_SUCCESS) {
431 430 ispec->intrspec_pri = intpriorities[0];
432 431 ddi_prop_free(intpriorities);
433 432 }
434 433 }
435 434 *pri = ispec->intrspec_pri;
436 435 return (DDI_SUCCESS);
437 436 }
438 437
439 438
440 439 /*
441 440 * xpvd_intr_ops: bus_intr_op() function for interrupt support
442 441 */
443 442 /* ARGSUSED */
444 443 static int
445 444 xpvd_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
446 445 ddi_intr_handle_impl_t *hdlp, void *result)
447 446 {
448 447 int priority = 0;
449 448 struct intrspec *ispec;
450 449 struct xendev_ppd *pdp;
451 450
452 451 DDI_INTR_NEXDBG((CE_CONT,
453 452 "xpvd_intr_ops: pdip 0x%p, rdip 0x%p, op %x handle 0x%p\n",
454 453 (void *)pdip, (void *)rdip, intr_op, (void *)hdlp));
455 454
456 455 /* Process the request */
457 456 switch (intr_op) {
458 457 case DDI_INTROP_SUPPORTED_TYPES:
459 458 /* Fixed supported by default */
460 459 *(int *)result = DDI_INTR_TYPE_FIXED;
461 460 break;
462 461
463 462 case DDI_INTROP_NINTRS:
464 463 *(int *)result = 1;
465 464 break;
466 465
467 466 case DDI_INTROP_ALLOC:
468 467 /*
469 468 * FIXED interrupts: just return available interrupts
470 469 */
471 470 if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
472 471 /*
473 472 * event channels are edge-triggered, maskable,
474 473 * and support int pending.
475 474 */
476 475 hdlp->ih_cap |= XENDEV_INTR_CAPABILITIES;
477 476 *(int *)result = 1; /* DDI_INTR_TYPE_FIXED */
478 477 } else {
479 478 return (DDI_FAILURE);
480 479 }
481 480 break;
482 481
483 482 case DDI_INTROP_FREE:
484 483 ispec = xpvd_get_ispec(rdip, (int)hdlp->ih_inum);
485 484 if (ispec == NULL)
486 485 return (DDI_FAILURE);
487 486 ispec->intrspec_pri = 0; /* mark as un-initialized */
488 487 break;
489 488
490 489 case DDI_INTROP_GETPRI:
491 490 if (xpvd_get_priority(rdip, hdlp->ih_inum, &priority) !=
492 491 DDI_SUCCESS)
493 492 return (DDI_FAILURE);
494 493 DDI_INTR_NEXDBG((CE_CONT, "xpvd_intr_ops: priority = 0x%x\n",
495 494 priority));
496 495 *(int *)result = priority;
497 496 break;
498 497
499 498 case DDI_INTROP_SETPRI:
500 499 /* Validate the interrupt priority passed */
501 500 if (*(int *)result > LOCK_LEVEL)
502 501 return (DDI_FAILURE);
503 502
504 503 /* Ensure that PSM is all initialized */
505 504 if (psm_intr_ops == NULL)
506 505 return (DDI_FAILURE);
507 506
508 507 /* Change the priority */
509 508 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_PRI, result) ==
510 509 PSM_FAILURE)
511 510 return (DDI_FAILURE);
512 511
513 512 ispec = xpvd_get_ispec(rdip, (int)hdlp->ih_inum);
514 513 if (ispec == NULL)
515 514 return (DDI_FAILURE);
516 515 ispec->intrspec_pri = *(int *)result;
517 516 break;
518 517
519 518 case DDI_INTROP_ADDISR:
520 519 /* update ispec */
521 520 ispec = xpvd_get_ispec(rdip, (int)hdlp->ih_inum);
522 521 if (ispec == NULL)
523 522 return (DDI_FAILURE);
524 523 ispec->intrspec_func = hdlp->ih_cb_func;
525 524
526 525 break;
527 526
528 527 case DDI_INTROP_REMISR:
529 528 ispec = xpvd_get_ispec(rdip, (int)hdlp->ih_inum);
530 529 pdp = (struct xendev_ppd *)ddi_get_parent_data(rdip);
531 530
532 531 ASSERT(pdp != NULL);
533 532 ASSERT(pdp->xd_evtchn != INVALID_EVTCHN);
534 533
535 534 if (ispec) {
536 535 ispec->intrspec_vec = 0;
537 536 ispec->intrspec_func = (uint_t (*)()) 0;
538 537 }
539 538 pdp->xd_evtchn = INVALID_EVTCHN;
540 539 break;
541 540
542 541 case DDI_INTROP_GETCAP:
543 542 if (hdlp->ih_type == DDI_INTR_TYPE_FIXED) {
544 543 /*
545 544 * event channels are edge-triggered, maskable,
546 545 * and support int pending.
547 546 */
548 547 *(int *)result = XENDEV_INTR_CAPABILITIES;
549 548 } else {
550 549 *(int *)result = 0;
551 550 return (DDI_FAILURE);
552 551 }
553 552 DDI_INTR_NEXDBG((CE_CONT, "xpvd: GETCAP returned = %x\n",
554 553 *(int *)result));
555 554 break;
556 555 case DDI_INTROP_SETCAP:
557 556 DDI_INTR_NEXDBG((CE_CONT, "xpvd_intr_ops: SETCAP cap=0x%x\n",
558 557 *(int *)result));
559 558 if (psm_intr_ops == NULL)
560 559 return (DDI_FAILURE);
561 560
562 561 if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result)) {
563 562 DDI_INTR_NEXDBG((CE_CONT, "GETCAP: psm_intr_ops"
564 563 " returned failure\n"));
565 564 return (DDI_FAILURE);
566 565 }
567 566 break;
568 567
569 568 case DDI_INTROP_ENABLE:
570 569 if (psm_intr_ops == NULL)
571 570 return (DDI_FAILURE);
572 571
573 572 if (xpvd_enable_intr(rdip, hdlp, (int)hdlp->ih_inum) !=
574 573 DDI_SUCCESS)
575 574 return (DDI_FAILURE);
576 575
577 576 DDI_INTR_NEXDBG((CE_CONT, "xpvd_intr_ops: ENABLE vec=0x%x\n",
578 577 hdlp->ih_vector));
579 578 break;
580 579
581 580 case DDI_INTROP_DISABLE:
582 581 if (psm_intr_ops == NULL)
583 582 return (DDI_FAILURE);
584 583 xpvd_disable_intr(rdip, hdlp, hdlp->ih_inum);
585 584 DDI_INTR_NEXDBG((CE_CONT, "xpvd_intr_ops: DISABLE vec = %x\n",
586 585 hdlp->ih_vector));
587 586 break;
588 587
589 588 case DDI_INTROP_BLOCKENABLE:
590 589 case DDI_INTROP_BLOCKDISABLE:
591 590 return (DDI_FAILURE);
592 591
593 592 case DDI_INTROP_SETMASK:
594 593 case DDI_INTROP_CLRMASK:
595 594 #ifdef XPV_HVM_DRIVER
596 595 return (DDI_ENOTSUP);
597 596 #else
598 597 /*
599 598 * Handle this here
600 599 */
601 600 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
602 601 return (DDI_FAILURE);
603 602 if (intr_op == DDI_INTROP_SETMASK) {
604 603 ec_disable_irq(hdlp->ih_vector);
605 604 } else {
606 605 ec_enable_irq(hdlp->ih_vector);
607 606 }
608 607 break;
609 608 #endif
610 609 case DDI_INTROP_GETPENDING:
611 610 #ifdef XPV_HVM_DRIVER
612 611 return (DDI_ENOTSUP);
613 612 #else
614 613 if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
615 614 return (DDI_FAILURE);
616 615 *(int *)result = ec_pending_irq(hdlp->ih_vector);
617 616 DDI_INTR_NEXDBG((CE_CONT, "xpvd: GETPENDING returned = %x\n",
618 617 *(int *)result));
619 618 break;
620 619 #endif
621 620
622 621 case DDI_INTROP_NAVAIL:
623 622 *(int *)result = 1;
624 623 DDI_INTR_NEXDBG((CE_CONT, "xpvd: NAVAIL returned = %x\n",
625 624 *(int *)result));
626 625 break;
627 626
628 627 default:
629 628 return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));
630 629 }
631 630
632 631 return (DDI_SUCCESS);
633 632 }
634 633
635 634
636 635 static int
637 636 xpvd_enable_intr(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp, int inum)
638 637 {
639 638 int vector;
640 639 ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
641 640
642 641 DDI_INTR_NEXDBG((CE_CONT, "xpvd_enable_intr: hdlp %p inum %x\n",
643 642 (void *)hdlp, inum));
644 643
645 644 ihdl_plat_datap->ip_ispecp = xpvd_get_ispec(rdip, inum);
646 645 if (ihdl_plat_datap->ip_ispecp == NULL)
647 646 return (DDI_FAILURE);
648 647
649 648 /* translate the interrupt if needed */
650 649 (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &vector);
651 650 DDI_INTR_NEXDBG((CE_CONT, "xpvd_enable_intr: priority=%x vector=%x\n",
652 651 hdlp->ih_pri, vector));
653 652
654 653 /* Add the interrupt handler */
655 654 if (!add_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func,
656 655 DEVI(rdip)->devi_name, vector, hdlp->ih_cb_arg1,
657 656 hdlp->ih_cb_arg2, NULL, rdip))
658 657 return (DDI_FAILURE);
659 658
660 659 /* Note this really is an irq. */
661 660 hdlp->ih_vector = (ushort_t)vector;
662 661
663 662 return (DDI_SUCCESS);
664 663 }
665 664
666 665
667 666 static void
668 667 xpvd_disable_intr(dev_info_t *rdip, ddi_intr_handle_impl_t *hdlp, int inum)
669 668 {
670 669 int vector;
671 670 ihdl_plat_t *ihdl_plat_datap = (ihdl_plat_t *)hdlp->ih_private;
672 671
673 672 DDI_INTR_NEXDBG((CE_CONT, "xpvd_disable_intr: \n"));
674 673 ihdl_plat_datap->ip_ispecp = xpvd_get_ispec(rdip, inum);
675 674 if (ihdl_plat_datap->ip_ispecp == NULL)
676 675 return;
677 676
678 677 /* translate the interrupt if needed */
679 678 (void) (*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR, &vector);
680 679
681 680 /* Disable the interrupt handler */
682 681 rem_avintr((void *)hdlp, hdlp->ih_pri, hdlp->ih_cb_func, vector);
683 682 ihdl_plat_datap->ip_ispecp = NULL;
684 683 }
685 684
686 685 /*ARGSUSED*/
687 686 static int
688 687 xpvd_ctlops(dev_info_t *dip, dev_info_t *rdip,
689 688 ddi_ctl_enum_t ctlop, void *arg, void *result)
690 689 {
691 690 switch (ctlop) {
692 691 case DDI_CTLOPS_REPORTDEV:
693 692 if (rdip == (dev_info_t *)0)
694 693 return (DDI_FAILURE);
695 694 cmn_err(CE_CONT, "?%s@%s, %s%d\n", ddi_node_name(rdip),
696 695 ddi_get_name_addr(rdip), ddi_driver_name(rdip),
697 696 ddi_get_instance(rdip));
698 697 return (DDI_SUCCESS);
699 698
700 699 case DDI_CTLOPS_INITCHILD:
701 700 return (xpvd_initchild((dev_info_t *)arg));
702 701
703 702 case DDI_CTLOPS_UNINITCHILD:
704 703 return (xpvd_removechild((dev_info_t *)arg));
705 704
706 705 case DDI_CTLOPS_SIDDEV:
707 706 return (DDI_SUCCESS);
708 707
709 708 case DDI_CTLOPS_REGSIZE:
710 709 case DDI_CTLOPS_NREGS:
711 710 return (DDI_FAILURE);
712 711
713 712 case DDI_CTLOPS_POWER: {
714 713 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
715 714 }
716 715
717 716 default:
718 717 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
719 718 }
720 719
721 720 /* NOTREACHED */
722 721
723 722 }
724 723
725 724 /*
726 725 * Assign the address portion of the node name
727 726 */
728 727 static int
729 728 xpvd_name_child(dev_info_t *child, char *addr, int addrlen)
730 729 {
731 730 int *domain, *vdev;
732 731 uint_t ndomain, nvdev;
733 732 char *prop_str;
734 733
735 734 /*
736 735 * i_xpvd_parse_devname() knows the formats used by this
737 736 * routine. If this code changes, so must that.
738 737 */
739 738
740 739 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
741 740 "domain", &domain, &ndomain) != DDI_PROP_SUCCESS)
742 741 return (DDI_FAILURE);
743 742 ASSERT(ndomain == 1);
744 743
745 744 /*
746 745 * Use "domain" and "vdev" properties (backend drivers).
747 746 */
748 747 if (*domain != DOMID_SELF) {
749 748 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child,
750 749 DDI_PROP_DONTPASS, "vdev", &vdev, &nvdev)
751 750 != DDI_PROP_SUCCESS) {
752 751 ddi_prop_free(domain);
753 752 return (DDI_FAILURE);
754 753 }
755 754 ASSERT(nvdev == 1);
756 755
757 756 (void) snprintf(addr, addrlen, "%d,%d", domain[0], vdev[0]);
758 757 ddi_prop_free(vdev);
759 758 ddi_prop_free(domain);
760 759 return (DDI_SUCCESS);
761 760 }
762 761 ddi_prop_free(domain);
763 762
764 763 /*
765 764 * Use "unit-address" property (frontend/softdev drivers).
766 765 */
767 766 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
768 767 "unit-address", &prop_str) != DDI_PROP_SUCCESS)
769 768 return (DDI_FAILURE);
770 769 (void) strlcpy(addr, prop_str, addrlen);
771 770 ddi_prop_free(prop_str);
772 771 return (DDI_SUCCESS);
773 772 }
774 773
775 774 static int
776 775 xpvd_initchild(dev_info_t *child)
777 776 {
778 777 char addr[80];
779 778
780 779 /*
781 780 * Pseudo nodes indicate a prototype node with per-instance
782 781 * properties to be merged into the real h/w device node.
783 782 */
784 783 if (ndi_dev_is_persistent_node(child) == 0) {
785 784 ddi_set_parent_data(child, NULL);
786 785
787 786 /*
788 787 * Try to merge the properties from this prototype
789 788 * node into real h/w nodes.
790 789 */
791 790 if (ndi_merge_node(child, xpvd_name_child) == DDI_SUCCESS) {
792 791 /*
793 792 * Merged ok - return failure to remove the node.
794 793 */
795 794 ddi_set_name_addr(child, NULL);
796 795 return (DDI_FAILURE);
797 796 }
798 797
799 798 /*
800 799 * The child was not merged into a h/w node,
801 800 * but there's not much we can do with it other
802 801 * than return failure to cause the node to be removed.
803 802 */
804 803 cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
805 804 ddi_get_name(child), ddi_get_name_addr(child),
806 805 ddi_get_name(child));
807 806 ddi_set_name_addr(child, NULL);
808 807 return (DDI_NOT_WELL_FORMED);
809 808 }
810 809
811 810 if (xvdi_init_dev(child) != DDI_SUCCESS)
812 811 return (DDI_FAILURE);
813 812
814 813 if (xpvd_name_child(child, addr, sizeof (addr)) != DDI_SUCCESS) {
815 814 xvdi_uninit_dev(child);
816 815 return (DDI_FAILURE);
817 816 }
818 817 ddi_set_name_addr(child, addr);
819 818
820 819 return (DDI_SUCCESS);
821 820 }
822 821
823 822 static int
824 823 xpvd_removechild(dev_info_t *dip)
825 824 {
826 825 xvdi_uninit_dev(dip);
827 826
828 827 ddi_set_name_addr(dip, NULL);
829 828
830 829 /*
831 830 * Strip the node to properly convert it back to prototype
832 831 * form.
833 832 */
834 833 ddi_remove_minor_node(dip, NULL);
835 834
836 835 return (DDI_SUCCESS);
837 836 }
838 837
839 838 static int
840 839 xpvd_bus_unconfig(dev_info_t *parent, uint_t flag, ddi_bus_config_op_t op,
841 840 void *device_name)
842 841 {
843 842 return (ndi_busop_bus_unconfig(parent, flag, op, device_name));
844 843 }
845 844
846 845 /*
847 846 * Given the name of a child of xpvd, determine the device class,
848 847 * domain and vdevnum to which it refers.
849 848 */
850 849 static boolean_t
851 850 i_xpvd_parse_devname(char *name, xendev_devclass_t *devclassp,
852 851 domid_t *domp, int *vdevp)
853 852 {
854 853 int len = strlen(name) + 1;
855 854 char *device_name = i_ddi_strdup(name, KM_SLEEP);
856 855 char *cname = NULL, *caddr = NULL;
857 856 boolean_t ret;
858 857
859 858 i_ddi_parse_name(device_name, &cname, &caddr, NULL);
860 859
861 860 if ((cname == NULL) || (strlen(cname) == 0) ||
862 861 (caddr == NULL) || (strlen(caddr) == 0)) {
863 862 ret = B_FALSE;
864 863 goto done;
865 864 }
866 865
867 866 *devclassp = xendev_nodename_to_devclass(cname);
868 867 if (*devclassp < 0) {
869 868 ret = B_FALSE;
870 869 goto done;
871 870 }
872 871
873 872 /*
874 873 * Parsing the address component requires knowledge of how
875 874 * xpvd_name_child() works. If that code changes, so must
876 875 * this.
877 876 */
878 877
879 878 /* Backend format is "<domain>,<vdev>". */
880 879 if (sscanf(caddr, "%hu,%d", domp, vdevp) == 2) {
881 880 ret = B_TRUE;
882 881 goto done;
883 882 }
884 883
885 884 /* Frontend format is "<vdev>". */
886 885 *domp = DOMID_SELF;
887 886 if (sscanf(caddr, "%d", vdevp) == 1)
888 887 ret = B_TRUE;
889 888 done:
890 889 kmem_free(device_name, len);
891 890 return (ret);
892 891 }
893 892
894 893 /*
895 894 * xpvd_bus_config()
896 895 *
897 896 * BUS_CONFIG_ONE:
898 897 * Enumerate the exact instance of a driver.
899 898 *
900 899 * BUS_CONFIG_ALL:
901 900 * Enumerate all the instances of all the possible children (seen before
902 901 * and never seen before).
903 902 *
904 903 * BUS_CONFIG_DRIVER:
905 904 * Enumerate all the instances of a particular driver.
906 905 */
907 906 static int
908 907 xpvd_bus_config(dev_info_t *parent, uint_t flag, ddi_bus_config_op_t op,
909 908 void *arg, dev_info_t **childp)
910 909 {
911 910 int circ;
912 911 char *cname = NULL;
913 912
914 913 ndi_devi_enter(parent, &circ);
915 914
916 915 switch (op) {
917 916 case BUS_CONFIG_ONE: {
918 917 xendev_devclass_t devclass;
919 918 domid_t dom;
920 919 int vdev;
921 920
922 921 if (!i_xpvd_parse_devname(arg, &devclass, &dom, &vdev)) {
923 922 ndi_devi_exit(parent, circ);
924 923 return (NDI_FAILURE);
925 924 }
926 925
927 926 *childp = xvdi_find_dev(parent, devclass, dom, vdev);
928 927 if (*childp == NULL)
929 928 *childp = xvdi_create_dev(parent, devclass, dom, vdev);
930 929
931 930 ndi_devi_exit(parent, circ);
932 931
933 932 if (*childp == NULL)
934 933 return (NDI_FAILURE);
935 934 else
936 935 return (ndi_busop_bus_config(parent, flag,
937 936 op, arg, childp, 0));
938 937 }
939 938
940 939 case BUS_CONFIG_DRIVER: {
941 940 xendev_devclass_t devclass = XEN_INVAL;
942 941
943 942 cname = ddi_major_to_name((major_t)(uintptr_t)arg);
944 943 if (cname != NULL)
945 944 devclass = xendev_nodename_to_devclass(cname);
946 945
947 946 if (devclass == XEN_INVAL) {
948 947 ndi_devi_exit(parent, circ);
949 948 return (NDI_FAILURE);
950 949 } else {
951 950 xendev_enum_class(parent, devclass);
952 951 ndi_devi_exit(parent, circ);
953 952 return (ndi_busop_bus_config(parent, flag, op,
954 953 arg, childp, 0));
955 954 }
956 955 /* NOTREACHED */
957 956 }
958 957
959 958 case BUS_CONFIG_ALL:
960 959 xendev_enum_all(parent, B_FALSE);
961 960 ndi_devi_exit(parent, circ);
962 961
963 962 return (ndi_busop_bus_config(parent, flag, op,
964 963 arg, childp, 0));
965 964
966 965 default:
967 966 ndi_devi_exit(parent, circ);
968 967 return (NDI_FAILURE);
969 968 }
970 969 }
971 970
972 971 /*ARGSUSED*/
973 972 static int
974 973 xpvd_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
975 974 char *eventname, ddi_eventcookie_t *cookie)
976 975 {
977 976 return (ndi_event_retrieve_cookie(xpvd_ndi_event_handle,
978 977 rdip, eventname, cookie, NDI_EVENT_NOPASS));
979 978 }
980 979
981 980 /*ARGSUSED*/
982 981 static int
983 982 xpvd_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
984 983 ddi_eventcookie_t cookie, void (*callback)(dev_info_t *dip,
985 984 ddi_eventcookie_t cookie, void *arg, void *bus_impldata),
986 985 void *arg, ddi_callback_id_t *cb_id)
987 986 {
988 987 return (ndi_event_add_callback(xpvd_ndi_event_handle,
989 988 rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
990 989 }
991 990
992 991 /*ARGSUSED*/
993 992 static int
994 993 xpvd_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
995 994 {
996 995 return (ndi_event_remove_callback(xpvd_ndi_event_handle,
997 996 cb_id));
998 997 }
999 998
1000 999 /*ARGSUSED*/
1001 1000 static int
1002 1001 xpvd_post_event(dev_info_t *dip, dev_info_t *rdip,
1003 1002 ddi_eventcookie_t cookie, void *bus_impldata)
1004 1003 {
1005 1004 return (ndi_event_run_callbacks(xpvd_ndi_event_handle, rdip,
1006 1005 cookie, bus_impldata));
1007 1006 }
↓ open down ↓ |
789 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX