Bootstrap

spi_async 与spi_sync区别

spi_async 与spi_sync区别

spi_async 异步:使用spi_async()函数,它也可以用于原子上下文
static struct spi_transfer t;
static struct spi_message m;
static unsigned char buf[4];
spi_message_init(&m);
spi_message_add_tail(&t, &m);
status = spi_async(spi, &m);
进行异步的spi读写操作,由于是异步操作,因此该调用返回时, spi读写操作不一定完成,因此
往该调用传的参数所指的地址空间必须是局部静态变量或全局变量,以防止函数返回时将传给
spi_async的地址空间释放掉。 spi_async函数的原型为int spi_async(struct spi_device *spi,
struct spi_message *message),则在这里变量m和t都必须为静态变量,并且t中所指的buf也必
须是静态的
spi_sync 同步:使用 spi_sync函数,它可能处于睡眠状态,不用在中断上下文中,借助完成量机制,完成spi的同步通信操作(主要借助完成量的complete、wait_for_completion这两个接口,休眠不能用在中断上下文,中断或原子上下文可以用try_wait_for_completion()和completion_done()都可以在IRQ或原子上下文中安全调用)

1、 spi_sync调__spi_sync

static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{
<....>
	if (ctlr->transfer == spi_queued_transfer) {
	//新内核走这里
		spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
		trace_spi_message_submit(message);
		status = __spi_queued_transfer(spi, message, false);
		/****这里的参数是false,不调__spi_pump_messages处理数据,在下面处理数据的收发****/
		spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
	} else {
	//老内核走这里
		status = spi_async_locked(spi, message);
		/****这个函数也是调__spi_queued_transfer(spi, message, true);这里是true,会调用__spi_pump_messages处理数据收发****/
	}
	if (status == 0) {
		if (ctlr->transfer == spi_queued_transfer) {
			SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics,
						       spi_sync_immediate);
			SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
						       spi_sync_immediate);
			__spi_pump_messages(ctlr, false); //新内核这里收发数据
		}
		wait_for_completion(&done);//等待完成量,会休眠,不能用在中断和原子上下文
		status = message->status;
	}
	message->context = NULL;
	return status;
}
//这里初始化transfer和transfer_one_message 
static int spi_controller_initialize_queue(struct spi_controller *ctlr)
{
	int ret;
	ctlr->transfer = spi_queued_transfer;
	if (!ctlr->transfer_one_message)
		ctlr->transfer_one_message = spi_transfer_one_message;
}

static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
{
	return __spi_queued_transfer(spi, msg, true);
}
__spi_queued_transfer这里会判断need_pump,true将ctlr->pump_messages任务加入工作线程
static int __spi_queued_transfer(struct spi_device *spi, struct spi_message *msg, bool need_pump)
{
	if (!ctlr->busy && need_pump)
		kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);//异步的时候这里只是加入工作队列,并没有完成传输,
	return 0;
}
static int spi_transfer_one_message(struct spi_controller *ctlr,
				    struct spi_message *msg)
{
	spi_finalize_current_message(ctlr);//这里释放完成量

	return ret;
}

老方法

int spi_async_locked(struct spi_device *spi, struct spi_message *message)
{
struct spi_controller *ctlr = spi->controller;
int ret;
unsigned long flags;
ret = __spi_validate(spi, message);
if (ret != 0)
return ret;
spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
ret = __spi_async(spi, message);
spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
return ret;
}
__spi_queued_transfer(spi, msg, true)这里是true

__spi_sync—>spi_async_locked–>__spi_async(spi, message)–>ctlr->transfer(spi, message)–>spi_queued_transfer–>__spi_queued_transfer(spi, msg, true)–>kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages)–>spi_pump_messages–>__spi_pump_messages(ctlr, true)–>ctlr->transfer_one_message(ctlr, ctlr->cur_msg)–>ctlr->transfer_one(ctlr, msg->spi, xfer)–>spi控制器驱动中实现的函数struct spi_master *master;master->transfer_one

新方法

__spi_queued_transfer(spi, msg, false)这里是false,不会将ctlr->pump_messages任务加入工作线程

__spi_sync—>__spi_queued_transfer(spi, msg, false);
这里直接调__spi_pump_messages函数收发数据
__spi_pump_messages(ctlr, false)–>ctlr->transfer_one_message(ctlr, ctlr->cur_msg)–>ctlr->transfer_one(ctlr, msg->spi, xfer)–>spi控制器驱动中实现的函数struct spi_master *master;master->transfer_one

2、spi_async 调__spi_async

和前面分析的spi_async_locked流程一样,只有自旋锁,没有完成量,不会休眠,可以用在中断和原子上下文

int spi_async(struct spi_device *spi, struct spi_message *message)
{
	struct spi_controller *ctlr = spi->controller;
	int ret;
	unsigned long flags;
	ret = __spi_validate(spi, message);
	if (ret != 0)
		return ret;
	spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
	if (ctlr->bus_lock_flag)
		ret = -EBUSY;
	else
		ret = __spi_async(spi, message);
	spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
	return ret;
}

;