1. 程式人生 > 其它 >I2C mux和複雜拓撲

I2C mux和複雜拓撲

構建更復雜的I2C拓撲,而不是帶有一個介面卡和一個或多個裝置的直觀的I2C匯流排,有幾個原因。

  1. 在總線上可能需要一個多路交換器來防止地址衝突。
  2. 匯流排可能可以從一些外部匯流排主機訪問,並且可能需要仲裁來確定是否可以訪問匯流排。
  3. 一個裝置(特別是射頻調諧器)可能想要避免來自I2C匯流排的數字噪聲,至少在大多數時間,並且位於一個門的後面,在裝置可以訪問之前必須操作這個門。

Etc

Linux將這些結構表示為I2C介面卡樹,其中每個介面卡都有一個父介面卡(根介面卡除外)和零個或多個子介面卡。根介面卡是發出I2C傳輸的實際介面卡,具有父級的所有介面卡都是“I2C -mux”物件(引用,因為它也可以是仲裁器或門)的一部分。

根據特定的mux驅動程式,當它的子介面卡上有I2C傳輸時,會發生一些事情。mux驅動程式顯然可以操作一個mux,但它也可以與外部匯流排主機進行仲裁或開啟門。mux驅動程式有兩種操作,select 和 deselect。在傳輸之前呼叫select,而(可選的)deselect在傳輸之後呼叫。

Locking

I2C mux有兩種鎖定方式,它們可以是mux-locked 或 parent-locked鎖。從下面可以明顯看出,知道一個mux是mux-locked鎖還是parent-locked鎖是很有用的。以下列表在撰寫本文時是正確的:

在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

在drivers/iio/下:

gyro/mpu3050

Mux-locked

imu/inv_mpu6050/

Mux-locked

在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

Mux-locked muxes

在完全select-transfer-deselect事務期間,mux鎖定的mux不會鎖定整個父介面卡,只有父介面卡上的mux被鎖定。如果select和/或deselect操作必須使用I2C傳輸來完成它們的任務,Mux-locked muxes是最有趣的。由於父介面卡在整個事務期間沒有完全鎖定,不相關的I2C傳輸可能會交叉事務的不同階段。:這樣做的好處是mux驅動程式可能更容易、更清晰地實現,但也有一些注意事項。

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 intension 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.

Mux-locked Example

               .----------.     .--------.
.--------.     |   mux-   |-----| dev D1 |
|  root  |--+--|  locked  |     '--------'
'--------'  |  |  mux M1  |--.  .--------.
            |  '----------'  '--| dev D2 |
            |  .--------.       '--------'
            '--| dev D3 |
               '--------'

當訪問D1時,會發生如下情況:

  1. 有人向D1發出I2C傳輸
  2. M1在其父(本例中的根介面卡)上鎖定mux。
  3. M1呼叫 ->select 準備mux。
  4. M1(大概)做一些I2C傳輸作為它選擇的一部分。這些傳輸是鎖定父介面卡的普通I2C傳輸。
  5. M1將第1步的I2C傳輸作為鎖定父介面卡的普通I2C傳輸提供給其父介面卡
  6. M1呼叫 ->deselect ,如果它有一個的話。
  7. 規則與步驟4相同,但是對於 ->deselect。
  8. M1解鎖其父結點的mux。

這意味著對D2的訪問在整個操作期間都被鎖定。但是對D3的訪問可能在任何點都是交錯的。

Parent-locked muxes

parent -locked muxes在整個select- transfer-deselect事務期間鎖定父介面卡。這意味著mux驅動程式必須確保在事務期間通過父介面卡的任何和所有I2C傳輸都是未鎖定的I2C傳輸(例如__i2c_transfer),否則就會出現死鎖。有幾點需要注意。

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.

Parent-locked Example

               .----------.     .--------.
.--------.     |  parent- |-----| dev D1 |
|  root  |--+--|  locked  |     '--------'
'--------'  |  |  mux M1  |--.  .--------.
            |  '----------'  '--| dev D2 |
            |  .--------.       '--------'
            '--| dev D3 |
               '--------'

當訪問D1時,會發生如下情況:

  1. 有人向D1發出I2C傳輸
  2. M1在其父(本例中的根介面卡)上鎖定mux。
  3. M1鎖定它的父介面卡。
  4. M1呼叫 ->select 準備mux。
  5. 如果M1將任何I2C傳輸(在這個根介面卡上)作為其選擇的一部分,那麼這些傳輸必須是未鎖定的I2C傳輸,以便它們不會死鎖根介面卡。
  6. M1將第1步到根介面卡的I2C傳輸作為未鎖定的I2C傳輸提供,這樣它就不會死鎖父介面卡。
  7. M1呼叫 ->deselect ,如果它有一個的話。
  8. 規則與第5步相同,但是對於 ->deselect。
  9. M1解鎖它的父介面卡。
  10. M1解鎖其父結點的mux。

這意味著在整個操作期間,D2和D3的訪問都是被鎖定的。

Complex Examples

Parent-locked mux as parent of parent-locked mux

這是一個有用的拓撲,但也可能是糟糕的:

               .----------.     .----------.     .--------.
.--------.     |  parent- |-----|  parent- |-----| dev D1 |
|  root  |--+--|  locked  |     |  locked  |     '--------'
'--------'  |  |  mux M1  |--.  |  mux M2  |--.  .--------.
            |  '----------'  |  '----------'  '--| dev D2 |
            |  .--------.    |  .--------.       '--------'
            '--| dev D4 |    '--| dev D3 |
               '--------'       '--------'

當任何裝置被訪問時,所有其他裝置在整個操作期間都被鎖定(mux鎖定它們的父裝置,特別是當M2請求其父裝置鎖定時,M1將責任傳遞給根介面卡)。

如果M2是一個自動關閉的mux,而 M1->select 在根介面卡上發出任何可能洩漏並被M2介面卡看到的未解鎖的I2C傳輸,從而過早關閉M2,那麼這種拓撲就很糟糕。

Mux-locked mux as parent of mux-locked mux

這是一個很好的拓撲:

               .----------.     .----------.     .--------.
.--------.     |   mux-   |-----|   mux-   |-----| dev D1 |
|  root  |--+--|  locked  |     |  locked  |     '--------'
'--------'  |  |  mux M1  |--.  |  mux M2  |--.  .--------.
            |  '----------'  |  '----------'  '--| dev D2 |
            |  .--------.    |  .--------.       '--------'
            '--| dev D4 |    '--| dev D3 |
               '--------'       '--------'

當裝置D1被訪問時,D2的訪問在整個操作期間都被鎖定(M1的頂部子介面卡的mux被鎖定)。但是對D3和D4的訪問可能在任何一點都是交錯的。對D3的訪問鎖定D1和D2,但對D4的訪問仍然可能是交錯的。

Mux-locked mux as parent of parent-locked mux

這可能是一個糟糕的拓撲:

               .----------.     .----------.     .--------.
.--------.     |   mux-   |-----|  parent- |-----| dev D1 |
|  root  |--+--|  locked  |     |  locked  |     '--------'
'--------'  |  |  mux M1  |--.  |  mux M2  |--.  .--------.
            |  '----------'  |  '----------'  '--| dev D2 |
            |  .--------.    |  .--------.       '--------'
            '--| dev D4 |    '--| dev D3 |
               '--------'       '--------'

當裝置D1被訪問時,D2和D3的訪問在整個操作期間都被鎖定(M1鎖定根介面卡上的子mux)。但是對D4的訪問可能在任何一點都是交錯的。

這種拓撲通常是不合適的,應該避免。原因是M2可能假設在它呼叫 ->select 和 ->deselect 的過程中不會有I2C傳輸,如果有的話,任何這樣的傳輸可能會出現在M2的從端作為部分I2C傳輸,即垃圾或更糟。這可能會導致裝置鎖定和/或其他問題。

如果M2是一個自動關閉的mux,那麼這種拓撲結構尤其麻煩。在這種情況下,對D4的任何交錯訪問都可能過早地關閉M2,就像 M1->select 的任何I2C傳輸部分一樣。

但是如果M2沒有做出上述假設,並且M2不是自動關閉的,那麼拓撲是好的。

Parent-locked mux as parent of mux-locked mux

這是一個很好的拓撲:

               .----------.     .----------.     .--------.
.--------.     |  parent- |-----|   mux-   |-----| dev D1 |
|  root  |--+--|  locked  |     |  locked  |     '--------'
'--------'  |  |  mux M1  |--.  |  mux M2  |--.  .--------.
            |  '----------'  |  '----------'  '--| dev D2 |
            |  .--------.    |  .--------.       '--------'
            '--| dev D4 |    '--| dev D3 |
               '--------'       '--------'

當D1被訪問時,D2的訪問在整個操作期間都被鎖定(M1的頂層子介面卡上的mux被鎖定)。D3和D4的訪問可能在任何點交錯,就像預期的mux-locked mux。

當D3或D4被訪問時,其他所有內容都被鎖定。對於D3訪問,M1鎖定根介面卡。對於D4訪問,根介面卡是直接鎖定的。

Two mux-locked sibling muxes

這是一個很好的拓撲:

                                .--------.
               .----------.  .--| dev D1 |
               |   mux-   |--'  '--------'
            .--|  locked  |     .--------.
            |  |  mux M1  |-----| dev D2 |
            |  '----------'     '--------'
            |  .----------.     .--------.
.--------.  |  |   mux-   |-----| dev D3 |
|  root  |--+--|  locked  |     '--------'
'--------'  |  |  mux M2  |--.  .--------.
            |  '----------'  '--| dev D4 |
            |  .--------.       '--------'
            '--| dev D5 |
               '--------'

當D1被訪問時,D2、D3和D4的訪問被鎖定。但是對D5的訪問可以在任何時候交錯。

Two parent-locked sibling muxes

這是一個很好的拓撲:

                                .--------.
               .----------.  .--| dev D1 |
               |  parent- |--'  '--------'
            .--|  locked  |     .--------.
            |  |  mux M1  |-----| dev D2 |
            |  '----------'     '--------'
            |  .----------.     .--------.
.--------.  |  |  parent- |-----| dev D3 |
|  root  |--+--|  locked  |     '--------'
'--------'  |  |  mux M2  |--.  .--------.
            |  '----------'  '--| dev D4 |
            |  .--------.       '--------'
            '--| dev D5 |
               '--------'

當訪問任何裝置時,對其他裝置的訪問將被鎖定。

Mux-locked and parent-locked sibling muxes

這是一個很好的拓撲:

                                .--------.
               .----------.  .--| dev D1 |
               |   mux-   |--'  '--------'
            .--|  locked  |     .--------.
            |  |  mux M1  |-----| dev D2 |
            |  '----------'     '--------'
            |  .----------.     .--------.
.--------.  |  |  parent- |-----| dev D3 |
|  root  |--+--|  locked  |     '--------'
'--------'  |  |  mux M2  |--.  .--------.
            |  '----------'  '--| dev D4 |
            |  .--------.       '--------'
            '--| dev D5 |
               '--------'

當D1或D2被訪問時,對D3和D4的訪問被鎖定,而對D5的訪問可能會交錯。當D3或D4被訪問時,對所有其他裝置的訪問被鎖定。

本文來自部落格園,作者:王樓小子,轉載請註明原文連結:https://www.cnblogs.com/wanglouxiaozi/p/15149412.html