.. | .. |
---|
89 | 89 | .dev_groups = stm_groups, |
---|
90 | 90 | }; |
---|
91 | 91 | |
---|
92 | | -static int stm_dev_match(struct device *dev, const void *data) |
---|
93 | | -{ |
---|
94 | | - const char *name = data; |
---|
95 | | - |
---|
96 | | - return sysfs_streq(name, dev_name(dev)); |
---|
97 | | -} |
---|
98 | | - |
---|
99 | 92 | /** |
---|
100 | 93 | * stm_find_device() - find stm device by name |
---|
101 | 94 | * @buf: character buffer containing the name |
---|
.. | .. |
---|
116 | 109 | if (!stm_core_up) |
---|
117 | 110 | return NULL; |
---|
118 | 111 | |
---|
119 | | - dev = class_find_device(&stm_class, NULL, buf, stm_dev_match); |
---|
| 112 | + dev = class_find_device_by_name(&stm_class, buf); |
---|
120 | 113 | if (!dev) |
---|
121 | 114 | return NULL; |
---|
122 | 115 | |
---|
.. | .. |
---|
295 | 288 | if (width > stm->data->sw_nchannels) |
---|
296 | 289 | return -EINVAL; |
---|
297 | 290 | |
---|
298 | | - if (policy_node) { |
---|
299 | | - stp_policy_node_get_ranges(policy_node, |
---|
300 | | - &midx, &mend, &cidx, &cend); |
---|
301 | | - } else { |
---|
302 | | - midx = stm->data->sw_start; |
---|
303 | | - cidx = 0; |
---|
304 | | - mend = stm->data->sw_end; |
---|
305 | | - cend = stm->data->sw_nchannels - 1; |
---|
306 | | - } |
---|
| 291 | + /* We no longer accept policy_node==NULL here */ |
---|
| 292 | + if (WARN_ON_ONCE(!policy_node)) |
---|
| 293 | + return -EINVAL; |
---|
| 294 | + |
---|
| 295 | + /* |
---|
| 296 | + * Also, the caller holds reference to policy_node, so it won't |
---|
| 297 | + * disappear on us. |
---|
| 298 | + */ |
---|
| 299 | + stp_policy_node_get_ranges(policy_node, &midx, &mend, &cidx, &cend); |
---|
307 | 300 | |
---|
308 | 301 | spin_lock(&stm->mc_lock); |
---|
309 | 302 | spin_lock(&output->lock); |
---|
.. | .. |
---|
318 | 311 | output->master = midx; |
---|
319 | 312 | output->channel = cidx; |
---|
320 | 313 | output->nr_chans = width; |
---|
| 314 | + if (stm->pdrv->output_open) { |
---|
| 315 | + void *priv = stp_policy_node_priv(policy_node); |
---|
| 316 | + |
---|
| 317 | + if (WARN_ON_ONCE(!priv)) |
---|
| 318 | + goto unlock; |
---|
| 319 | + |
---|
| 320 | + /* configfs subsys mutex is held by the caller */ |
---|
| 321 | + ret = stm->pdrv->output_open(priv, output); |
---|
| 322 | + if (ret) |
---|
| 323 | + goto unlock; |
---|
| 324 | + } |
---|
| 325 | + |
---|
321 | 326 | stm_output_claim(stm, output); |
---|
322 | 327 | dev_dbg(&stm->dev, "assigned %u:%u (+%u)\n", midx, cidx, width); |
---|
323 | 328 | |
---|
324 | 329 | ret = 0; |
---|
325 | 330 | unlock: |
---|
| 331 | + if (ret) |
---|
| 332 | + output->nr_chans = 0; |
---|
| 333 | + |
---|
326 | 334 | spin_unlock(&output->lock); |
---|
327 | 335 | spin_unlock(&stm->mc_lock); |
---|
328 | 336 | |
---|
.. | .. |
---|
335 | 343 | spin_lock(&output->lock); |
---|
336 | 344 | if (output->nr_chans) |
---|
337 | 345 | stm_output_disclaim(stm, output); |
---|
| 346 | + if (stm->pdrv && stm->pdrv->output_close) |
---|
| 347 | + stm->pdrv->output_close(output); |
---|
338 | 348 | spin_unlock(&output->lock); |
---|
339 | 349 | spin_unlock(&stm->mc_lock); |
---|
340 | 350 | } |
---|
.. | .. |
---|
349 | 359 | unsigned int major = *(unsigned int *)data; |
---|
350 | 360 | |
---|
351 | 361 | return MAJOR(dev->devt) == major; |
---|
| 362 | +} |
---|
| 363 | + |
---|
| 364 | +/* |
---|
| 365 | + * Framing protocol management |
---|
| 366 | + * Modules can implement STM protocol drivers and (un-)register them |
---|
| 367 | + * with the STM class framework. |
---|
| 368 | + */ |
---|
| 369 | +static struct list_head stm_pdrv_head; |
---|
| 370 | +static struct mutex stm_pdrv_mutex; |
---|
| 371 | + |
---|
| 372 | +struct stm_pdrv_entry { |
---|
| 373 | + struct list_head entry; |
---|
| 374 | + const struct stm_protocol_driver *pdrv; |
---|
| 375 | + const struct config_item_type *node_type; |
---|
| 376 | +}; |
---|
| 377 | + |
---|
| 378 | +static const struct stm_pdrv_entry * |
---|
| 379 | +__stm_lookup_protocol(const char *name) |
---|
| 380 | +{ |
---|
| 381 | + struct stm_pdrv_entry *pe; |
---|
| 382 | + |
---|
| 383 | + /* |
---|
| 384 | + * If no name is given (NULL or ""), fall back to "p_basic". |
---|
| 385 | + */ |
---|
| 386 | + if (!name || !*name) |
---|
| 387 | + name = "p_basic"; |
---|
| 388 | + |
---|
| 389 | + list_for_each_entry(pe, &stm_pdrv_head, entry) { |
---|
| 390 | + if (!strcmp(name, pe->pdrv->name)) |
---|
| 391 | + return pe; |
---|
| 392 | + } |
---|
| 393 | + |
---|
| 394 | + return NULL; |
---|
| 395 | +} |
---|
| 396 | + |
---|
| 397 | +int stm_register_protocol(const struct stm_protocol_driver *pdrv) |
---|
| 398 | +{ |
---|
| 399 | + struct stm_pdrv_entry *pe = NULL; |
---|
| 400 | + int ret = -ENOMEM; |
---|
| 401 | + |
---|
| 402 | + mutex_lock(&stm_pdrv_mutex); |
---|
| 403 | + |
---|
| 404 | + if (__stm_lookup_protocol(pdrv->name)) { |
---|
| 405 | + ret = -EEXIST; |
---|
| 406 | + goto unlock; |
---|
| 407 | + } |
---|
| 408 | + |
---|
| 409 | + pe = kzalloc(sizeof(*pe), GFP_KERNEL); |
---|
| 410 | + if (!pe) |
---|
| 411 | + goto unlock; |
---|
| 412 | + |
---|
| 413 | + if (pdrv->policy_attr) { |
---|
| 414 | + pe->node_type = get_policy_node_type(pdrv->policy_attr); |
---|
| 415 | + if (!pe->node_type) |
---|
| 416 | + goto unlock; |
---|
| 417 | + } |
---|
| 418 | + |
---|
| 419 | + list_add_tail(&pe->entry, &stm_pdrv_head); |
---|
| 420 | + pe->pdrv = pdrv; |
---|
| 421 | + |
---|
| 422 | + ret = 0; |
---|
| 423 | +unlock: |
---|
| 424 | + mutex_unlock(&stm_pdrv_mutex); |
---|
| 425 | + |
---|
| 426 | + if (ret) |
---|
| 427 | + kfree(pe); |
---|
| 428 | + |
---|
| 429 | + return ret; |
---|
| 430 | +} |
---|
| 431 | +EXPORT_SYMBOL_GPL(stm_register_protocol); |
---|
| 432 | + |
---|
| 433 | +void stm_unregister_protocol(const struct stm_protocol_driver *pdrv) |
---|
| 434 | +{ |
---|
| 435 | + struct stm_pdrv_entry *pe, *iter; |
---|
| 436 | + |
---|
| 437 | + mutex_lock(&stm_pdrv_mutex); |
---|
| 438 | + |
---|
| 439 | + list_for_each_entry_safe(pe, iter, &stm_pdrv_head, entry) { |
---|
| 440 | + if (pe->pdrv == pdrv) { |
---|
| 441 | + list_del(&pe->entry); |
---|
| 442 | + |
---|
| 443 | + if (pe->node_type) { |
---|
| 444 | + kfree(pe->node_type->ct_attrs); |
---|
| 445 | + kfree(pe->node_type); |
---|
| 446 | + } |
---|
| 447 | + kfree(pe); |
---|
| 448 | + break; |
---|
| 449 | + } |
---|
| 450 | + } |
---|
| 451 | + |
---|
| 452 | + mutex_unlock(&stm_pdrv_mutex); |
---|
| 453 | +} |
---|
| 454 | +EXPORT_SYMBOL_GPL(stm_unregister_protocol); |
---|
| 455 | + |
---|
| 456 | +static bool stm_get_protocol(const struct stm_protocol_driver *pdrv) |
---|
| 457 | +{ |
---|
| 458 | + return try_module_get(pdrv->owner); |
---|
| 459 | +} |
---|
| 460 | + |
---|
| 461 | +void stm_put_protocol(const struct stm_protocol_driver *pdrv) |
---|
| 462 | +{ |
---|
| 463 | + module_put(pdrv->owner); |
---|
| 464 | +} |
---|
| 465 | + |
---|
| 466 | +int stm_lookup_protocol(const char *name, |
---|
| 467 | + const struct stm_protocol_driver **pdrv, |
---|
| 468 | + const struct config_item_type **node_type) |
---|
| 469 | +{ |
---|
| 470 | + const struct stm_pdrv_entry *pe; |
---|
| 471 | + |
---|
| 472 | + mutex_lock(&stm_pdrv_mutex); |
---|
| 473 | + |
---|
| 474 | + pe = __stm_lookup_protocol(name); |
---|
| 475 | + if (pe && pe->pdrv && stm_get_protocol(pe->pdrv)) { |
---|
| 476 | + *pdrv = pe->pdrv; |
---|
| 477 | + *node_type = pe->node_type; |
---|
| 478 | + } |
---|
| 479 | + |
---|
| 480 | + mutex_unlock(&stm_pdrv_mutex); |
---|
| 481 | + |
---|
| 482 | + return pe ? 0 : -ENOENT; |
---|
352 | 483 | } |
---|
353 | 484 | |
---|
354 | 485 | static int stm_char_open(struct inode *inode, struct file *file) |
---|
.. | .. |
---|
407 | 538 | return 0; |
---|
408 | 539 | } |
---|
409 | 540 | |
---|
410 | | -static int stm_file_assign(struct stm_file *stmf, char *id, unsigned int width) |
---|
| 541 | +static int |
---|
| 542 | +stm_assign_first_policy(struct stm_device *stm, struct stm_output *output, |
---|
| 543 | + char **ids, unsigned int width) |
---|
411 | 544 | { |
---|
412 | | - struct stm_device *stm = stmf->stm; |
---|
413 | | - int ret; |
---|
| 545 | + struct stp_policy_node *pn; |
---|
| 546 | + int err, n; |
---|
414 | 547 | |
---|
415 | | - stmf->policy_node = stp_policy_node_lookup(stm, id); |
---|
| 548 | + /* |
---|
| 549 | + * On success, stp_policy_node_lookup() will return holding the |
---|
| 550 | + * configfs subsystem mutex, which is then released in |
---|
| 551 | + * stp_policy_node_put(). This allows the pdrv->output_open() in |
---|
| 552 | + * stm_output_assign() to serialize against the attribute accessors. |
---|
| 553 | + */ |
---|
| 554 | + for (n = 0, pn = NULL; ids[n] && !pn; n++) |
---|
| 555 | + pn = stp_policy_node_lookup(stm, ids[n]); |
---|
416 | 556 | |
---|
417 | | - ret = stm_output_assign(stm, width, stmf->policy_node, &stmf->output); |
---|
| 557 | + if (!pn) |
---|
| 558 | + return -EINVAL; |
---|
418 | 559 | |
---|
419 | | - if (stmf->policy_node) |
---|
420 | | - stp_policy_node_put(stmf->policy_node); |
---|
| 560 | + err = stm_output_assign(stm, width, pn, output); |
---|
421 | 561 | |
---|
422 | | - return ret; |
---|
| 562 | + stp_policy_node_put(pn); |
---|
| 563 | + |
---|
| 564 | + return err; |
---|
423 | 565 | } |
---|
424 | 566 | |
---|
425 | | -static ssize_t notrace stm_write(struct stm_data *data, unsigned int master, |
---|
426 | | - unsigned int channel, const char *buf, size_t count) |
---|
| 567 | +/** |
---|
| 568 | + * stm_data_write() - send the given payload as data packets |
---|
| 569 | + * @data: stm driver's data |
---|
| 570 | + * @m: STP master |
---|
| 571 | + * @c: STP channel |
---|
| 572 | + * @ts_first: timestamp the first packet |
---|
| 573 | + * @buf: data payload buffer |
---|
| 574 | + * @count: data payload size |
---|
| 575 | + */ |
---|
| 576 | +ssize_t notrace stm_data_write(struct stm_data *data, unsigned int m, |
---|
| 577 | + unsigned int c, bool ts_first, const void *buf, |
---|
| 578 | + size_t count) |
---|
427 | 579 | { |
---|
428 | | - unsigned int flags = STP_PACKET_TIMESTAMPED; |
---|
429 | | - const unsigned char *p = buf, nil = 0; |
---|
430 | | - size_t pos; |
---|
| 580 | + unsigned int flags = ts_first ? STP_PACKET_TIMESTAMPED : 0; |
---|
431 | 581 | ssize_t sz; |
---|
| 582 | + size_t pos; |
---|
432 | 583 | |
---|
433 | | - for (pos = 0, p = buf; count > pos; pos += sz, p += sz) { |
---|
| 584 | + for (pos = 0, sz = 0; pos < count; pos += sz) { |
---|
434 | 585 | sz = min_t(unsigned int, count - pos, 8); |
---|
435 | | - sz = data->packet(data, master, channel, STP_PACKET_DATA, flags, |
---|
436 | | - sz, p); |
---|
437 | | - flags = 0; |
---|
438 | | - |
---|
439 | | - if (sz < 0) |
---|
| 586 | + sz = data->packet(data, m, c, STP_PACKET_DATA, flags, sz, |
---|
| 587 | + &((u8 *)buf)[pos]); |
---|
| 588 | + if (sz <= 0) |
---|
440 | 589 | break; |
---|
| 590 | + |
---|
| 591 | + if (ts_first) { |
---|
| 592 | + flags = 0; |
---|
| 593 | + ts_first = false; |
---|
| 594 | + } |
---|
441 | 595 | } |
---|
442 | 596 | |
---|
443 | | - data->packet(data, master, channel, STP_PACKET_FLAG, 0, 0, &nil); |
---|
| 597 | + return sz < 0 ? sz : pos; |
---|
| 598 | +} |
---|
| 599 | +EXPORT_SYMBOL_GPL(stm_data_write); |
---|
444 | 600 | |
---|
445 | | - return pos; |
---|
| 601 | +static ssize_t notrace |
---|
| 602 | +stm_write(struct stm_device *stm, struct stm_output *output, |
---|
| 603 | + unsigned int chan, const char *buf, size_t count) |
---|
| 604 | +{ |
---|
| 605 | + int err; |
---|
| 606 | + |
---|
| 607 | + /* stm->pdrv is serialized against policy_mutex */ |
---|
| 608 | + if (!stm->pdrv) |
---|
| 609 | + return -ENODEV; |
---|
| 610 | + |
---|
| 611 | + err = stm->pdrv->write(stm->data, output, chan, buf, count); |
---|
| 612 | + if (err < 0) |
---|
| 613 | + return err; |
---|
| 614 | + |
---|
| 615 | + return err; |
---|
446 | 616 | } |
---|
447 | 617 | |
---|
448 | 618 | static ssize_t stm_char_write(struct file *file, const char __user *buf, |
---|
.. | .. |
---|
457 | 627 | count = PAGE_SIZE - 1; |
---|
458 | 628 | |
---|
459 | 629 | /* |
---|
460 | | - * if no m/c have been assigned to this writer up to this |
---|
461 | | - * point, use "default" policy entry |
---|
| 630 | + * If no m/c have been assigned to this writer up to this |
---|
| 631 | + * point, try to use the task name and "default" policy entries. |
---|
462 | 632 | */ |
---|
463 | 633 | if (!stmf->output.nr_chans) { |
---|
464 | | - err = stm_file_assign(stmf, "default", 1); |
---|
| 634 | + char comm[sizeof(current->comm)]; |
---|
| 635 | + char *ids[] = { comm, "default", NULL }; |
---|
| 636 | + |
---|
| 637 | + get_task_comm(comm, current); |
---|
| 638 | + |
---|
| 639 | + err = stm_assign_first_policy(stmf->stm, &stmf->output, ids, 1); |
---|
465 | 640 | /* |
---|
466 | 641 | * EBUSY means that somebody else just assigned this |
---|
467 | 642 | * output, which is just fine for write() |
---|
468 | 643 | */ |
---|
469 | | - if (err && err != -EBUSY) |
---|
| 644 | + if (err) |
---|
470 | 645 | return err; |
---|
471 | 646 | } |
---|
472 | 647 | |
---|
.. | .. |
---|
482 | 657 | |
---|
483 | 658 | pm_runtime_get_sync(&stm->dev); |
---|
484 | 659 | |
---|
485 | | - count = stm_write(stm->data, stmf->output.master, stmf->output.channel, |
---|
486 | | - kbuf, count); |
---|
| 660 | + count = stm_write(stm, &stmf->output, 0, kbuf, count); |
---|
487 | 661 | |
---|
488 | 662 | pm_runtime_mark_last_busy(&stm->dev); |
---|
489 | 663 | pm_runtime_put_autosuspend(&stm->dev); |
---|
.. | .. |
---|
552 | 726 | { |
---|
553 | 727 | struct stm_device *stm = stmf->stm; |
---|
554 | 728 | struct stp_policy_id *id; |
---|
| 729 | + char *ids[] = { NULL, NULL }; |
---|
555 | 730 | int ret = -EINVAL, wlimit = 1; |
---|
556 | 731 | u32 size; |
---|
557 | 732 | |
---|
.. | .. |
---|
586 | 761 | if (id->width < 1 || id->width > wlimit) |
---|
587 | 762 | goto err_free; |
---|
588 | 763 | |
---|
589 | | - ret = stm_file_assign(stmf, id->id, id->width); |
---|
| 764 | + ids[0] = id->id; |
---|
| 765 | + ret = stm_assign_first_policy(stmf->stm, &stmf->output, ids, |
---|
| 766 | + id->width); |
---|
590 | 767 | if (ret) |
---|
591 | 768 | goto err_free; |
---|
592 | 769 | |
---|
.. | .. |
---|
655 | 832 | return err; |
---|
656 | 833 | } |
---|
657 | 834 | |
---|
658 | | -#ifdef CONFIG_COMPAT |
---|
659 | | -static long |
---|
660 | | -stm_char_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
---|
661 | | -{ |
---|
662 | | - return stm_char_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); |
---|
663 | | -} |
---|
664 | | -#else |
---|
665 | | -#define stm_char_compat_ioctl NULL |
---|
666 | | -#endif |
---|
667 | | - |
---|
668 | 835 | static const struct file_operations stm_fops = { |
---|
669 | 836 | .open = stm_char_open, |
---|
670 | 837 | .release = stm_char_release, |
---|
671 | 838 | .write = stm_char_write, |
---|
672 | 839 | .mmap = stm_char_mmap, |
---|
673 | 840 | .unlocked_ioctl = stm_char_ioctl, |
---|
674 | | - .compat_ioctl = stm_char_compat_ioctl, |
---|
| 841 | + .compat_ioctl = compat_ptr_ioctl, |
---|
675 | 842 | .llseek = no_llseek, |
---|
676 | 843 | }; |
---|
677 | 844 | |
---|
.. | .. |
---|
822 | 989 | static int stm_source_link_add(struct stm_source_device *src, |
---|
823 | 990 | struct stm_device *stm) |
---|
824 | 991 | { |
---|
825 | | - char *id; |
---|
826 | | - int err; |
---|
| 992 | + char *ids[] = { NULL, "default", NULL }; |
---|
| 993 | + int err = -ENOMEM; |
---|
827 | 994 | |
---|
828 | 995 | mutex_lock(&stm->link_mutex); |
---|
829 | 996 | spin_lock(&stm->link_lock); |
---|
.. | .. |
---|
837 | 1004 | spin_unlock(&stm->link_lock); |
---|
838 | 1005 | mutex_unlock(&stm->link_mutex); |
---|
839 | 1006 | |
---|
840 | | - id = kstrdup(src->data->name, GFP_KERNEL); |
---|
841 | | - if (id) { |
---|
842 | | - src->policy_node = |
---|
843 | | - stp_policy_node_lookup(stm, id); |
---|
| 1007 | + ids[0] = kstrdup(src->data->name, GFP_KERNEL); |
---|
| 1008 | + if (!ids[0]) |
---|
| 1009 | + goto fail_detach; |
---|
844 | 1010 | |
---|
845 | | - kfree(id); |
---|
846 | | - } |
---|
847 | | - |
---|
848 | | - err = stm_output_assign(stm, src->data->nr_chans, |
---|
849 | | - src->policy_node, &src->output); |
---|
850 | | - |
---|
851 | | - if (src->policy_node) |
---|
852 | | - stp_policy_node_put(src->policy_node); |
---|
| 1011 | + err = stm_assign_first_policy(stm, &src->output, ids, |
---|
| 1012 | + src->data->nr_chans); |
---|
| 1013 | + kfree(ids[0]); |
---|
853 | 1014 | |
---|
854 | 1015 | if (err) |
---|
855 | 1016 | goto fail_detach; |
---|
.. | .. |
---|
1137 | 1298 | |
---|
1138 | 1299 | stm = srcu_dereference(src->link, &stm_source_srcu); |
---|
1139 | 1300 | if (stm) |
---|
1140 | | - count = stm_write(stm->data, src->output.master, |
---|
1141 | | - src->output.channel + chan, |
---|
1142 | | - buf, count); |
---|
| 1301 | + count = stm_write(stm, &src->output, chan, buf, count); |
---|
1143 | 1302 | else |
---|
1144 | 1303 | count = -ENODEV; |
---|
1145 | 1304 | |
---|
.. | .. |
---|
1166 | 1325 | goto err_src; |
---|
1167 | 1326 | |
---|
1168 | 1327 | init_srcu_struct(&stm_source_srcu); |
---|
| 1328 | + INIT_LIST_HEAD(&stm_pdrv_head); |
---|
| 1329 | + mutex_init(&stm_pdrv_mutex); |
---|
1169 | 1330 | |
---|
| 1331 | + /* |
---|
| 1332 | + * So as to not confuse existing users with a requirement |
---|
| 1333 | + * to load yet another module, do it here. |
---|
| 1334 | + */ |
---|
| 1335 | + if (IS_ENABLED(CONFIG_STM_PROTO_BASIC)) |
---|
| 1336 | + (void)request_module_nowait("stm_p_basic"); |
---|
1170 | 1337 | stm_core_up++; |
---|
1171 | 1338 | |
---|
1172 | 1339 | return 0; |
---|