1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2017 Joyent, Inc.
26 */
27
28
29 /*
30 * srn Provide apm-like interfaces to Xorg
31 */
32
33 #include <sys/types.h>
34 #include <sys/errno.h>
35 #include <sys/modctl.h>
36 #include <sys/conf.h> /* driver flags and functions */
37 #include <sys/open.h> /* OTYP_CHR definition */
38 #include <sys/stat.h> /* S_IFCHR definition */
39 #include <sys/pathname.h> /* name -> dev_info xlation */
40 #include <sys/kmem.h> /* memory alloc stuff */
41 #include <sys/debug.h>
42 #include <sys/pm.h>
43 #include <sys/ddi.h>
44 #include <sys/sunddi.h>
45 #include <sys/epm.h>
46 #include <sys/vfs.h>
47 #include <sys/mode.h>
48 #include <sys/mkdev.h>
49 #include <sys/promif.h>
50 #include <sys/consdev.h>
51 #include <sys/ddi_impldefs.h>
52 #include <sys/poll.h>
53 #include <sys/note.h>
54 #include <sys/taskq.h>
55 #include <sys/policy.h>
56 #include <sys/srn.h>
57
58 /*
59 * Minor number is instance<<8 + clone minor from range 1-255;
60 * But only one will be allocated
61 */
62 #define SRN_MINOR_TO_CLONE(minor) ((minor) & (SRN_MAX_CLONE - 1))
63 #define SU 0x002
64 #define SG 0x004
65
66 extern kmutex_t srn_clone_lock; /* protects srn_clones array */
67 extern kcondvar_t srn_clones_cv[SRN_MAX_CLONE];
68 extern uint_t srn_poll_cnt[SRN_MAX_CLONE];
69
70 /*
71 * The soft state of the srn driver. Since there will only be
72 * one of these, just reference it through a static struct.
73 */
74 static struct srnstate {
75 dev_info_t *srn_dip; /* ptr to our dev_info node */
76 int srn_instance; /* for ddi_get_instance() */
77 uchar_t srn_clones[SRN_MAX_CLONE]; /* unique opens */
78 struct cred *srn_cred[SRN_MAX_CLONE]; /* cred for each open */
79 int srn_type[SRN_MAX_CLONE]; /* type of handshake */
80 int srn_delivered[SRN_MAX_CLONE];
81 srn_event_info_t srn_pending[SRN_MAX_CLONE];
82 int srn_fault[SRN_MAX_CLONE];
83 } srn = { NULL, -1};
84 typedef struct srnstate *srn_state_t;
85
86 kcondvar_t srn_clones_cv[SRN_MAX_CLONE];
87 uint_t srn_poll_cnt[SRN_MAX_CLONE]; /* count of events for poll */
88 int srn_apm_count;
89 int srn_autosx_count;
90 /* Number of seconds to wait for clients to ack a poll */
91 int srn_timeout = 10;
92
93 struct pollhead srn_pollhead[SRN_MAX_CLONE];
94
95 static int srn_open(dev_t *, int, int, cred_t *);
96 static int srn_close(dev_t, int, int, cred_t *);
97 static int srn_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
98 static int srn_chpoll(dev_t, short, int, short *, struct pollhead **);
99
100 static struct cb_ops srn_cb_ops = {
101 srn_open, /* open */
102 srn_close, /* close */
103 nodev, /* strategy */
104 nodev, /* print */
105 nodev, /* dump */
106 nodev, /* read */
107 nodev, /* write */
108 srn_ioctl, /* ioctl */
109 nodev, /* devmap */
110 nodev, /* mmap */
111 nodev, /* segmap */
112 srn_chpoll, /* poll */
113 ddi_prop_op, /* prop_op */
114 NULL, /* streamtab */
115 D_NEW | D_MP /* driver compatibility flag */
116 };
117
118 static int srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
119 void **result);
120 static int srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
121 static int srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
122 static void srn_notify(int type, int event);
123
124 static struct dev_ops srn_ops = {
125 DEVO_REV, /* devo_rev */
126 0, /* refcnt */
127 srn_getinfo, /* info */
128 nulldev, /* identify */
129 nulldev, /* probe */
130 srn_attach, /* attach */
131 srn_detach, /* detach */
132 nodev, /* reset */
133 &srn_cb_ops, /* driver operations */
134 NULL, /* bus operations */
135 NULL, /* power */
136 ddi_quiesce_not_needed, /* quiesce */
137 };
138
139 static struct modldrv modldrv = {
140 &mod_driverops,
141 "srn driver",
142 &srn_ops
143 };
144
145 static struct modlinkage modlinkage = {
146 MODREV_1, &modldrv, 0
147 };
148
149 /* Local functions */
150
151 int
_init(void)152 _init(void)
153 {
154 return (mod_install(&modlinkage));
155 }
156
157 int
_fini(void)158 _fini(void)
159 {
160 return (mod_remove(&modlinkage));
161 }
162
163 int
_info(struct modinfo * modinfop)164 _info(struct modinfo *modinfop)
165 {
166 return (mod_info(&modlinkage, modinfop));
167 }
168
169 static int
srn_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)170 srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
171 {
172 int i;
173 extern void (*srn_signal)(int, int);
174
175 switch (cmd) {
176
177 case DDI_ATTACH:
178 if (srn.srn_instance != -1) /* Only allow one instance */
179 return (DDI_FAILURE);
180 srn.srn_instance = ddi_get_instance(dip);
181 if (ddi_create_minor_node(dip, "srn", S_IFCHR,
182 (srn.srn_instance << 8) + 0, DDI_PSEUDO, 0)
183 != DDI_SUCCESS) {
184 return (DDI_FAILURE);
185 }
186 srn.srn_dip = dip; /* srn_init and getinfo depend on it */
187
188 for (i = 0; i < SRN_MAX_CLONE; i++)
189 cv_init(&srn_clones_cv[i], NULL, CV_DEFAULT, NULL);
190
191 srn.srn_instance = ddi_get_instance(dip);
192 mutex_enter(&srn_clone_lock);
193 srn_signal = srn_notify;
194 mutex_exit(&srn_clone_lock);
195 ddi_report_dev(dip);
196 return (DDI_SUCCESS);
197
198 default:
199 return (DDI_FAILURE);
200 }
201 }
202
203 /* ARGSUSED */
204 static int
srn_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)205 srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
206 {
207 int i;
208 extern int srn_inuse;
209 extern void (*srn_signal)(int, int);
210
211 switch (cmd) {
212 case DDI_DETACH:
213
214 mutex_enter(&srn_clone_lock);
215 while (srn_inuse) {
216 mutex_exit(&srn_clone_lock);
217 delay(1);
218 mutex_enter(&srn_clone_lock);
219 }
220 srn_signal = NULL;
221 mutex_exit(&srn_clone_lock);
222
223 for (i = 0; i < SRN_MAX_CLONE; i++)
224 cv_destroy(&srn_clones_cv[i]);
225
226 ddi_remove_minor_node(dip, NULL);
227 srn.srn_instance = -1;
228 return (DDI_SUCCESS);
229
230 default:
231 return (DDI_FAILURE);
232 }
233 }
234
235
236 #ifdef DEBUG
237 char *srn_cmd_string;
238 int srn_cmd;
239 #endif
240
241 /*
242 * Returns true if permission granted by credentials
243 * XXX
244 */
245 static int
srn_perms(int perm,cred_t * cr)246 srn_perms(int perm, cred_t *cr)
247 {
248 if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */
249 return (1);
250 if ((perm & SG) && (crgetgid(cr) == 0)) /* group 0 is ok */
251 return (1);
252 return (0);
253 }
254
255 static int
srn_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)256 srn_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
257 struct pollhead **phpp)
258 {
259 extern struct pollhead srn_pollhead[];
260 int clone;
261
262 clone = SRN_MINOR_TO_CLONE(getminor(dev));
263 if ((events & (POLLIN | POLLRDNORM)) && srn_poll_cnt[clone]) {
264 *reventsp |= (POLLIN | POLLRDNORM);
265 } else {
266 *reventsp = 0;
267 }
268
269 if ((*reventsp == 0 && !anyyet) || (events & POLLET)) {
270 *phpp = &srn_pollhead[clone];
271 }
272 return (0);
273 }
274
275 /*ARGSUSED*/
276 static int
srn_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)277 srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
278 {
279 dev_t dev;
280 int instance;
281
282 switch (infocmd) {
283 case DDI_INFO_DEVT2DEVINFO:
284 if (srn.srn_instance == -1)
285 return (DDI_FAILURE);
286 *result = srn.srn_dip;
287 return (DDI_SUCCESS);
288
289 case DDI_INFO_DEVT2INSTANCE:
290 dev = (dev_t)arg;
291 instance = getminor(dev) >> 8;
292 *result = (void *)(uintptr_t)instance;
293 return (DDI_SUCCESS);
294
295 default:
296 return (DDI_FAILURE);
297 }
298 }
299
300
301 /*ARGSUSED1*/
302 static int
srn_open(dev_t * devp,int flag,int otyp,cred_t * cr)303 srn_open(dev_t *devp, int flag, int otyp, cred_t *cr)
304 {
305 int clone;
306
307 if (otyp != OTYP_CHR)
308 return (EINVAL);
309
310 mutex_enter(&srn_clone_lock);
311 for (clone = 1; clone < SRN_MAX_CLONE - 1; clone++)
312 if (!srn.srn_clones[clone])
313 break;
314
315 if (clone == SRN_MAX_CLONE) {
316 mutex_exit(&srn_clone_lock);
317 return (ENXIO);
318 }
319 srn.srn_cred[clone] = cr;
320 ASSERT(srn_apm_count >= 0);
321 srn_apm_count++;
322 srn.srn_type[clone] = SRN_TYPE_APM;
323 crhold(cr);
324
325 *devp = makedevice(getmajor(*devp), (srn.srn_instance << 8) +
326 clone);
327 srn.srn_clones[clone] = 1;
328 srn.srn_cred[clone] = cr;
329 crhold(cr);
330 mutex_exit(&srn_clone_lock);
331 PMD(PMD_SX, ("srn open OK\n"))
332 return (0);
333 }
334
335 /*ARGSUSED1*/
336 static int
srn_close(dev_t dev,int flag,int otyp,cred_t * cr)337 srn_close(dev_t dev, int flag, int otyp, cred_t *cr)
338 {
339 int clone;
340
341 if (otyp != OTYP_CHR)
342 return (EINVAL);
343
344 clone = SRN_MINOR_TO_CLONE(getminor(dev));
345 PMD(PMD_SX, ("srn_close: minor %x, clone %x\n", getminor(dev),
346 clone))
347 mutex_enter(&srn_clone_lock);
348 crfree(srn.srn_cred[clone]);
349 srn.srn_cred[clone] = 0;
350 srn_poll_cnt[clone] = 0;
351 srn.srn_fault[clone] = 0;
352 if (srn.srn_pending[clone].ae_type || srn.srn_delivered[clone]) {
353 srn.srn_pending[clone].ae_type = 0;
354 srn.srn_delivered[clone] = 0;
355 cv_signal(&srn_clones_cv[clone]);
356 }
357 switch (srn.srn_type[clone]) {
358 case SRN_TYPE_AUTOSX:
359 ASSERT(srn_autosx_count);
360 srn_autosx_count--;
361 break;
362 case SRN_TYPE_APM:
363 ASSERT(srn_apm_count);
364 srn_apm_count--;
365 break;
366 default:
367 ASSERT(0);
368 return (EINVAL);
369 }
370 srn.srn_clones[clone] = 0;
371 mutex_exit(&srn_clone_lock);
372 return (0);
373 }
374
375 /*ARGSUSED*/
376 static int
srn_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval_p)377 srn_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)
378 {
379 int clone = SRN_MINOR_TO_CLONE(getminor(dev));
380
381 PMD(PMD_SX, ("ioctl: %x: begin\n", cmd))
382
383 switch (cmd) {
384 case SRN_IOC_NEXTEVENT:
385 case SRN_IOC_SUSPEND:
386 case SRN_IOC_RESUME:
387 case SRN_IOC_AUTOSX:
388 break;
389 default:
390 return (ENOTTY);
391 }
392
393 if (!srn_perms(SU | SG, srn.srn_cred[clone])) {
394 return (EPERM);
395 }
396 switch (cmd) {
397 case SRN_IOC_AUTOSX:
398 PMD(PMD_SX, ("SRN_IOC_AUTOSX entered\n"))
399 mutex_enter(&srn_clone_lock);
400 if (!srn.srn_clones[clone]) {
401 PMD(PMD_SX, (" ioctl !srn_clones--EINVAL\n"))
402 mutex_exit(&srn_clone_lock);
403 return (EINVAL);
404 }
405 if (srn.srn_pending[clone].ae_type) {
406 PMD(PMD_SX, ("AUTOSX while pending--EBUSY\n"))
407 mutex_exit(&srn_clone_lock);
408 return (EBUSY);
409 }
410 if (srn.srn_type[clone] == SRN_TYPE_AUTOSX) {
411 PMD(PMD_SX, ("AUTOSX already--EBUSY\n"))
412 mutex_exit(&srn_clone_lock);
413 return (EBUSY);
414 }
415 ASSERT(srn.srn_type[clone] == SRN_TYPE_APM);
416 srn.srn_type[clone] = SRN_TYPE_AUTOSX;
417 srn.srn_fault[clone] = 0;
418 srn_apm_count--;
419 ASSERT(srn_apm_count >= 0);
420 ASSERT(srn_autosx_count >= 0);
421 srn_autosx_count++;
422 mutex_exit(&srn_clone_lock);
423 PMD(PMD_SX, ("SRN_IOC_AUTOSX returns success\n"))
424 return (0);
425
426 case SRN_IOC_NEXTEVENT:
427 /*
428 * return the next suspend or resume event; there should
429 * be one, cause we only get called if we've signalled a
430 * poll data completion
431 * then wake up the kernel thread sleeping for the delivery
432 */
433 PMD(PMD_SX, ("SRN_IOC_NEXTEVENT entered\n"))
434 if (srn.srn_fault[clone]) {
435 PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d fault "
436 "cleared\n", clone))
437 srn.srn_fault[clone] = 0;
438 }
439 mutex_enter(&srn_clone_lock);
440 if (srn_poll_cnt[clone] == 0) {
441 mutex_exit(&srn_clone_lock);
442 PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d "
443 "EWOULDBLOCK\n", clone))
444 return (EWOULDBLOCK);
445 }
446 ASSERT(srn.srn_pending[clone].ae_type);
447 if (ddi_copyout(&srn.srn_pending[clone], (void *)arg,
448 sizeof (srn_event_info_t), mode) != 0) {
449 mutex_exit(&srn_clone_lock);
450 PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d EFAULT\n",
451 clone))
452 return (EFAULT);
453 }
454 if (srn.srn_type[clone] == SRN_TYPE_APM)
455 srn.srn_delivered[clone] =
456 srn.srn_pending[clone].ae_type;
457 PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d delivered %x\n",
458 clone, srn.srn_pending[clone].ae_type))
459 srn_poll_cnt[clone] = 0;
460 mutex_exit(&srn_clone_lock);
461 return (0);
462
463 case SRN_IOC_SUSPEND:
464 /* ack suspend */
465 PMD(PMD_SX, ("SRN_IOC_SUSPEND entered clone %d\n", clone))
466 if (srn.srn_fault[clone]) {
467 PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d fault "
468 "cleared\n", clone))
469 srn.srn_fault[clone] = 0;
470 }
471 mutex_enter(&srn_clone_lock);
472 if (srn.srn_delivered[clone] != SRN_SUSPEND_REQ) {
473 mutex_exit(&srn_clone_lock);
474 PMD(PMD_SX, ("SRN_IOC_SUSPEND EINVAL\n"))
475 return (EINVAL);
476 }
477 srn.srn_delivered[clone] = 0;
478 srn.srn_pending[clone].ae_type = 0;
479 /* notify the kernel suspend thread to continue */
480 PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d ok\n", clone))
481 cv_signal(&srn_clones_cv[clone]);
482 mutex_exit(&srn_clone_lock);
483 return (0);
484
485 case SRN_IOC_RESUME:
486 /* ack resume */
487 PMD(PMD_SX, ("SRN_IOC_RESUME entered clone %d\n", clone))
488 if (srn.srn_fault[clone]) {
489 PMD(PMD_SX, ("SRN_IOC_RESUME clone %d fault "
490 "cleared\n", clone))
491 srn.srn_fault[clone] = 0;
492 }
493 mutex_enter(&srn_clone_lock);
494 if (srn.srn_delivered[clone] != SRN_NORMAL_RESUME) {
495 mutex_exit(&srn_clone_lock);
496 PMD(PMD_SX, ("SRN_IOC_RESUME EINVAL\n"))
497 return (EINVAL);
498 }
499 srn.srn_delivered[clone] = 0;
500 srn.srn_pending[clone].ae_type = 0;
501 /* notify the kernel resume thread to continue */
502 PMD(PMD_SX, ("SRN_IOC_RESUME ok for clone %d\n", clone))
503 cv_signal(&srn_clones_cv[clone]);
504 mutex_exit(&srn_clone_lock);
505 return (0);
506
507 default:
508 PMD(PMD_SX, ("srn_ioctl unknown cmd EINVAL\n"))
509 return (EINVAL);
510 }
511 }
512 /*
513 * A very simple handshake with the srn driver,
514 * only one outstanding event at a time.
515 * The OS delivers the event and depending on type,
516 * either blocks waiting for the ack, or drives on
517 */
518 void
srn_notify(int type,int event)519 srn_notify(int type, int event)
520 {
521 int clone, count;
522
523 PMD(PMD_SX, ("srn_notify entered with type %d, event 0x%x\n",
524 type, event));
525 ASSERT(mutex_owned(&srn_clone_lock));
526 switch (type) {
527 case SRN_TYPE_APM:
528 if (srn_apm_count == 0) {
529 PMD(PMD_SX, ("no apm types\n"))
530 return;
531 }
532 count = srn_apm_count;
533 break;
534 case SRN_TYPE_AUTOSX:
535 if (srn_autosx_count == 0) {
536 PMD(PMD_SX, ("no autosx types\n"))
537 return;
538 }
539 count = srn_autosx_count;
540 break;
541 default:
542 PMD(PMD_SX, ("unsupported type\n"))
543 return;
544 }
545 ASSERT(count > 0);
546 PMD(PMD_SX, ("count %d\n", count))
547 for (clone = 0; clone < SRN_MAX_CLONE; clone++) {
548 if (srn.srn_type[clone] == type) {
549 #ifdef DEBUG
550 if (type == SRN_TYPE_APM && !srn.srn_fault[clone]) {
551 ASSERT(srn.srn_pending[clone].ae_type == 0);
552 ASSERT(srn_poll_cnt[clone] == 0);
553 ASSERT(srn.srn_delivered[clone] == 0);
554 }
555 #endif
556 srn.srn_pending[clone].ae_type = event;
557 srn_poll_cnt[clone] = 1;
558 PMD(PMD_SX, ("pollwake %d\n", clone))
559 pollwakeup(&srn_pollhead[clone], (POLLRDNORM | POLLIN));
560 count--;
561 if (count == 0)
562 break;
563 }
564 }
565 if (type == SRN_TYPE_AUTOSX) { /* we don't wait */
566 PMD(PMD_SX, ("Not waiting for AUTOSX ack\n"))
567 return;
568 }
569 ASSERT(type == SRN_TYPE_APM);
570 /* otherwise wait for acks */
571 restart:
572 /*
573 * We wait until all of the pending events are cleared.
574 * We have to start over every time we do a cv_wait because
575 * we give up the mutex and can be re-entered
576 */
577 for (clone = 1; clone < SRN_MAX_CLONE; clone++) {
578 if (srn.srn_clones[clone] == 0 ||
579 srn.srn_type[clone] != SRN_TYPE_APM)
580 continue;
581 if (srn.srn_pending[clone].ae_type && !srn.srn_fault[clone]) {
582 PMD(PMD_SX, ("srn_notify waiting for ack for clone %d, "
583 "event %x\n", clone, event))
584 if (cv_timedwait(&srn_clones_cv[clone],
585 &srn_clone_lock, ddi_get_lbolt() +
586 drv_usectohz(srn_timeout * 1000000)) == -1) {
587 /*
588 * Client didn't respond, mark it as faulted
589 * and continue as if a regular signal.
590 */
591 PMD(PMD_SX, ("srn_notify: clone %d did not "
592 "ack event %x\n", clone, event))
593 cmn_err(CE_WARN, "srn_notify: clone %d did "
594 "not ack event %x\n", clone, event);
595 srn.srn_fault[clone] = 1;
596 }
597 goto restart;
598 }
599 }
600 PMD(PMD_SX, ("srn_notify done with %x\n", event))
601 }
602