L
做光模块评估板或交换机板卡时,常常要在嵌入式 Linux 里读模块的管理寄存器,确认厂商信息、温度、Tx/Rx 功率和告警。SFP+ 多用 SFF-8472,QSFP-DD / OSFP 则是 CMIS。底层几乎都是 I2C,地址一般是 0x50(有的实现还会看到 0x51)。
我们这边比较稳的读法是:
1. 确认总线。很多板子会用 PCA954x 一类的 I2C mux,模块不在 i2c-0 上,而在某个下游总线。先看 `/sys/bus/i2c/devices/`,或用 `i2cdetect -l` 把通道对上丝印。
2. 打开对应的 `/dev/i2c-N`,用 `I2C_SLAVE` 设成 0x50。注意有的内核会把 7-bit 地址和 8-bit 地址搞混,应用层统一按 7-bit 0x50 来。
3. CMIS 的页选择在 byte 127(0x7F)。先写页号,再读该页的数据。连续读的时候不要假设页不会被别人改掉,尤其是同时有 BMC 或 SDK 也在访问同一只模块。
4. 校验和按规范对指定区间求和取低 8 位。读到的 vendor name、PN 如果乱码,优先怀疑读错页,其次才是校验。
5. 时钟拉伸和 NAK。热插拔瞬间模块可能 NAK,重试要比直接报错更接近真实现场。有的模块在写页后需要几个毫秒再读。
常见坑:把 Lower Memory 和 Upper Page 的偏移弄混;在 mux 未切到该通道时读到全 0xFF 却当成模块不在位;以及用 `i2cget` 单字节读大数据块,既慢又容易和页切换打架。批量读用 `I2C_RDWR` 一次读完当前页会稳很多。
如果有人在 ARM Linux 上用过 netlink / 自己的 CMIS 库,或者踩过 QSFP-DD 和 SFP28 混插时地址映射不一致的问题,欢迎补充。
我们这边比较稳的读法是:
1. 确认总线。很多板子会用 PCA954x 一类的 I2C mux,模块不在 i2c-0 上,而在某个下游总线。先看 `/sys/bus/i2c/devices/`,或用 `i2cdetect -l` 把通道对上丝印。
2. 打开对应的 `/dev/i2c-N`,用 `I2C_SLAVE` 设成 0x50。注意有的内核会把 7-bit 地址和 8-bit 地址搞混,应用层统一按 7-bit 0x50 来。
3. CMIS 的页选择在 byte 127(0x7F)。先写页号,再读该页的数据。连续读的时候不要假设页不会被别人改掉,尤其是同时有 BMC 或 SDK 也在访问同一只模块。
4. 校验和按规范对指定区间求和取低 8 位。读到的 vendor name、PN 如果乱码,优先怀疑读错页,其次才是校验。
5. 时钟拉伸和 NAK。热插拔瞬间模块可能 NAK,重试要比直接报错更接近真实现场。有的模块在写页后需要几个毫秒再读。
常见坑:把 Lower Memory 和 Upper Page 的偏移弄混;在 mux 未切到该通道时读到全 0xFF 却当成模块不在位;以及用 `i2cget` 单字节读大数据块,既慢又容易和页切换打架。批量读用 `I2C_RDWR` 一次读完当前页会稳很多。
如果有人在 ARM Linux 上用过 netlink / 自己的 CMIS 库,或者踩过 QSFP-DD 和 SFP28 混插时地址映射不一致的问题,欢迎补充。
