요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. _device_link:
============
Device links
============
By default, the driver core only enforces dependencies between devices
that are borne out of a parent/child relationship within the device
hierarchy: When suspending, resuming or shutting down the system, devices
are ordered based on this relationship, i.e. children are always suspended
before their parent, and the parent is always resumed before its children.
Sometimes there is a need to represent device dependencies beyond the
mere parent/child relationship, e.g. between siblings, and have the
driver core automatically take care of them.
Secondly, the driver core by default does not enforce any driver presence
dependencies, i.e. that one device must be bound to a driver before
another one can probe or function correctly.
Often these two dependency types come together, so a device depends on
another one both with regards to driver presence *and* with regards to
suspend/resume and shutdown ordering.
Device links allow representation of such dependencies in the driver core.
In its standard or *managed* form, a device link combines *both* dependency
types: It guarantees correct suspend/resume and shutdown ordering between a
"supplier" device and its "consumer" devices, and it guarantees driver
presence on the supplier. The consumer devices are not probed before the
supplier is bound to a driver, and they're unbound before the supplier
is unbound.
When driver presence on the supplier is irrelevant and only correct
suspend/resume and shutdown ordering is needed, the device link may
simply be set up with the ``DL_FLAG_STATELESS`` flag. In other words,
enforcing driver presence on the supplier is optional.
Another optional feature is runtime PM integration: By setting the
``DL_FLAG_PM_RUNTIME`` flag on addition of the device link, the PM core
is instructed to runtime resume the supplier and keep it active
whenever and for as long as the consumer is runtime resumed.
Usage
=====
The earliest point in time when device links can be added is after
:c:func:`device_add()` has been called for the supplier and
:c:func:`device_initialize()` has been called for the consumer.
It is legal to add them later, but care must be taken that the system
remains in a consistent state: E.g. a device link cannot be added in
the midst of a suspend/resume transition, so either commencement of
such a transition needs to be prevented with :c:func:`lock_system_sleep()`,
or the device link needs to be added from a function which is guaranteed
not to run in parallel to a suspend/resume transition, such as from a
device ``->probe`` callback or a boot-time PCI quirk.
Another example for an inconsistent state would be a device link that
represents a driver presence dependency, yet is added from the consumer's
``->probe`` callback while the supplier hasn't started to probe yet: Had the
driver core known about the device link earlier, it wouldn't have probed the
consumer in the first place. The onus is thus on the consumer to check
presence of the supplier after adding the link, and defer probing on
non-presence. [Note that it is valid to create a link from the consumer's
``->probe`` callback while the supplier is still probing, but the consumer must
know that the supplier is functional already at the link creation time (that is
the case, for instance, if the consumer has just acquired some resources that
would not have been available had the supplier not been functional then).]
If a device link with ``DL_FLAG_STATELESS`` set (i.e. a stateless device link)
is added in the ``->probe`` callback of the supplier or consumer driver, it is
typically deleted in its ``->remove`` callback for symmetry. That way, if the
driver is compiled as a module, the device link is added on module load and
orderly deleted on unload. The same restrictions that apply to device link
addition (e.g. exclusion of a parallel suspend/resume transition) apply equally
to deletion. Device links managed by the driver core are deleted automatically
by it.
Several flags may be specified on device link addition, two of which
have already been mentioned above: ``DL_FLAG_STATELESS`` to express that no
driver presence dependency is needed (but only correct suspend/resume and
shutdown ordering) and ``DL_FLAG_PM_RUNTIME`` to express that runtime PM
integration is desired.
Two other flags are specifically targeted at use cases where the device
link is added from the consumer's ``->probe`` callback: ``DL_FLAG_RPM_ACTIVE``
can be specified to runtime resume the supplier and prevent it from suspending
before the consumer is runtime suspended. ``DL_FLAG_AUTOREMOVE_CONSUMER``
causes the device link to be automatically purged when the consumer fails to
probe or later unbinds.
Similarly, when the device link is added from supplier's ``->probe`` callback,
``DL_FLAG_AUTOREMOVE_SUPPLIER`` causes the device link to be automatically
purged when the supplier fails to probe or later unbinds.
If neither ``DL_FLAG_AUTOREMOVE_CONSUMER`` nor ``DL_FLAG_AUTOREMOVE_SUPPLIER``
is set, ``DL_FLAG_AUTOPROBE_CONSUMER`` can be used to request the driver core
to probe for a driver for the consumer driver on the link automatically after
a driver has been bound to the supplier device.
Note, however, that any combinations of ``DL_FLAG_AUTOREMOVE_CONSUMER``,
``DL_FLAG_AUTOREMOVE_SUPPLIER`` or ``DL_FLAG_AUTOPROBE_CONSUMER`` with
``DL_FLAG_STATELESS`` are invalid and cannot be used.
Limitations
===========
Driver authors should be aware that a driver presence dependency for managed
device links (i.e. when ``DL_FLAG_STATELESS`` is not specified on link addition)
may cause probing of the consumer to be deferred indefinitely. This can become
a problem if the consumer is required to probe before a certain initcall level
is reached. Worse, if the supplier driver is blacklisted or missing, the
consumer will never be probed.
Moreover, managed device links cannot be deleted directly. They are deleted
by the driver core when they are not necessary any more in accordance with the
``DL_FLAG_AUTOREMOVE_CONSUMER`` and ``DL_FLAG_AUTOREMOVE_SUPPLIER`` flags.
However, stateless device links (i.e. device links with ``DL_FLAG_STATELESS``
set) are expected to be removed by whoever called :c:func:`device_link_add()`
to add them with the help of either :c:func:`device_link_del()` or
:c:func:`device_link_remove()`.
Passing ``DL_FLAG_RPM_ACTIVE`` along with ``DL_FLAG_STATELESS`` to
:c:func:`device_link_add()` may cause the PM-runtime usage counter of the
supplier device to remain nonzero after a subsequent invocation of either
:c:func:`device_link_del()` or :c:func:`device_link_remove()` to remove the
device link returned by it. This happens if :c:func:`device_link_add()` is
called twice in a row for the same consumer-supplier pair without removing the
link between these calls, in which case allowing the PM-runtime usage counter
of the supplier to drop on an attempt to remove the link may cause it to be
suspended while the consumer is still PM-runtime-active and that has to be
avoided. [To work around this limitation it is sufficient to let the consumer
runtime suspend at least once, or call :c:func:`pm_runtime_set_suspended()` for
it with PM-runtime disabled, between the :c:func:`device_link_add()` and
:c:func:`device_link_del()` or :c:func:`device_link_remove()` calls.]
Sometimes drivers depend on optional resources. They are able to operate
in a degraded mode (reduced feature set or performance) when those resources
are not present. An example is an SPI controller that can use a DMA engine
or work in PIO mode. The controller can determine presence of the optional
resources at probe time but on non-presence there is no way to know whether
they will become available in the near future (due to a supplier driver
probing) or never. Consequently it cannot be determined whether to defer
probing or not. It would be possible to notify drivers when optional
resources become available after probing, but it would come at a high cost
for drivers as switching between modes of operation at runtime based on the
availability of such resources would be much more complex than a mechanism
based on probe deferral. In any case optional resources are beyond the
scope of device links.
Examples
========
* An MMU device exists alongside a busmaster device, both are in the same
power domain. The MMU implements DMA address translation for the busmaster
device and shall be runtime resumed and kept active whenever and as long
as the busmaster device is active. The busmaster device's driver shall
not bind before the MMU is bound. To achieve this, a device link with
runtime PM integration is added from the busmaster device (consumer)
to the MMU device (supplier). The effect with regards to runtime PM
is the same as if the MMU was the parent of the master device.
The fact that both devices share the same power domain would normally
suggest usage of a struct dev_pm_domain or struct generic_pm_domain,
however these are not independent devices that happen to share a power
switch, but rather the MMU device serves the busmaster device and is
useless without it. A device link creates a synthetic hierarchical
relationship between the devices and is thus more apt.
* A Thunderbolt host controller comprises a number of PCIe hotplug ports
and an NHI device to manage the PCIe switch. On resume from system sleep,
the NHI device needs to re-establish PCI tunnels to attached devices
before the hotplug ports can resume. If the hotplug ports were children
of the NHI, this resume order would automatically be enforced by the
PM core, but unfortunately they're aunts. The solution is to add
device links from the hotplug ports (consumers) to the NHI device
(supplier). A driver presence dependency is not necessary for this
use case.
* Discrete GPUs in hybrid graphics laptops often feature an HDA controller
for HDMI/DP audio. In the device hierarchy the HDA controller is a sibling
of the VGA device, yet both share the same power domain and the HDA
controller is only ever needed when an HDMI/DP display is attached to the
VGA device. A device link from the HDA controller (consumer) to the
VGA device (supplier) aptly represents this relationship.
* ACPI allows definition of a device start order by way of _DEP objects.
A classical example is when ACPI power management methods on one device
are implemented in terms of I\ :sup:`2`\ C accesses and require a specific
I\ :sup:`2`\ C controller to be present and functional for the power
management of the device in question to work.
* In some SoCs a functional dependency exists from display, video codec and
video processing IP cores on transparent memory access IP cores that handle
burst access and compression/decompression.
Alternatives
============
* A struct dev_pm_domain can be used to override the bus,
class or device type callbacks. It is intended for devices sharing
a single on/off switch, however it does not guarantee a specific
suspend/resume ordering, this needs to be implemented separately.
It also does not by itself track the runtime PM status of the involved
devices and turn off the power switch only when all of them are runtime
suspended. Furthermore it cannot be used to enforce a specific shutdown
ordering or a driver presence dependency.
* A struct generic_pm_domain is a lot more heavyweight than a
device link and does not allow for shutdown ordering or driver presence
dependencies. It also cannot be used on ACPI systems.
Implementation
==============
The device hierarchy, which -- as the name implies -- is a tree,
becomes a directed acyclic graph once device links are added.
Ordering of these devices during suspend/resume is determined by the
dpm_list. During shutdown it is determined by the devices_kset. With
no device links present, the two lists are a flattened, one-dimensional
representations of the device tree such that a device is placed behind
all its ancestors. That is achieved by traversing the ACPI namespace
or OpenFirmware device tree top-down and appending devices to the lists
as they are discovered.
Once device links are added, the lists need to satisfy the additional
constraint that a device is placed behind all its suppliers, recursively.
To ensure this, upon addition of the device link the consumer and the
entire sub-graph below it (all children and consumers of the consumer)
are moved to the end of the list. (Call to :c:func:`device_reorder_to_tail()`
from :c:func:`device_link_add()`.)
To prevent introduction of dependency loops into the graph, it is
verified upon device link addition that the supplier is not dependent
on the consumer or any children or consumers of the consumer.
(Call to :c:func:`device_is_dependent()` from :c:func:`device_link_add()`.)
If that constraint is violated, :c:func:`device_link_add()` will return
``NULL`` and a ``WARNING`` will be logged.
Notably this also prevents the addition of a device link from a parent
device to a child. However the converse is allowed, i.e. a device link
from a child to a parent. Since the driver core already guarantees
correct suspend/resume and shutdown ordering between parent and child,
such a device link only makes sense if a driver presence dependency is
needed on top of that. In this case driver authors should weigh
carefully if a device link is at all the right tool for the purpose.
A more suitable approach might be to simply use deferred probing or
add a device flag causing the parent driver to be probed before the
child one.
State machine
=============
.. kernel-doc:: include/linux/device.h
:functions: device_link_state
::
.=============================.
| |
v |
DORMANT <=> AVAILABLE <=> CONSUMER_PROBE => ACTIVE
^ |
| |
'============ SUPPLIER_UNBIND <============'
* The initial state of a device link is automatically determined by
:c:func:`device_link_add()` based on the driver presence on the supplier
and consumer. If the link is created before any devices are probed, it
is set to ``DL_STATE_DORMANT``.
* When a supplier device is bound to a driver, links to its consumers
progress to ``DL_STATE_AVAILABLE``.
(Call to :c:func:`device_links_driver_bound()` from
:c:func:`driver_bound()`.)
* Before a consumer device is probed, presence of supplier drivers is
verified by checking the consumer device is not in the wait_for_suppliers
list and by checking that links to suppliers are in ``DL_STATE_AVAILABLE``
state. The state of the links is updated to ``DL_STATE_CONSUMER_PROBE``.
(Call to :c:func:`device_links_check_suppliers()` from
:c:func:`really_probe()`.)
This prevents the supplier from unbinding.
(Call to :c:func:`wait_for_device_probe()` from
:c:func:`device_links_unbind_consumers()`.)
* If the probe fails, links to suppliers revert back to ``DL_STATE_AVAILABLE``.
(Call to :c:func:`device_links_no_driver()` from :c:func:`really_probe()`.)
* If the probe succeeds, links to suppliers progress to ``DL_STATE_ACTIVE``.
(Call to :c:func:`device_links_driver_bound()` from :c:func:`driver_bound()`.)
* When the consumer's driver is later on removed, links to suppliers revert
back to ``DL_STATE_AVAILABLE``.
(Call to :c:func:`__device_links_no_driver()` from
:c:func:`device_links_driver_cleanup()`, which in turn is called from
:c:func:`__device_release_driver()`.)
* Before a supplier's driver is removed, links to consumers that are not
bound to a driver are updated to ``DL_STATE_SUPPLIER_UNBIND``.
(Call to :c:func:`device_links_busy()` from
:c:func:`__device_release_driver()`.)
This prevents the consumers from binding.
(Call to :c:func:`device_links_check_suppliers()` from
:c:func:`really_probe()`.)
Consumers that are bound are freed from their driver; consumers that are
probing are waited for until they are done.
(Call to :c:func:`device_links_unbind_consumers()` from
:c:func:`__device_release_driver()`.)
Once all links to consumers are in ``DL_STATE_SUPPLIER_UNBIND`` state,
the supplier driver is released and the links revert to ``DL_STATE_DORMANT``.
(Call to :c:func:`device_links_driver_cleanup()` from
:c:func:`__device_release_driver()`.)
API
===
See device_link_add(), device_link_del() and device_link_remove().
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Device link dependency model
1-43.. _device_link:
기본적으로 driver core는 device hierarchy의 parent/child 관계에서 생기는 dependency만 강제합니다. system suspend, resume, shutdown 때 child는 항상 parent보다 먼저 suspend되고 parent는 child보다 먼저 resume됩니다.
그러나 sibling 사이처럼 parent/child 관계를 넘어선 device dependency를 표현하고 driver core가 자동으로 처리해야 할 때가 있습니다. 또한 기본 driver core는 한 device가 probe되거나 올바르게 동작하기 전에 다른 device가 driver에 bind되어 있어야 한다는 driver presence dependency를 강제하지 않습니다.
두 dependency는 자주 함께 나타납니다. 즉 consumer device가 supplier device에 driver presence와 suspend/resume·shutdown ordering 양쪽 모두에서 의존할 수 있습니다. Device link는 이런 dependency를 driver core에 표현합니다.
표준 또는 managed device link는 두 dependency를 결합합니다. supplier와 consumer 사이의 올바른 suspend/resume·shutdown 순서를 보장하고 supplier의 driver presence도 보장합니다. supplier가 driver에 bind되기 전에는 consumer를 probe하지 않으며 supplier가 unbind되기 전에 consumer를 먼저 unbind합니다.
supplier의 driver presence가 중요하지 않고 ordering만 필요하면 `DL_FLAG_STATELESS`를 사용합니다. `DL_FLAG_PM_RUNTIME`을 지정하면 consumer가 runtime resumed 상태인 동안 PM core가 supplier를 runtime resume하고 active로 유지합니다.
managed, stateless, runtime-PM integrated link가 강제하는 dependency를 비교했습니다.
Device link 추가·삭제 시점
44-78device link를 가장 일찍 추가할 수 있는 시점은 supplier에 :c:func:`device_add()`를 호출하고 consumer에 :c:func:`device_initialize()`를 호출한 뒤입니다.
더 늦게 추가해도 되지만 system state가 일관되어야 합니다. suspend/resume transition 도중에는 link를 추가할 수 없으므로 :c:func:`lock_system_sleep()`으로 transition 시작을 막거나, device `->probe` callback이나 boot-time PCI quirk처럼 suspend/resume과 병렬 실행되지 않는 function에서 추가해야 합니다.
driver presence dependency를 나타내는 link를 supplier probe가 시작되기 전에 consumer `->probe`에서 추가하면 state가 모순될 수 있습니다. driver core가 link를 미리 알았다면 consumer를 probe하지 않았을 것이기 때문입니다. 따라서 consumer는 link를 추가한 뒤 supplier presence를 확인하고 없으면 probe를 defer해야 합니다.
supplier가 아직 probing 중이어도 consumer가 link 생성 시점에 supplier가 이미 functional임을 아는 경우에는 consumer `->probe`에서 link를 만들 수 있습니다. 예를 들어 supplier가 동작하지 않았다면 얻을 수 없었을 resource를 consumer가 방금 획득한 경우입니다.
supplier 또는 consumer driver의 `->probe`에서 `DL_FLAG_STATELESS` link를 추가했다면 보통 대칭적으로 `->remove`에서 삭제합니다. module load 때 추가하고 unload 때 orderly delete할 수 있습니다. 추가 때와 같은 suspend/resume 배제 조건이 삭제에도 적용됩니다. managed link는 driver core가 자동으로 삭제합니다.
Device link flag
79-105link 추가 때 여러 flag를 지정할 수 있습니다. `DL_FLAG_STATELESS`는 driver presence dependency 없이 ordering만 필요함을, `DL_FLAG_PM_RUNTIME`은 runtime PM integration이 필요함을 나타냅니다.
consumer `->probe`에서 link를 추가하는 경우 `DL_FLAG_RPM_ACTIVE`는 supplier를 runtime resume하고 consumer가 runtime suspended되기 전까지 supplier suspend를 막습니다. `DL_FLAG_AUTOREMOVE_CONSUMER`는 consumer probe가 실패하거나 나중에 unbind될 때 link를 자동 제거합니다.
supplier `->probe`에서 link를 추가할 때 `DL_FLAG_AUTOREMOVE_SUPPLIER`는 supplier probe 실패 또는 unbind 때 link를 자동 제거합니다. 두 AUTOREMOVE flag가 없으면 `DL_FLAG_AUTOPROBE_CONSUMER`로 supplier bind 뒤 driver core가 consumer driver probe를 자동 요청하게 할 수 있습니다.
`DL_FLAG_AUTOREMOVE_CONSUMER`, `DL_FLAG_AUTOREMOVE_SUPPLIER`, `DL_FLAG_AUTOPROBE_CONSUMER` 가운데 어느 것도 `DL_FLAG_STATELESS`와 조합할 수 없습니다.
link 생성 위치와 lifecycle에 따라 각 flag가 수행하는 동작을 정리했습니다.
Managed link와 runtime PM 제약
106-137managed device link의 driver presence dependency는 consumer probe를 무기한 defer할 수 있습니다. 특정 initcall level 전에 consumer가 probe되어야 하면 문제가 되며 supplier driver가 blacklist되었거나 없으면 consumer는 영원히 probe되지 않습니다.
managed link는 직접 삭제할 수 없습니다. 필요 없어지면 driver core가 `DL_FLAG_AUTOREMOVE_CONSUMER`와 `DL_FLAG_AUTOREMOVE_SUPPLIER`에 따라 삭제합니다. 반면 stateless link는 :c:func:`device_link_add()`를 호출한 주체가 :c:func:`device_link_del()` 또는 :c:func:`device_link_remove()`로 제거해야 합니다.
`DL_FLAG_RPM_ACTIVE`와 `DL_FLAG_STATELESS`를 함께 사용하면 link 제거 뒤에도 supplier의 PM-runtime usage counter가 0이 아닐 수 있습니다. 같은 consumer-supplier pair에 대해 중간 삭제 없이 :c:func:`device_link_add()`를 연속 두 번 호출한 경우입니다.
이때 link 제거 시 supplier usage counter를 낮추면 consumer가 아직 PM-runtime-active인데 supplier가 suspend될 수 있어 이를 피해야 합니다. workaround는 add와 del/remove 사이에 consumer를 적어도 한 번 runtime suspend하거나, PM-runtime을 끈 상태에서 consumer에 :c:func:`pm_runtime_set_suspended()`를 호출하는 것입니다.
Optional resource는 device link 범위 밖
138-151일부 driver는 optional resource가 없어도 feature나 performance가 줄어든 degraded mode로 동작할 수 있습니다. 예를 들어 SPI controller는 DMA engine을 사용하거나 PIO mode로 작동할 수 있습니다.
controller는 probe 때 optional resource presence를 확인할 수 있지만, 없을 때 supplier driver가 곧 probe해 resource가 생길지 영원히 없을지는 알 수 없습니다. 따라서 probe를 defer할지 결정할 수 없습니다.
probe 뒤 optional resource가 생겼음을 driver에 알릴 수도 있지만 runtime resource availability에 따라 operation mode를 바꾸는 것은 probe deferral 기반 mechanism보다 훨씬 복잡합니다. 어떤 경우든 optional resource는 device link의 scope 밖입니다.
Device link 사용 사례
152-197- MMU와 busmaster device가 같은 power domain에 있을 때 MMU는 busmaster의 DMA address translation을 수행합니다. busmaster가 active인 동안 MMU를 runtime resume 상태로 유지하고 MMU driver가 먼저 bind되도록 busmaster consumer에서 MMU supplier로 runtime PM device link를 추가합니다. 단순 power switch 공유가 아니라 MMU가 busmaster를 service하는 관계이므로 synthetic hierarchy인 device link가 `struct dev_pm_domain`이나 `struct generic_pm_domain`보다 적합합니다.
- Thunderbolt host controller의 PCIe hotplug port는 system sleep resume 때 NHI가 PCI tunnel을 먼저 복원해야 합니다. hotplug port는 NHI의 child가 아니므로 각 port consumer에서 NHI supplier로 device link를 추가해 resume ordering을 강제합니다. 이 경우 driver presence dependency는 필요하지 않습니다.
- hybrid graphics laptop의 discrete GPU에는 HDMI/DP audio용 HDA controller가 있을 수 있습니다. HDA와 VGA는 sibling이지만 같은 power domain을 공유하고 HDA는 VGA에 display가 연결될 때만 필요하므로 HDA consumer에서 VGA supplier로 가는 device link가 관계를 표현합니다.
- ACPI `_DEP` object는 device start order를 정의할 수 있습니다. 한 device의 ACPI power management method가 I²C access로 구현되어 특정 I²C controller가 먼저 존재하고 동작해야 하는 경우가 대표적입니다.
- 일부 SoC에서는 display, video codec, video processing IP core가 burst access와 compression/decompression을 처리하는 transparent memory access IP core에 functional dependency를 가집니다.
대안 mechanism
198-213`struct dev_pm_domain`은 bus, class 또는 device type callback을 override할 수 있고 단일 on/off switch를 공유하는 device를 위한 것입니다. 그러나 특정 suspend/resume ordering을 보장하지 않아 별도 구현이 필요합니다. runtime PM status를 자체 추적해 모든 device가 suspend될 때만 switch를 끄지도 않으며 shutdown ordering이나 driver presence dependency도 강제할 수 없습니다.
`struct generic_pm_domain`은 device link보다 훨씬 무겁고 shutdown ordering이나 driver presence dependency를 허용하지 않으며 ACPI system에서는 사용할 수 없습니다.
Tree에서 directed acyclic graph로
214-252device hierarchy는 원래 tree이지만 device link를 추가하면 directed acyclic graph(DAG)가 됩니다. suspend/resume ordering은 `dpm_list`, shutdown ordering은 `devices_kset`이 결정합니다.
device link가 없을 때 두 list는 device tree를 평탄화한 1차원 표현이며 각 device는 모든 ancestor 뒤에 배치됩니다. ACPI namespace 또는 OpenFirmware device tree를 top-down으로 순회하고 발견한 device를 list에 append해 이를 달성합니다.
device link가 추가되면 각 device가 모든 supplier 뒤에 재귀적으로 배치되어야 합니다. link 추가 때 consumer와 그 아래 전체 sub-graph, 즉 consumer의 모든 child와 consumer를 list 끝으로 이동합니다. :c:func:`device_link_add()`가 :c:func:`device_reorder_to_tail()`을 호출합니다.
dependency loop를 막기 위해 link 추가 때 supplier가 consumer 또는 consumer의 child·consumer에 의존하지 않는지 확인합니다. :c:func:`device_link_add()`가 :c:func:`device_is_dependent()`를 호출하며 위반 시 `NULL`을 반환하고 `WARNING`을 기록합니다.
이 검사는 parent에서 child로 향하는 device link도 막지만 child에서 parent로 향하는 link는 허용합니다. parent/child ordering은 이미 driver core가 보장하므로 이런 link는 추가 driver presence dependency가 필요할 때만 의미가 있습니다. 그 목적이라면 deferred probing이나 parent driver를 먼저 probe하게 하는 device flag가 더 적합할 수 있습니다.
Device link state machine
253-268`device_link_state` enum의 kernel-doc와 원문 state diagram은 managed device link의 lifecycle을 나타냅니다.
.. kernel-doc:: include/linux/device.h
:functions: device_link_state
.=============================.
| |
v |
DORMANT <=> AVAILABLE <=> CONSUMER_PROBE => ACTIVE
^ |
| |
'============ SUPPLIER_UNBIND <============'
원문의 ASCII state machine과 이어지는 설명을 event 중심 transition table로 재구성했습니다.
State transition 세부 동작
269-316- 초기 state는 supplier와 consumer의 driver presence를 바탕으로 :c:func:`device_link_add()`가 자동 결정합니다. 어느 device도 probe되기 전에 link를 만들면 `DL_STATE_DORMANT`입니다.
- supplier가 driver에 bind되면 consumer로 향하는 link는 `DL_STATE_AVAILABLE`로 진행합니다. :c:func:`driver_bound()`에서 :c:func:`device_links_driver_bound()`를 호출합니다.
- consumer probe 전에 consumer가 `wait_for_suppliers` list에 없고 supplier link가 `DL_STATE_AVAILABLE`인지 검사한 뒤 `DL_STATE_CONSUMER_PROBE`로 바꿉니다. :c:func:`really_probe()`가 :c:func:`device_links_check_suppliers()`를 호출합니다. :c:func:`device_links_unbind_consumers()`의 :c:func:`wait_for_device_probe()` 호출은 supplier unbind를 막습니다.
- probe가 실패하면 supplier link는 `DL_STATE_AVAILABLE`로 돌아갑니다. :c:func:`really_probe()`가 :c:func:`device_links_no_driver()`를 호출합니다. 성공하면 `DL_STATE_ACTIVE`로 진행하며 :c:func:`driver_bound()`가 :c:func:`device_links_driver_bound()`를 호출합니다.
- 나중에 consumer driver를 제거하면 supplier link는 `DL_STATE_AVAILABLE`로 돌아갑니다. :c:func:`__device_release_driver()`에서 이어지는 cleanup이 :c:func:`__device_links_no_driver()`를 호출합니다.
- supplier driver 제거 전, driver에 bind되지 않은 consumer link는 `DL_STATE_SUPPLIER_UNBIND`로 바뀌어 consumer bind를 막습니다. bind된 consumer는 driver에서 해제하고 probing 중인 consumer는 완료될 때까지 기다립니다.
- 모든 consumer link가 `DL_STATE_SUPPLIER_UNBIND`가 되면 supplier driver를 release하고 link는 `DL_STATE_DORMANT`로 돌아갑니다. :c:func:`__device_release_driver()`에서 :c:func:`device_links_driver_cleanup()`을 호출합니다.
Device link API
317-320API 사용법은 `device_link_add()`, `device_link_del()`, `device_link_remove()`를 참조합니다.
요약과 해설
device_link.rst:1-320Device link는 supplier와 consumer 사이의 driver presence 및 suspend/resume·shutdown ordering을 driver core의 DAG에 추가합니다. managed와 stateless lifecycle, runtime PM flag, auto-remove/probe flag, probe deferral 제약을 이해해야 하며 link 추가 시 list reorder와 cycle 검사로 ordering을 보장합니다. state machine은 supplier bind, consumer probe, active, unbind, dormant 전이를 명시합니다.