SPI 子系统 对比 操作系统
SPI 子系统 ↔ 操作系统用户态进程的 IO 请求和 SPI 设备驱动的数据传输请求在抽象层面面对的是同一个问题如何协调多个请求者公平高效地访问一份共享资源。下面从几个维度逐条对比。1. 调度操作系统 CPU 只有一个多个进程想用 → 调度器CFS/O(1)决定下一个谁跑 SPI 子系统 SPI 总线只有一条多个 message 想发 → 消息泵spi_pump_messages决定下一个谁传OS 的调度器从 runqueue 里挑进程SPI 的消息泵从master-queue里挑 message。代码里对应// spi.c:1428staticint__spi_queued_transfer(structspi_device*spi,structspi_message*msg){list_add_tail(msg-queue,master-queue);// 入队kthread_queue_work(master-kworker,master-pump_messages);// 唤醒调度}注释也很有意思——仲裁算法未指定但核心就是 FIFOThe master’s main job is to process its message queueIf there are multiple spi_device children, the i/o queue arbitration algorithm is unspecified2. 同步与异步 IO操作系统 read() 可阻塞同步→ 进程睡眠等数据 或 aio_read/epoll异步→ 回调通知 SPI 子系统 spi_sync() → completion 等待唤醒 spi_async() → complete 回调通知// 同步路径 → 类似阻塞 read()spi_sync(spi,msg){msg.completespi_complete;// 内部 completionmsg.contextdone;spi_async(spi,msg);// 入队wait_for_completion(done);// 睡下去等returnmsg.status;}// 异步路径 → 类似 aio_readmsg.completemy_callback;msg.contextmy_data;spi_async(spi,msg);// 入队就返回完成后调 my_callback同步路径就像调read()时进程被 blocking异步路径就像投递一个 AIO 请求。3. 中断与下半部操作系统 硬件中断 → 中断处理程序上半个→ 软中断/tasklet/workqueue下半个 上半个快进快出下半个做重活 SPI 子系统 控制器 FIFO 中断 → 中断处理器逐字节搬运→ spi_finalize_current_message唤醒等待者 类似地上半搬运数据下半唤醒上层以spi-imx为例的中断处理模式// 中断上半部抄 FIFOstaticirqreturn_tspi_imx_isr(intirq,void*dev_id){// 从 FIFO 读一个字节到 rx_buf// 或往 FIFO 写一个字节从 tx_buf// 如果传输完成 → spi_finalize_current_transfer}4. 锁机制操作系统 自旋锁短临界区中断上下文可用 互斥锁长临界区可睡眠 SPI 子系统 queue_lock自旋锁→ 保护 message 入队中断中可用 io_mutex互斥锁→ 保护对控制器的长操作同一段代码中两种锁共存structspi_master{spinlock_tqueue_lock;// 自旋锁 → 入队操作structmutexio_mutex;// 互斥锁 → 总线访问spinlock_tbus_lock_spinlock;structmutexbus_lock_mutex;// 互斥锁 → 总线锁定};5. 优先级操作系统 nice 值 / RT 优先级SCHED_FIFO 高优先级进程抢占低优先级 SPI 子系统 master-rt 标志 → 消息泵线程 SCHED_FIFO MAX_RT_PRIO-1 → 接近硬实时优先级// spi.c:1268if(master-rt){sched_setscheduler(master-kworker_task,SCHED_FIFO,param);// param.sched_priority MAX_RT_PRIO - 1 ≈ 98Linux 默认 RT 最高 99}如果某个 SPI 设备对延迟敏感比如音频编解码器controller 驱动设master-rt true消息泵线程就获得了接近实时的调度优先级。6. 内存管理操作系统 malloc/freemmap DMA 区域映射 SPI 子系统 spi_alloc_master / spi_master_put spi_map_msg / spi_unmap_msgDMA 映射全局buf就像一个小型内核缓冲区池——给短传输节省一次 kmallocstaticu8*buf;// spi_init 中一次分配spi_write_then_read 复用bufkmalloc(SPI_BUFSIZ,GFP_KERNEL);7. 设备即文件操作系统 open() → write() → close() 所有东西都是文件 SPI 子系统 spidev → open → ioctl(SPI_IOC_MESSAGE) → close SPI 设备通过 spidev 变成了 /dev/spidev0.0staticconststructfile_operationsspidev_fops{.ownerTHIS_MODULE,.unlocked_ioctlspidev_ioctl,.openspidev_open,.releasespidev_release,};一张表收尾维度操作系统SPI 子系统资源CPUSPI 总线请求进程spi_message调度器CFS / SCHED_FIFOspi_pump_messages kthread同步 IOblocking read/writespi_sync completion异步 IOaio / epollspi_async complete 回调中断处理上半部 下半部ISR spi_finalize_current_message锁spinlock / mutexqueue_lock / io_mutex优先级nice / RTmaster-rt → SCHED_FIFO内存管理kmalloc / vmallocspi_alloc_master / spi_map_msg用户态接口系统调用spidev ioctlSPI 子系统就是一个针对单条 SPI 总线做了极简设计的微型操作系统——它有调度器消息泵、同步/异步 IO 模型、中断驱动、多种锁机制、甚至支持实时优先级。只不过它不管理 CPU 时间片而管理 spi_message 在总线上的传输顺序。