.. | .. |
---|
97 | 97 | /* Transition with new state-specific callbacks */ |
---|
98 | 98 | switch (state) { |
---|
99 | 99 | case CLOCK_EVT_STATE_DETACHED: |
---|
| 100 | + case CLOCK_EVT_STATE_RESERVED: |
---|
100 | 101 | /* The clockevent device is getting replaced. Shut it down. */ |
---|
101 | 102 | |
---|
102 | 103 | case CLOCK_EVT_STATE_SHUTDOWN: |
---|
.. | .. |
---|
437 | 438 | } |
---|
438 | 439 | EXPORT_SYMBOL_GPL(clockevents_unbind_device); |
---|
439 | 440 | |
---|
| 441 | +#ifdef CONFIG_IRQ_PIPELINE |
---|
| 442 | + |
---|
| 443 | +/** |
---|
| 444 | + * clockevents_register_proxy - register a proxy device on the current CPU |
---|
| 445 | + * @dev: proxy to register |
---|
| 446 | + */ |
---|
| 447 | +int clockevents_register_proxy(struct clock_proxy_device *dev) |
---|
| 448 | +{ |
---|
| 449 | + struct clock_event_device *proxy_dev, *real_dev; |
---|
| 450 | + unsigned long flags; |
---|
| 451 | + u32 freq; |
---|
| 452 | + int ret; |
---|
| 453 | + |
---|
| 454 | + raw_spin_lock_irqsave(&clockevents_lock, flags); |
---|
| 455 | + |
---|
| 456 | + ret = tick_setup_proxy(dev); |
---|
| 457 | + if (ret) { |
---|
| 458 | + raw_spin_unlock_irqrestore(&clockevents_lock, flags); |
---|
| 459 | + return ret; |
---|
| 460 | + } |
---|
| 461 | + |
---|
| 462 | + proxy_dev = &dev->proxy_device; |
---|
| 463 | + clockevent_set_state(proxy_dev, CLOCK_EVT_STATE_DETACHED); |
---|
| 464 | + |
---|
| 465 | + list_add(&proxy_dev->list, &clockevent_devices); |
---|
| 466 | + tick_check_new_device(proxy_dev); |
---|
| 467 | + clockevents_notify_released(); |
---|
| 468 | + |
---|
| 469 | + raw_spin_unlock_irqrestore(&clockevents_lock, flags); |
---|
| 470 | + |
---|
| 471 | + real_dev = dev->real_device; |
---|
| 472 | + freq = (1000000000ULL * real_dev->mult) >> real_dev->shift; |
---|
| 473 | + printk(KERN_INFO "CPU%d: proxy tick device registered (%u.%02uMHz)\n", |
---|
| 474 | + smp_processor_id(), freq / 1000000, (freq / 10000) % 100); |
---|
| 475 | + |
---|
| 476 | + return ret; |
---|
| 477 | +} |
---|
| 478 | + |
---|
| 479 | +void clockevents_unregister_proxy(struct clock_proxy_device *dev) |
---|
| 480 | +{ |
---|
| 481 | + unsigned long flags; |
---|
| 482 | + int ret; |
---|
| 483 | + |
---|
| 484 | + clockevents_register_device(dev->real_device); |
---|
| 485 | + clockevents_switch_state(dev->real_device, CLOCK_EVT_STATE_DETACHED); |
---|
| 486 | + |
---|
| 487 | + /* |
---|
| 488 | + * Pop the proxy device, do not give it back to the |
---|
| 489 | + * framework. |
---|
| 490 | + */ |
---|
| 491 | + raw_spin_lock_irqsave(&clockevents_lock, flags); |
---|
| 492 | + ret = clockevents_replace(&dev->proxy_device); |
---|
| 493 | + raw_spin_unlock_irqrestore(&clockevents_lock, flags); |
---|
| 494 | + |
---|
| 495 | + if (WARN_ON(ret)) |
---|
| 496 | + return; |
---|
| 497 | + |
---|
| 498 | + printk(KERN_INFO "CPU%d: proxy tick device unregistered\n", |
---|
| 499 | + smp_processor_id()); |
---|
| 500 | +} |
---|
| 501 | + |
---|
| 502 | +#endif |
---|
| 503 | + |
---|
440 | 504 | /** |
---|
441 | 505 | * clockevents_register_device - register a clock event device |
---|
442 | 506 | * @dev: device to register |
---|
.. | .. |
---|
575 | 639 | */ |
---|
576 | 640 | if (old) { |
---|
577 | 641 | module_put(old->owner); |
---|
578 | | - clockevents_switch_state(old, CLOCK_EVT_STATE_DETACHED); |
---|
| 642 | + /* |
---|
| 643 | + * Do not move the device backing a proxy tick device |
---|
| 644 | + * to the release list, keep it around but mark it as |
---|
| 645 | + * reserved. |
---|
| 646 | + */ |
---|
579 | 647 | list_del(&old->list); |
---|
580 | | - list_add(&old->list, &clockevents_released); |
---|
| 648 | + if (tick_check_is_proxy(new)) { |
---|
| 649 | + clockevents_switch_state(old, CLOCK_EVT_STATE_RESERVED); |
---|
| 650 | + } else { |
---|
| 651 | + clockevents_switch_state(old, CLOCK_EVT_STATE_DETACHED); |
---|
| 652 | + list_add(&old->list, &clockevents_released); |
---|
| 653 | + } |
---|
581 | 654 | } |
---|
582 | 655 | |
---|
583 | 656 | if (new) { |
---|