요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
================================
I2C muxes and complex topologies
================================
There are a couple of reasons for building more complex I2C topologies
than a straight-forward I2C bus with one adapter and one or more devices.
Some example use cases are:
1. A mux may be needed on the bus to prevent address collisions.
2. The bus may be accessible from some external bus master, and arbitration
may be needed to determine if it is ok to access the bus.
3. A device (particularly RF tuners) may want to avoid the digital noise
from the I2C bus, at least most of the time, and sits behind a gate
that has to be operated before the device can be accessed.
Several types of hardware components such as I2C muxes, I2C gates and I2C
arbitrators allow to handle such needs.
These components are represented as I2C adapter trees by Linux, where
each adapter has a parent adapter (except the root adapter) and zero or
more child adapters. The root adapter is the actual adapter that issues
I2C transfers, and all adapters with a parent are part of an "i2c-mux"
object (quoted, since it can also be an arbitrator or a gate).
Depending of the particular mux driver, something happens when there is
an I2C transfer on one of its child adapters. The mux driver can
obviously operate a mux, but it can also do arbitration with an external
bus master or open a gate. The mux driver has two operations for this,
select and deselect. select is called before the transfer and (the
optional) deselect is called after the transfer.
Locking
=======
There are two variants of locking available to I2C muxes, they can be
mux-locked or parent-locked muxes.
Mux-locked muxes
----------------
Mux-locked muxes does not lock the entire parent adapter during the
full select-transfer-deselect transaction, only the muxes on the parent
adapter are locked. Mux-locked muxes are mostly interesting if the
select and/or deselect operations must use I2C transfers to complete
their tasks. Since the parent adapter is not fully locked during the
full transaction, unrelated I2C transfers may interleave the different
stages of the transaction. This has the benefit that the mux driver
may be easier and cleaner to implement, but it has some caveats.
Mux-locked Example
~~~~~~~~~~~~~~~~~~
::
.----------. .--------.
.--------. | mux- |-----| dev D1 |
| root |--+--| locked | '--------'
'--------' | | mux M1 |--. .--------.
| '----------' '--| dev D2 |
| .--------. '--------'
'--| dev D3 |
'--------'
When there is an access to D1, this happens:
1. Someone issues an I2C transfer to D1.
2. M1 locks muxes on its parent (the root adapter in this case).
3. M1 calls ->select to ready the mux.
4. M1 (presumably) does some I2C transfers as part of its select.
These transfers are normal I2C transfers that locks the parent
adapter.
5. M1 feeds the I2C transfer from step 1 to its parent adapter as a
normal I2C transfer that locks the parent adapter.
6. M1 calls ->deselect, if it has one.
7. Same rules as in step 4, but for ->deselect.
8. M1 unlocks muxes on its parent.
This means that accesses to D2 are lockout out for the full duration
of the entire operation. But accesses to D3 are possibly interleaved
at any point.
Mux-locked caveats
~~~~~~~~~~~~~~~~~~
When using a mux-locked mux, be aware of the following restrictions:
[ML1]
If you build a topology with a mux-locked mux being the parent
of a parent-locked mux, this might break the expectation from the
parent-locked mux that the root adapter is locked during the
transaction.
[ML2]
It is not safe to build arbitrary topologies with two (or more)
mux-locked muxes that are not siblings, when there are address
collisions between the devices on the child adapters of these
non-sibling muxes.
I.e. the select-transfer-deselect transaction targeting e.g. device
address 0x42 behind mux-one may be interleaved with a similar
operation targeting device address 0x42 behind mux-two. The
intent with such a topology would in this hypothetical example
be that mux-one and mux-two should not be selected simultaneously,
but mux-locked muxes do not guarantee that in all topologies.
[ML3]
A mux-locked mux cannot be used by a driver for auto-closing
gates/muxes, i.e. something that closes automatically after a given
number (one, in most cases) of I2C transfers. Unrelated I2C transfers
may creep in and close prematurely.
[ML4]
If any non-I2C operation in the mux driver changes the I2C mux state,
the driver has to lock the root adapter during that operation.
Otherwise garbage may appear on the bus as seen from devices
behind the mux, when an unrelated I2C transfer is in flight during
the non-I2C mux-changing operation.
Parent-locked muxes
-------------------
Parent-locked muxes lock the parent adapter during the full select-
transfer-deselect transaction. The implication is that the mux driver
has to ensure that any and all I2C transfers through that parent
adapter during the transaction are unlocked I2C transfers (using e.g.
__i2c_transfer), or a deadlock will follow.
Parent-locked Example
~~~~~~~~~~~~~~~~~~~~~
::
.----------. .--------.
.--------. | parent- |-----| dev D1 |
| root |--+--| locked | '--------'
'--------' | | mux M1 |--. .--------.
| '----------' '--| dev D2 |
| .--------. '--------'
'--| dev D3 |
'--------'
When there is an access to D1, this happens:
1. Someone issues an I2C transfer to D1.
2. M1 locks muxes on its parent (the root adapter in this case).
3. M1 locks its parent adapter.
4. M1 calls ->select to ready the mux.
5. If M1 does any I2C transfers (on this root adapter) as part of
its select, those transfers must be unlocked I2C transfers so
that they do not deadlock the root adapter.
6. M1 feeds the I2C transfer from step 1 to the root adapter as an
unlocked I2C transfer, so that it does not deadlock the parent
adapter.
7. M1 calls ->deselect, if it has one.
8. Same rules as in step 5, but for ->deselect.
9. M1 unlocks its parent adapter.
10. M1 unlocks muxes on its parent.
This means that accesses to both D2 and D3 are locked out for the full
duration of the entire operation.
Parent-locked Caveats
~~~~~~~~~~~~~~~~~~~~~
When using a parent-locked mux, be aware of the following restrictions:
[PL1]
If you build a topology with a parent-locked mux being the child
of another mux, this might break a possible assumption from the
child mux that the root adapter is unused between its select op
and the actual transfer (e.g. if the child mux is auto-closing
and the parent mux issues I2C transfers as part of its select).
This is especially the case if the parent mux is mux-locked, but
it may also happen if the parent mux is parent-locked.
[PL2]
If select/deselect calls out to other subsystems such as gpio,
pinctrl, regmap or iio, it is essential that any I2C transfers
caused by these subsystems are unlocked. This can be convoluted to
accomplish, maybe even impossible if an acceptably clean solution
is sought.
Complex Examples
================
Parent-locked mux as parent of parent-locked mux
------------------------------------------------
This is a useful topology, but it can be bad::
.----------. .----------. .--------.
.--------. | parent- |-----| parent- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When any device is accessed, all other devices are locked out for
the full duration of the operation (both muxes lock their parent,
and specifically when M2 requests its parent to lock, M1 passes
the buck to the root adapter).
This topology is bad if M2 is an auto-closing mux and M1->select
issues any unlocked I2C transfers on the root adapter that may leak
through and be seen by the M2 adapter, thus closing M2 prematurely.
Mux-locked mux as parent of mux-locked mux
------------------------------------------
This is a good topology::
.----------. .----------. .--------.
.--------. | mux- |-----| mux- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When device D1 is accessed, accesses to D2 are locked out for the
full duration of the operation (muxes on the top child adapter of M1
are locked). But accesses to D3 and D4 are possibly interleaved at
any point.
Accesses to D3 locks out D1 and D2, but accesses to D4 are still possibly
interleaved.
Mux-locked mux as parent of parent-locked mux
---------------------------------------------
This is probably a bad topology::
.----------. .----------. .--------.
.--------. | mux- |-----| parent- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When device D1 is accessed, accesses to D2 and D3 are locked out
for the full duration of the operation (M1 locks child muxes on the
root adapter). But accesses to D4 are possibly interleaved at any
point.
This kind of topology is generally not suitable and should probably
be avoided. The reason is that M2 probably assumes that there will
be no I2C transfers during its calls to ->select and ->deselect, and
if there are, any such transfers might appear on the slave side of M2
as partial I2C transfers, i.e. garbage or worse. This might cause
device lockups and/or other problems.
The topology is especially troublesome if M2 is an auto-closing
mux. In that case, any interleaved accesses to D4 might close M2
prematurely, as might any I2C transfers part of M1->select.
But if M2 is not making the above stated assumption, and if M2 is not
auto-closing, the topology is fine.
Parent-locked mux as parent of mux-locked mux
---------------------------------------------
This is a good topology::
.----------. .----------. .--------.
.--------. | parent- |-----| mux- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When D1 is accessed, accesses to D2 are locked out for the full
duration of the operation (muxes on the top child adapter of M1
are locked). Accesses to D3 and D4 are possibly interleaved at
any point, just as is expected for mux-locked muxes.
When D3 or D4 are accessed, everything else is locked out. For D3
accesses, M1 locks the root adapter. For D4 accesses, the root
adapter is locked directly.
Two mux-locked sibling muxes
----------------------------
This is a good topology::
.--------.
.----------. .--| dev D1 |
| mux- |--' '--------'
.--| locked | .--------.
| | mux M1 |-----| dev D2 |
| '----------' '--------'
| .----------. .--------.
.--------. | | mux- |-----| dev D3 |
| root |--+--| locked | '--------'
'--------' | | mux M2 |--. .--------.
| '----------' '--| dev D4 |
| .--------. '--------'
'--| dev D5 |
'--------'
When D1 is accessed, accesses to D2, D3 and D4 are locked out. But
accesses to D5 may be interleaved at any time.
Two parent-locked sibling muxes
-------------------------------
This is a good topology::
.--------.
.----------. .--| dev D1 |
| parent- |--' '--------'
.--| locked | .--------.
| | mux M1 |-----| dev D2 |
| '----------' '--------'
| .----------. .--------.
.--------. | | parent- |-----| dev D3 |
| root |--+--| locked | '--------'
'--------' | | mux M2 |--. .--------.
| '----------' '--| dev D4 |
| .--------. '--------'
'--| dev D5 |
'--------'
When any device is accessed, accesses to all other devices are locked
out.
Mux-locked and parent-locked sibling muxes
------------------------------------------
This is a good topology::
.--------.
.----------. .--| dev D1 |
| mux- |--' '--------'
.--| locked | .--------.
| | mux M1 |-----| dev D2 |
| '----------' '--------'
| .----------. .--------.
.--------. | | parent- |-----| dev D3 |
| root |--+--| locked | '--------'
'--------' | | mux M2 |--. .--------.
| '----------' '--| dev D4 |
| .--------. '--------'
'--| dev D5 |
'--------'
When D1 or D2 are accessed, accesses to D3 and D4 are locked out while
accesses to D5 may interleave. When D3 or D4 are accessed, accesses to
all other devices are locked out.
Mux type of existing device drivers
===================================
Whether a device is mux-locked or parent-locked depends on its
implementation. The following list was correct at the time of writing:
In drivers/i2c/muxes/:
====================== =============================================
i2c-arb-gpio-challenge Parent-locked
i2c-mux-gpio Normally parent-locked, mux-locked iff
all involved gpio pins are controlled by the
same I2C root adapter that they mux.
i2c-mux-gpmux Normally parent-locked, mux-locked iff
specified in device-tree.
i2c-mux-ltc4306 Mux-locked
i2c-mux-mlxcpld Parent-locked
i2c-mux-pca9541 Parent-locked
i2c-mux-pca954x Parent-locked
i2c-mux-pinctrl Normally parent-locked, mux-locked iff
all involved pinctrl devices are controlled
by the same I2C root adapter that they mux.
i2c-mux-reg Parent-locked
====================== =============================================
In drivers/iio/:
====================== =============================================
gyro/mpu3050 Mux-locked
imu/inv_mpu6050/ Mux-locked
====================== =============================================
In drivers/media/:
======================= =============================================
dvb-frontends/lgdt3306a Mux-locked
dvb-frontends/m88ds3103 Parent-locked
dvb-frontends/rtl2830 Parent-locked
dvb-frontends/rtl2832 Mux-locked
dvb-frontends/si2168 Mux-locked
usb/cx231xx/ Parent-locked
======================= =============================================
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
복잡한 I2C 토폴로지와 어댑터 트리
1-35하나의 어댑터와 하나 이상의 장치만 있는 단순 I2C 버스보다 복잡한 토폴로지를 구성하는 데에는 몇 가지 이유가 있습니다.
첫째, 주소 충돌을 막기 위해 버스에 mux가 필요할 수 있습니다. 둘째, 외부 버스 마스터도 버스에 접근할 수 있어 현재 접근해도 되는지 판단하는 중재가 필요할 수 있습니다. 셋째, 특히 RF 튜너 같은 장치는 대부분의 시간 동안 I2C 버스의 디지털 잡음을 피하려고 하므로 접근 전에 열어야 하는 gate 뒤에 놓일 수 있습니다.
I2C mux, I2C gate, I2C arbitrator 같은 여러 하드웨어 구성 요소가 이런 요구를 처리합니다.
Linux는 이 구성 요소를 I2C 어댑터 트리로 표현합니다. 루트 어댑터를 제외한 각 어댑터에는 부모 어댑터가 있고, 자식 어댑터는 0개 이상일 수 있습니다. 루트 어댑터는 실제 I2C 전송을 발생시키는 어댑터이며, 부모가 있는 모든 어댑터는 넓은 의미의 `i2c-mux` 객체 일부입니다. 이 객체는 실제 mux뿐 아니라 arbitrator나 gate일 수도 있습니다.
자식 어댑터에서 I2C 전송이 일어나면 해당 mux 드라이버의 종류에 맞는 작업이 수행됩니다. 실제 mux 채널을 선택하거나, 외부 마스터와 중재하거나, gate를 열 수 있습니다.
이를 위해 mux 드라이버에는 `select`와 `deselect` 두 연산이 있습니다. `select`는 전송 전에 호출되고, 선택 사항인 `deselect`는 전송 후 호출됩니다.
각 하드웨어 구성 요소가 해결하는 문제입니다.
루트와 mux 자식 어댑터의 역할을 구조화합니다.
모든 유형은 select와 전송, 선택적 deselect 순서를 따릅니다.
================================
I2C muxes and complex topologies
================================
There are a couple of reasons for building more complex I2C topologies
than a straight-forward I2C bus with one adapter and one or more devices.
Some example use cases are:
1. A mux may be needed on the bus to prevent address collisions.
2. The bus may be accessible from some external bus master, and arbitration
may be needed to determine if it is ok to access the bus.
3. A device (particularly RF tuners) may want to avoid the digital noise
from the I2C bus, at least most of the time, and sits behind a gate
that has to be operated before the device can be accessed.
Several types of hardware components such as I2C muxes, I2C gates and I2C
arbitrators allow to handle such needs.
These components are represented as I2C adapter trees by Linux, where
each adapter has a parent adapter (except the root adapter) and zero or
more child adapters. The root adapter is the actual adapter that issues
I2C transfers, and all adapters with a parent are part of an "i2c-mux"
object (quoted, since it can also be an arbitrator or a gate).
Depending of the particular mux driver, something happens when there is
an I2C transfer on one of its child adapters. The mux driver can
obviously operate a mux, but it can also do arbitration with an external
bus master or open a gate. The mux driver has two operations for this,
select and deselect. select is called before the transfer and (the
optional) deselect is called after the transfer.
mux-locked 잠금과 제약
36-123I2C mux에는 mux-locked와 parent-locked 두 가지 잠금 방식이 있습니다.
mux-locked mux는 `select-transfer-deselect` 전체 동안 부모 어댑터 전체를 잠그지 않고 부모 어댑터 위의 mux들만 잠급니다. `select`나 `deselect` 작업 자체를 완료하기 위해 I2C 전송이 필요한 경우에 특히 유용합니다.
부모 어댑터가 전체 트랜잭션 동안 잠기지 않으므로 무관한 I2C 전송이 각 단계 사이에 끼어들 수 있습니다. mux 드라이버 구현이 더 쉽고 깔끔해질 수 있지만 제약이 따릅니다.
원문의 ASCII 구조를 부모·자식 관계로 재구성합니다.
D1에 접근하면 다음 순서가 일어납니다. 누군가 D1 전송을 발행하고, M1은 부모인 루트 어댑터 위의 mux를 잠근 뒤 `select`를 호출해 mux를 준비합니다.
M1이 `select` 과정에서 I2C 전송을 수행한다면 이는 부모 어댑터를 잠그는 일반 I2C 전송입니다. 이어서 원래 D1 전송도 부모 어댑터를 잠그는 일반 전송으로 전달합니다.
그 뒤 M1은 구현되어 있다면 `deselect`를 호출합니다. 이 과정의 I2C 전송에도 `select`와 같은 규칙이 적용됩니다. 마지막으로 부모 위의 mux 잠금을 해제합니다.
부모 전체 잠금은 각 I2C 전송 동안에만 걸립니다.
전체 동작 동안 같은 M1 뒤의 D2 접근은 차단됩니다. 그러나 루트에 직접 연결된 D3 접근은 어느 단계에서든 끼어들 수 있습니다.
D1 접근 중 다른 장치의 상태입니다.
[ML1] mux-locked mux 아래에 parent-locked mux를 두면, 자식 parent-locked mux가 트랜잭션 동안 루트 어댑터가 잠겨 있다고 기대하는 조건을 깨뜨릴 수 있습니다.
[ML2] 서로 형제가 아닌 mux-locked mux가 둘 이상이고 각 자식 어댑터의 장치 주소가 충돌한다면 임의의 토폴로지는 안전하지 않습니다. 예를 들어 mux-one 뒤 주소 `0x42`를 향한 `select-transfer-deselect`가 mux-two 뒤 주소 `0x42` 작업과 섞일 수 있습니다. 두 mux가 동시에 선택되지 않아야 하는 의도라도 모든 토폴로지에서 이를 보장하지 못합니다.
[ML3] mux-locked mux는 정해진 수, 보통 한 번의 I2C 전송 후 자동으로 닫히는 gate나 mux의 드라이버에 사용할 수 없습니다. 무관한 I2C 전송이 끼어들어 너무 일찍 닫을 수 있습니다.
[ML4] mux 드라이버의 비-I2C 연산이 I2C mux 상태를 바꾼다면 그 연산 동안 루트 어댑터를 잠가야 합니다. 그렇지 않으면 상태 변경 중 무관한 I2C 전송이 진행되어 mux 뒤 장치가 버스에서 잘못된 신호를 볼 수 있습니다.
ML1부터 ML4까지의 위험과 대응입니다.
Locking
=======
There are two variants of locking available to I2C muxes, they can be
mux-locked or parent-locked muxes.
Mux-locked muxes
----------------
Mux-locked muxes does not lock the entire parent adapter during the
full select-transfer-deselect transaction, only the muxes on the parent
adapter are locked. Mux-locked muxes are mostly interesting if the
select and/or deselect operations must use I2C transfers to complete
their tasks. Since the parent adapter is not fully locked during the
full transaction, unrelated I2C transfers may interleave the different
stages of the transaction. This has the benefit that the mux driver
may be easier and cleaner to implement, but it has some caveats.
Mux-locked Example
~~~~~~~~~~~~~~~~~~
::
.----------. .--------.
.--------. | mux- |-----| dev D1 |
| root |--+--| locked | '--------'
'--------' | | mux M1 |--. .--------.
| '----------' '--| dev D2 |
| .--------. '--------'
'--| dev D3 |
'--------'
When there is an access to D1, this happens:
1. Someone issues an I2C transfer to D1.
2. M1 locks muxes on its parent (the root adapter in this case).
3. M1 calls ->select to ready the mux.
4. M1 (presumably) does some I2C transfers as part of its select.
These transfers are normal I2C transfers that locks the parent
adapter.
5. M1 feeds the I2C transfer from step 1 to its parent adapter as a
normal I2C transfer that locks the parent adapter.
6. M1 calls ->deselect, if it has one.
7. Same rules as in step 4, but for ->deselect.
8. M1 unlocks muxes on its parent.
This means that accesses to D2 are lockout out for the full duration
of the entire operation. But accesses to D3 are possibly interleaved
at any point.
Mux-locked caveats
~~~~~~~~~~~~~~~~~~
When using a mux-locked mux, be aware of the following restrictions:
[ML1]
If you build a topology with a mux-locked mux being the parent
of a parent-locked mux, this might break the expectation from the
parent-locked mux that the root adapter is locked during the
transaction.
[ML2]
It is not safe to build arbitrary topologies with two (or more)
mux-locked muxes that are not siblings, when there are address
collisions between the devices on the child adapters of these
non-sibling muxes.
I.e. the select-transfer-deselect transaction targeting e.g. device
address 0x42 behind mux-one may be interleaved with a similar
operation targeting device address 0x42 behind mux-two. The
intent with such a topology would in this hypothetical example
be that mux-one and mux-two should not be selected simultaneously,
but mux-locked muxes do not guarantee that in all topologies.
[ML3]
A mux-locked mux cannot be used by a driver for auto-closing
gates/muxes, i.e. something that closes automatically after a given
number (one, in most cases) of I2C transfers. Unrelated I2C transfers
may creep in and close prematurely.
[ML4]
If any non-I2C operation in the mux driver changes the I2C mux state,
the driver has to lock the root adapter during that operation.
Otherwise garbage may appear on the bus as seen from devices
behind the mux, when an unrelated I2C transfer is in flight during
the non-I2C mux-changing operation.
parent-locked 잠금과 제약
124-189parent-locked mux는 `select-transfer-deselect` 전체 동안 부모 어댑터를 잠급니다. 따라서 mux 드라이버는 이 트랜잭션 중 부모 어댑터를 통과하는 모든 I2C 전송이 `__i2c_transfer` 같은 잠금 없는 I2C 전송이어야 함을 보장해야 합니다. 다시 잠그려 하면 교착 상태가 발생합니다.
원문의 ASCII 구조와 잠금 범위입니다.
D1 접근에서는 먼저 M1이 부모 위의 mux를 잠그고 부모 어댑터 자체도 잠급니다. 이어서 `select`를 호출해 mux를 준비합니다.
M1이 `select` 과정에서 같은 루트 어댑터로 I2C 전송을 한다면 루트 어댑터를 다시 잠그지 않도록 잠금 없는 전송을 사용해야 합니다. 원래 D1 전송도 교착을 피하기 위해 잠금 없는 I2C 전송으로 루트 어댑터에 전달합니다.
구현되어 있다면 `deselect`를 호출하며, 그 안의 전송에도 동일한 잠금 없는 규칙이 적용됩니다. 그 뒤 부모 어댑터 잠금을 해제하고 마지막으로 부모 위 mux 잠금을 해제합니다.
부모 잠금을 한 번 유지한 채 내부 전송은 모두 unlocked API로 수행합니다.
이 방식에서는 전체 동작 동안 같은 mux의 D2뿐 아니라 루트에 직접 연결된 D3 접근도 모두 차단됩니다.
[PL1] parent-locked mux가 다른 mux의 자식이라면, 자식 mux가 `select`와 실제 전송 사이에 루트 어댑터가 사용되지 않는다고 기대하는 조건을 깨뜨릴 수 있습니다. 자식이 auto-closing이고 부모 mux가 `select` 중 I2C 전송을 하는 경우가 예입니다. 부모가 mux-locked일 때 특히 문제지만 parent-locked여도 발생할 수 있습니다.
[PL2] `select`나 `deselect`가 gpio, pinctrl, regmap, iio 같은 다른 하위 시스템을 호출한다면, 이 하위 시스템이 유발하는 모든 I2C 전송도 잠금 없는 전송이어야 합니다. 이를 깔끔하게 보장하는 일은 복잡하거나 불가능할 수도 있습니다.
PL1과 PL2의 중첩·외부 하위 시스템 위험입니다.
잠금 범위와 내부 전송 API를 한눈에 비교합니다.
Parent-locked muxes
-------------------
Parent-locked muxes lock the parent adapter during the full select-
transfer-deselect transaction. The implication is that the mux driver
has to ensure that any and all I2C transfers through that parent
adapter during the transaction are unlocked I2C transfers (using e.g.
__i2c_transfer), or a deadlock will follow.
Parent-locked Example
~~~~~~~~~~~~~~~~~~~~~
::
.----------. .--------.
.--------. | parent- |-----| dev D1 |
| root |--+--| locked | '--------'
'--------' | | mux M1 |--. .--------.
| '----------' '--| dev D2 |
| .--------. '--------'
'--| dev D3 |
'--------'
When there is an access to D1, this happens:
1. Someone issues an I2C transfer to D1.
2. M1 locks muxes on its parent (the root adapter in this case).
3. M1 locks its parent adapter.
4. M1 calls ->select to ready the mux.
5. If M1 does any I2C transfers (on this root adapter) as part of
its select, those transfers must be unlocked I2C transfers so
that they do not deadlock the root adapter.
6. M1 feeds the I2C transfer from step 1 to the root adapter as an
unlocked I2C transfer, so that it does not deadlock the parent
adapter.
7. M1 calls ->deselect, if it has one.
8. Same rules as in step 5, but for ->deselect.
9. M1 unlocks its parent adapter.
10. M1 unlocks muxes on its parent.
This means that accesses to both D2 and D3 are locked out for the full
duration of the entire operation.
Parent-locked Caveats
~~~~~~~~~~~~~~~~~~~~~
When using a parent-locked mux, be aware of the following restrictions:
[PL1]
If you build a topology with a parent-locked mux being the child
of another mux, this might break a possible assumption from the
child mux that the root adapter is unused between its select op
and the actual transfer (e.g. if the child mux is auto-closing
and the parent mux issues I2C transfers as part of its select).
This is especially the case if the parent mux is mux-locked, but
it may also happen if the parent mux is parent-locked.
[PL2]
If select/deselect calls out to other subsystems such as gpio,
pinctrl, regmap or iio, it is essential that any I2C transfers
caused by these subsystems are unlocked. This can be convoluted to
accomplish, maybe even impossible if an acceptably clean solution
is sought.
중첩 mux 조합: parent-parent, mux-mux, mux-parent
190-273parent-locked M1 아래에 parent-locked M2를 두는 구성은 유용하지만 나쁠 수도 있습니다. M2가 부모 잠금을 요청하면 M1이 이를 루트 어댑터까지 전달하므로 어떤 장치에 접근하든 다른 모든 장치는 전체 기간 차단됩니다.
그러나 M2가 auto-closing mux이고 M1의 `select`가 루트 어댑터에서 잠금 없는 I2C 전송을 수행한다면 그 전송이 M2 어댑터 쪽에 새어 들어가 M2를 너무 일찍 닫을 수 있습니다.
원문의 D1~D4 구조와 차단 범위입니다.
mux-locked M1 아래에 mux-locked M2를 두는 것은 좋은 구성입니다. D1 접근 중 같은 M2 뒤의 D2는 전체 기간 차단되지만, M1의 다른 자식 D3와 루트 직결 D4는 어느 시점에도 끼어들 수 있습니다.
D3 접근은 D1과 D2를 차단하지만 D4 접근은 여전히 끼어들 수 있습니다.
계층별 mux 잠금만 적용되는 좋은 구성입니다.
mux-locked M1 아래에 parent-locked M2를 두는 구성은 대체로 나쁩니다. D1 접근 중 M1이 루트 어댑터의 자식 mux를 잠그므로 D2와 D3는 전체 기간 차단되지만 D4는 어느 시점에도 끼어들 수 있습니다.
M2는 `select`와 `deselect` 동안 다른 I2C 전송이 없다고 가정할 가능성이 큽니다. D4 전송이 끼어들면 M2의 슬레이브 쪽에는 부분 I2C 전송, 즉 잘못된 신호가 나타나 장치 잠금이나 다른 문제를 일으킬 수 있습니다.
M2가 auto-closing이면 D4 접근이나 M1의 `select`에 포함된 I2C 전송이 M2를 너무 일찍 닫을 수 있어 특히 문제입니다. 다만 M2가 무간섭을 가정하지 않고 auto-closing도 아니라면 이 토폴로지도 사용할 수 있습니다.
기본적으로 피해야 하는 중첩 조합입니다.
부모·자식 잠금 방식과 auto-close 가정을 함께 확인합니다.
Complex Examples
================
Parent-locked mux as parent of parent-locked mux
------------------------------------------------
This is a useful topology, but it can be bad::
.----------. .----------. .--------.
.--------. | parent- |-----| parent- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When any device is accessed, all other devices are locked out for
the full duration of the operation (both muxes lock their parent,
and specifically when M2 requests its parent to lock, M1 passes
the buck to the root adapter).
This topology is bad if M2 is an auto-closing mux and M1->select
issues any unlocked I2C transfers on the root adapter that may leak
through and be seen by the M2 adapter, thus closing M2 prematurely.
Mux-locked mux as parent of mux-locked mux
------------------------------------------
This is a good topology::
.----------. .----------. .--------.
.--------. | mux- |-----| mux- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When device D1 is accessed, accesses to D2 are locked out for the
full duration of the operation (muxes on the top child adapter of M1
are locked). But accesses to D3 and D4 are possibly interleaved at
any point.
Accesses to D3 locks out D1 and D2, but accesses to D4 are still possibly
interleaved.
Mux-locked mux as parent of parent-locked mux
---------------------------------------------
This is probably a bad topology::
.----------. .----------. .--------.
.--------. | mux- |-----| parent- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When device D1 is accessed, accesses to D2 and D3 are locked out
for the full duration of the operation (M1 locks child muxes on the
root adapter). But accesses to D4 are possibly interleaved at any
point.
This kind of topology is generally not suitable and should probably
be avoided. The reason is that M2 probably assumes that there will
be no I2C transfers during its calls to ->select and ->deselect, and
if there are, any such transfers might appear on the slave side of M2
as partial I2C transfers, i.e. garbage or worse. This might cause
device lockups and/or other problems.
The topology is especially troublesome if M2 is an auto-closing
mux. In that case, any interleaved accesses to D4 might close M2
prematurely, as might any I2C transfers part of M1->select.
But if M2 is not making the above stated assumption, and if M2 is not
auto-closing, the topology is fine.
중첩·형제 mux의 안전한 조합
274-370parent-locked M1 아래에 mux-locked M2를 두는 것은 좋은 구성입니다. D1 접근 중 M1의 최상위 자식 어댑터에 있는 mux들이 잠기므로 D2는 전체 기간 차단되지만 D3와 D4는 mux-locked 방식의 예상대로 어느 시점에도 끼어들 수 있습니다.
D3이나 D4에 접근할 때는 그 밖의 모든 장치가 차단됩니다. D3 접근에서는 M1이 루트 어댑터를 잠그고, D4 접근에서는 루트 어댑터가 직접 잠깁니다.
부모의 강한 잠금과 자식의 국소 잠금이 양립하는 좋은 구성입니다.
mux-locked 형제 mux M1과 M2가 루트에 함께 연결된 구성도 좋습니다. M1 뒤 D1에 접근하면 같은 M1의 D2뿐 아니라 형제 mux M2 뒤 D3과 D4도 차단되지만, 루트에 직접 연결된 D5는 언제든 끼어들 수 있습니다.
형제 mux들은 함께 잠기지만 루트 직접 장치는 열려 있습니다.
parent-locked 형제 mux M1과 M2가 루트에 연결된 구성도 좋습니다. 어떤 장치에 접근하더라도 부모 루트 어댑터가 잠기므로 다른 모든 장치 접근이 차단됩니다.
어느 가지에 접근해도 루트 전체가 잠깁니다.
mux-locked M1과 parent-locked M2가 형제로 루트에 연결된 혼합 구성도 좋습니다. M1 뒤 D1이나 D2에 접근하면 M2 뒤 D3과 D4는 차단되지만 루트 직결 D5는 끼어들 수 있습니다.
반대로 parent-locked M2 뒤 D3이나 D4에 접근하면 다른 모든 장치가 차단됩니다.
접근하는 가지의 잠금 방식에 따라 차단 범위가 달라집니다.
원문이 제시한 중첩·형제 조합의 평가입니다.
자식에서 시작한 잠금 요청이 mux 종류에 따라 루트까지 전파됩니다.
Parent-locked mux as parent of mux-locked mux
---------------------------------------------
This is a good topology::
.----------. .----------. .--------.
.--------. | parent- |-----| mux- |-----| dev D1 |
| root |--+--| locked | | locked | '--------'
'--------' | | mux M1 |--. | mux M2 |--. .--------.
| '----------' | '----------' '--| dev D2 |
| .--------. | .--------. '--------'
'--| dev D4 | '--| dev D3 |
'--------' '--------'
When D1 is accessed, accesses to D2 are locked out for the full
duration of the operation (muxes on the top child adapter of M1
are locked). Accesses to D3 and D4 are possibly interleaved at
any point, just as is expected for mux-locked muxes.
When D3 or D4 are accessed, everything else is locked out. For D3
accesses, M1 locks the root adapter. For D4 accesses, the root
adapter is locked directly.
Two mux-locked sibling muxes
----------------------------
This is a good topology::
.--------.
.----------. .--| dev D1 |
| mux- |--' '--------'
.--| locked | .--------.
| | mux M1 |-----| dev D2 |
| '----------' '--------'
| .----------. .--------.
.--------. | | mux- |-----| dev D3 |
| root |--+--| locked | '--------'
'--------' | | mux M2 |--. .--------.
| '----------' '--| dev D4 |
| .--------. '--------'
'--| dev D5 |
'--------'
When D1 is accessed, accesses to D2, D3 and D4 are locked out. But
accesses to D5 may be interleaved at any time.
Two parent-locked sibling muxes
-------------------------------
This is a good topology::
.--------.
.----------. .--| dev D1 |
| parent- |--' '--------'
.--| locked | .--------.
| | mux M1 |-----| dev D2 |
| '----------' '--------'
| .----------. .--------.
.--------. | | parent- |-----| dev D3 |
| root |--+--| locked | '--------'
'--------' | | mux M2 |--. .--------.
| '----------' '--| dev D4 |
| .--------. '--------'
'--| dev D5 |
'--------'
When any device is accessed, accesses to all other devices are locked
out.
Mux-locked and parent-locked sibling muxes
------------------------------------------
This is a good topology::
.--------.
.----------. .--| dev D1 |
| mux- |--' '--------'
.--| locked | .--------.
| | mux M1 |-----| dev D2 |
| '----------' '--------'
| .----------. .--------.
.--------. | | parent- |-----| dev D3 |
| root |--+--| locked | '--------'
'--------' | | mux M2 |--. .--------.
| '----------' '--| dev D4 |
| .--------. '--------'
'--| dev D5 |
'--------'
When D1 or D2 are accessed, accesses to D3 and D4 are locked out while
accesses to D5 may interleave. When D3 or D4 are accessed, accesses to
all other devices are locked out.
기존 드라이버의 mux 잠금 유형
371-412장치가 mux-locked인지 parent-locked인지는 구현에 따라 달라집니다. 다음 목록은 문서 작성 당시의 상태입니다.
I2C mux·arbitrator 드라이버의 잠금 방식을 보존합니다.
IIO의 mux 제공 드라이버입니다.
미디어 하위 시스템의 mux 제공 드라이버입니다.
드라이버 구현의 실제 잠금 유형을 기준으로 조합을 평가합니다.
Mux type of existing device drivers
===================================
Whether a device is mux-locked or parent-locked depends on its
implementation. The following list was correct at the time of writing:
In drivers/i2c/muxes/:
====================== =============================================
i2c-arb-gpio-challenge Parent-locked
i2c-mux-gpio Normally parent-locked, mux-locked iff
all involved gpio pins are controlled by the
same I2C root adapter that they mux.
i2c-mux-gpmux Normally parent-locked, mux-locked iff
specified in device-tree.
i2c-mux-ltc4306 Mux-locked
i2c-mux-mlxcpld Parent-locked
i2c-mux-pca9541 Parent-locked
i2c-mux-pca954x Parent-locked
i2c-mux-pinctrl Normally parent-locked, mux-locked iff
all involved pinctrl devices are controlled
by the same I2C root adapter that they mux.
i2c-mux-reg Parent-locked
====================== =============================================
In drivers/iio/:
====================== =============================================
gyro/mpu3050 Mux-locked
imu/inv_mpu6050/ Mux-locked
====================== =============================================
In drivers/media/:
======================= =============================================
dvb-frontends/lgdt3306a Mux-locked
dvb-frontends/m88ds3103 Parent-locked
dvb-frontends/rtl2830 Parent-locked
dvb-frontends/rtl2832 Mux-locked
dvb-frontends/si2168 Mux-locked
usb/cx231xx/ Parent-locked
======================= =============================================
요약·해설
i2c-topology.rst:1-412복잡한 I2C 토폴로지의 안전성은 select-transfer-deselect 동안 부모의 어느 범위를 잠그는지와 내부 I2C 전송이 잠금 있는 API인지 여부에 달려 있습니다. 중첩 mux의 auto-close와 무간섭 가정도 함께 검토해야 합니다.
원문 분량과 핵심 검토 대상을 요약합니다.
문서의 주요 판단 또는 탐색 순서를 압축합니다.