基于trace的正点原子imx6ull开发板linux内核spi驱动调用关系分析

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

学习linux内核spi驱动,发现结构体中函数指针指来指去让人很绕,总是找不到调用函数,网上看到有大佬分享linux下trace可查看函数调用关系,故总结此文章,通过trace工具分析spi_sync()和spi_async()的调用过程。
spi驱动主要涉及文件如下:
spi-imx.c
spi-bitbang.c
spidev.c


一、linux下trace功能开启

1.1menuconfig操作

进入linux下menuconfig,tracers配置如下图所示:
在这里插入图片描述
配置完tracers后,debug filesystem是默认开启的,但是最好也检查一下,配置界面如下:
在这里插入图片描述

1.2编译内核

编译内核和设备树。

make

将新编译的内核和根文件系统添加入tftpboot目录下,重启正点原子IMX6ULL开发板。


二、trace使用步骤

2.1spi_sync同步模式调用关系查询

2.1.1spi驱动加载

spi驱动加载参考《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6.pdf》下第62章节。
正点原子的spi驱动是使用的同步模式,调用的spi_sync()函数,具体代码如下:

static s32 icm20608_write_regs(struct icm20608_dev *dev, u8 reg, u8 *buf, u8 len)
{
	int ret = -1;
	unsigned char *txdata;
	struct spi_message m;
	struct spi_transfer *t;
	struct spi_device *spi = (struct spi_device *)dev->private_data;
		
	t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);	/* 申请内存 */
	if(!t) {
		return -ENOMEM;
	}
		
	txdata = kzalloc(sizeof(char)+len, GFP_KERNEL);
	if(!txdata) {
		goto out1;
	}	
	
	/* 一共发送len+1个字节的数据,第一个字节为
	寄存器首地址,len为要写入的寄存器的集合,*/
	*txdata = reg & ~0x80;	/* 写数据的时候首寄存器地址bit8要清零 */
    memcpy(txdata+1, buf, len);	/* 把len个寄存器拷贝到txdata里,等待发送 */
	t->tx_buf = txdata;			/* 要发送的数据 */
	t->len = len+1;				/* t->len=发送的长度+读取的长度 */
	spi_message_init(&m);		/* 初始化spi_message */
	spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */
	ret = spi_sync(spi, &m);	/* 同步发送 */
    if(ret) {
        goto out2;
    }
out2:
	kfree(txdata);				/* 释放内存 */
out1:
	kfree(t);					/* 释放内存 */
	return ret;
}

我们在板子串口输入如下命令加载驱动:

depmod //第一次加载驱动的时候需要运行此命令
modprobe icm20608.ko //加载驱动模块

2.1.2trace调用函数追踪

我们在板子串口输入如下命令:

mount -t debugfs none /sys/kernel/debug/
cd /sys/kernel/debug/tracing/
echo 0 > tracing_on
echo function_graph > current_tracer
//同步模式查询
echo spi_sync > set_graph_function
echo *spi* > set_ftrace_filter
echo *dma* >> set_ftrace_filter
echo *spin* >> set_ftrace_notrace
echo 1 > tracing_on
/lib/modules/4.1.15/icm20608App /dev/icm20608 
echo 0 > tracing_on
cat trace

注意:
echo dma >> set_ftrace_filter 的>>表示在此文件中append添加,如果是>则是覆盖。

2.1.3spi_sync调用关系

trace中打印如下:

0)               |  spi_sync() {
 0)               |    __spi_sync() {
 0)   2.667 us    |      __spi_validate();
 0)   1.667 us    |      __spi_queued_transfer();
 0)               |      __spi_pump_messages() {
 0)   1.667 us    |        spi_bitbang_prepare_hardware();
 0) + 11.667 us   |        spi_imx_prepare_message();
 0)   1.333 us    |        spi_imx_can_dma();
 0)               |        spi_bitbang_transfer_one() {
 0)               |          spi_imx_setupxfer() {
 0)   4.000 us    |            mx51_ecspi_config();
 0) + 11.000 us   |          }
 0)   5.000 us    |          spi_imx_chipselect();
 0)               |          spi_imx_transfer() {
 0)               |            spi_imx_push() {
 0)   1.000 us    |              spi_imx_buf_tx_u8();
 0)   1.000 us    |              spi_imx_buf_tx_u8();
 0)   1.000 us    |              spi_imx_buf_tx_u8();
 0)   0.667 us    |              spi_imx_buf_tx_u8();
 0)   0.667 us    |              spi_imx_buf_tx_u8();
 0)   1.000 us    |              spi_imx_buf_tx_u8();
 0)   1.000 us    |              spi_imx_buf_tx_u8();
 0)   1.000 us    |              spi_imx_buf_tx_u8();
 0)   0.667 us    |              spi_imx_buf_tx_u8();
 0)   0.667 us    |              spi_imx_buf_tx_u8();
 0)   1.000 us    |              spi_imx_buf_tx_u8();
 0)   0.667 us    |              spi_imx_buf_tx_u8();
 0)   1.000 us    |              spi_imx_buf_tx_u8();
 0)   1.000 us    |              spi_imx_buf_tx_u8();
 0)   1.000 us    |              spi_imx_buf_tx_u8();
 0)   1.334 us    |              mx51_ecspi_trigger();
 0) ! 106.000 us  |            }
 0)   1.333 us    |            mx51_ecspi_intctrl();
 0) ! 188.666 us  |          }
 0)   3.334 us    |          spi_imx_chipselect();
 0)               |          spi_finalize_current_message() {
 0)   0.667 us    |            spi_imx_can_dma();
 0)   7.000 us    |            spi_imx_unprepare_message();
 0)   1.667 us    |            spi_complete();
 0) + 69.000 us   |          }
 0) ! 314.667 us  |        }
 0) ! 356.334 us  |      }

这就是spi_sync()的整体调用关系,我们可根据上述函数学习spi驱动源码。

2.2spi_async异步模式调用关系查询

2.2.1spidev驱动加载

2.2.1.1源码学习

linux内核源码中spidev.c是调用的spi_async()函数,正好可以供我们分析,源码如下:

static ssize_t
spidev_sync(struct spidev_data *spidev, struct spi_message *message)
{
	DECLARE_COMPLETION_ONSTACK(done);
	int status;

	message->complete = spidev_complete;
	message->context = &done;

	spin_lock_irq(&spidev->spi_lock);
	if (spidev->spi == NULL)
		status = -ESHUTDOWN;
	else
		status = spi_async(spidev->spi, message);
	spin_unlock_irq(&spidev->spi_lock);

	if (status == 0) {
		wait_for_completion(&done);
		status = message->status;
		if (status == 0)
			status = message->actual_length;
	}
	return status;
}

如果我们想将正点原子的icm20608.c里的spi同步发送改成异步发送,可以参考上述源码进行修改。

2.2.1.2menuconfig配置

进入menuconfig下,使能spidev功能,勾选下图黄框中功能。
在这里插入图片描述

2.2.1.3修改设备树

spidev.c源码中,compatible属性为"rohm,dh2228fv",如下所示,所以我们需要修改匹配值。

static const struct of_device_id spidev_dt_ids[] = {
	{ .compatible = "rohm,dh2228fv" },
	{},
};

基于正点原子第62章节的设备树,屏蔽spidev: icm20608@0 内容,添加spidevtest: test@0内容,具体修改为如下:

&ecspi3 {
	fsl,spi-num-chipselects = <1>;
	cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_ecspi3>;
	status = "okay";

	spidevtest: test@0 {
		compatible = "rohm,dh2228fv";
		spi-max-frequency = <8000000>;
		reg = <0>;
	};

	/*spidev: icm20608@0 {
		compatible = "alientek,icm20608";
		spi-max-frequency = <8000000>;
		reg = <0>;
	};*/
};

注意,compatible = “rohm,dh2228fv”;一定要内核和设备树对应上。

2.2.1.4编译源码和设备树

编译源码和设备树,并tftpboot重启开发板。
开发板串口下,spidev显示如下,表示驱动加载成功。

/dev # ls /dev/spi*
/dev/spidev2.0
/dev # 

其中,前面的2代表的是&ecspi3(详见imx6ull.dtsi中spi2 = &ecspi3;),后面的0指代spidevtest: test@0。

/ {
	aliases {
		spi0 = &ecspi1;
		spi1 = &ecspi2;
		spi2 = &ecspi3;
		spi3 = &ecspi4;
	};

至此,我们spidev驱动配置完成。

2.2.2spi_async异步模式调用关系查询

下面的trace过程是基于修改正点原子icm20608.c源码的spi_sync为spi_async后进行的操作。
我们在板子串口输入如下命令:

mount -t debugfs none /sys/kernel/debug/
cd /sys/kernel/debug/tracing/
echo 0 > tracing_on
echo function_graph > current_tracer
//异步模式查询
echo spi_async > set_graph_function
echo *spi* > set_ftrace_filter
echo *dma* >> set_ftrace_filter
echo *spin* >> set_ftrace_notrace
echo 1 > tracing_on
/lib/modules/4.1.15/icm20608App /dev/icm20608 
echo 0 > tracing_on
cat trace

2.2.3spi_sync调用关系

trace中打印如下:

 0)               |  spi_async() {
 0)   4.000 us    |    __spi_validate();
 0)               |    __spi_async() {
 0)               |      spi_queued_transfer() {
 0) + 13.667 us   |        __spi_queued_transfer();
 0) + 20.667 us   |      }
 0) + 27.334 us   |    }
 0) ! 117.000 us  |  }

上述打印中到__spi_queued_transfer()这一层就不再显示了,如果想看中断中的信息,需要将下属两句话在配置时去掉。

echo *spi* > set_ftrace_filter
echo *dma* >> set_ftrace_filter

去除掉spin后具体调用关系如下:

 0)               |  spi_async() {
 0)   2.667 us    |    __spi_validate();
 0)   1.000 us    |    preempt_count_add();
 0)               |    __spi_async() {
 0)               |      spi_queued_transfer() {
 0)               |        __spi_queued_transfer() {
 0)   0.667 us    |          preempt_count_add();
 0)               |          queue_kthread_work() {
 0)   0.666 us    |            preempt_count_add();
 0)               |            insert_kthread_work.part.0() {
 0)               |              wake_up_process() {
 0)               |                try_to_wake_up() {
 0)   0.666 us    |                  preempt_count_add();
 0)   1.000 us    |                  task_waking_fair();
 0)               |                  select_task_rq_fair() {
 0)   0.667 us    |                    __rcu_read_lock();
 0)   0.666 us    |                    idle_cpu();
 0)   0.667 us    |                    __rcu_read_unlock();
 0) + 20.000 us   |                  }
 0)   0.666 us    |                  preempt_count_add();
 0)               |                  ttwu_do_activate.constprop.28() {
 0)               |                    activate_task() {
 0)               |                      enqueue_task() {
 0)   1.000 us    |                        update_rq_clock.part.16();
 0)               |                        enqueue_task_fair() {
 0)               |                          update_curr() {
 0)   2.334 us    |                            update_min_vruntime();
 0)   8.667 us    |                          }
 0)   1.000 us    |                          __compute_runnable_contrib();
 0)   1.000 us    |                          __update_entity_load_avg_contrib();
 0)   1.000 us    |                          __update_entity_utilization_avg_contrib();
 0)   1.000 us    |                          update_cfs_rq_blocked_load();
 0)   1.333 us    |                          __enqueue_entity();
 0)   0.667 us    |                          hrtick_update();
 0) + 56.334 us   |                        }
 0) + 68.333 us   |                      }
 0) + 73.667 us   |                    }
 0)               |                    ttwu_do_wakeup() {
 0)               |                      check_preempt_curr() {
 0)               |                        check_preempt_wakeup() {
 0)   0.667 us    |                          update_curr();
 0)   1.000 us    |                          wakeup_preempt_entity();
 0)   0.667 us    |                          resched_curr();
 0) + 19.333 us   |                        }
 0) + 26.667 us   |                      }
 0) + 33.667 us   |                    }
 0) ! 120.000 us  |                  }
 0)   0.666 us    |                  preempt_count_sub();
 0)   0.666 us    |                  preempt_count_sub();
 0) ! 183.667 us  |                }
 0) ! 189.334 us  |              }
 0) ! 195.333 us  |            }
 0)   0.667 us    |            preempt_count_sub();
 0) ! 215.000 us  |          }
 0)   0.667 us    |          preempt_count_sub();
 0) ! 235.333 us  |        }
 0) ! 240.666 us  |      }
 0) ! 246.667 us  |    }
 0)               |    preempt_count_sub() {
 0)               |      __schedule() {
 0)   0.666 us    |        preempt_count_add();
 0)               |        rcu_note_context_switch() {
 0)   0.667 us    |          rcu_sched_qs();
 0)   0.667 us    |          rcu_preempt_qs();
 0) + 12.667 us   |        }
 0)   0.667 us    |        preempt_count_add();
 0)               |        pick_next_task_fair() {
 0)               |          put_prev_task_fair() {
 0)   0.666 us    |            update_curr();
 0)   0.666 us    |            __enqueue_entity();
 0)   0.666 us    |            __compute_runnable_contrib();
 0)   1.000 us    |            __update_entity_load_avg_contrib();
 0)   0.667 us    |            __update_entity_utilization_avg_contrib();
 0) + 33.334 us   |          }
 0)   1.000 us    |          wakeup_preempt_entity();
 0)   0.667 us    |            preempt_count_sub();
 0) ! 215.000 us  |          } /* queue_kthread_work */
 0)   0.667 us    |          preempt_count_sub();
 0) ! 235.333 us  |        } /* __spi_queued_transfer */
 0) ! 240.666 us  |      } /* spi_queued_transfer */
 0) ! 246.667 us  |    } /* __spi_async */
 0)               |    preempt_count_sub() {
 0)               |      __schedule() {
 0)   0.666 us    |        preempt_count_add();
 0)               |        rcu_note_context_switch() {
 0)   0.667 us    |          rcu_sched_qs();
 0)   0.667 us    |          rcu_preempt_qs();
 0) + 12.667 us   |        }
 0)   0.667 us    |        preempt_count_add();
 0)               |        pick_next_task_fair() {
 0)               |          put_prev_task_fair() {
 0)   0.666 us    |            update_curr();
 0)   0.666 us    |            __enqueue_entity();
 0)   0.666 us    |            __compute_runnable_contrib();
 0)   1.000 us    |            __update_entity_load_avg_contrib();
 0)   0.667 us    |            __update_entity_utilization_avg_contrib();
 0) + 33.334 us   |          }
 0)   1.000 us    |          wakeup_preempt_entity();
 0)   1.000 us    |          clear_buddies();
 0)   1.333 us    |          set_next_entity();
 0) + 58.000 us   |        }
 0)               |        atomic_notifier_call_chain() {
 0)   0.667 us    |          __rcu_read_lock();
 0)               |          notifier_call_chain() {
 0)   0.667 us    |            vfp_notifier();
 0)   6.667 us    |          }
 0)   0.667 us    |          __rcu_read_unlock();
 0) + 25.667 us   |        }
 0)               |        finish_task_switch() {
 0)   ==========> |
 0)               |          gic_handle_irq() {
 0)               |            __handle_domain_irq() {
 0)               |              irq_enter() {
 0)   1.000 us    |                rcu_irq_enter();
 0)   0.667 us    |                preempt_count_add();
 0) + 12.334 us   |              }
 0)   2.333 us    |              irq_find_mapping();
 0)               |              generic_handle_irq() {
 0)               |                handle_fasteoi_irq() {
 0)   0.667 us    |                  preempt_count_add();
 0)   0.667 us    |                  irq_may_run();
 0)               |                  handle_irq_event() {
 0)   0.667 us    |                    preempt_count_sub();
 0)               |                    handle_irq_event_percpu() {
 0)               |                      spi_imx_isr() {
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   0.667 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   0.667 us    |                        mx51_ecspi_rx_available();
 0)   0.667 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        } /* mx51_ecspi_rx_available */
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   0.667 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   0.667 us    |                        mx51_ecspi_rx_available();
 0)   0.667 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   0.667 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        spi_imx_buf_rx_u8();
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        mx51_ecspi_intctrl();
 0)               |                        complete() {
 0)   1.000 us    |                          preempt_count_add();
 0)               |                          __wake_up_locked() {
 0)               |                            __wake_up_common() {
 0)               |                              default_wake_function() {
 0)               |                                try_to_wake_up() {
 0)   1.000 us    |                                  preempt_count_add();
 0)   1.000 us    |                                  task_waking_fair();
 0)               |                                  select_task_rq_fair() {
 0)   0.666 us    |                                    __rcu_read_lock();
 0)   1.000 us    |                                    idle_cpu();
 0)   0.667 us    |                                    __rcu_read_unlock();
 0) + 22.000 us   |                                  }
 0)   0.667 us    |                                  preempt_count_add();
 0)               |                                  ttwu_do_activate.constprop.28() {
 0)               |                                    activate_task() {
 0)               |                                      enqueue_task() {
 0)   1.000 us    |                                        update_rq_clock.part.16();
 0)               |                                        enqueue_task_fair() {
 0)               |                                          update_curr() {
 0)   0.666 us    |                                            update_min_vruntime();
 0)   9.334 us    |                                          }
 0)   0.667 us    |                                          update_cfs_rq_blocked_load();
 0)   1.000 us    |                                          __enqueue_entity();
 0)   0.666 us    |                                          hrtick_update();
 0) + 38.667 us   |                                        }
 0) + 54.333 us   |                                      }
 0)   1.000 us    |                        mx51_ecspi_rx_available();
 0)   1.000 us    |                        mx51_ecspi_intctrl();
 0)               |                        complete() {
 0)   1.000 us    |                          preempt_count_add();
 0)               |                          __wake_up_locked() {
 0)               |                            __wake_up_common() {
 0)               |                              default_wake_function() {
 0)               |                                try_to_wake_up() {
 0)   1.000 us    |                                  preempt_count_add();
 0)   1.000 us    |                                  task_waking_fair();
 0)               |                                  select_task_rq_fair() {
 0)   0.666 us    |                                    __rcu_read_lock();
 0)   1.000 us    |                                    idle_cpu();
 0)   0.667 us    |                                    __rcu_read_unlock();
 0) + 22.000 us   |                                  }
 0)   0.667 us    |                                  preempt_count_add();
 0)               |                                  ttwu_do_activate.constprop.28() {
 0)               |                                    activate_task() {
 0)               |                                      enqueue_task() {
 0)   1.000 us    |                                        update_rq_clock.part.16();
 0)               |                                        enqueue_task_fair() {
 0)               |                                          update_curr() {
 0)   0.666 us    |                                            update_min_vruntime();
 0)   9.334 us    |                                          }
 0)   0.667 us    |                                          update_cfs_rq_blocked_load();
 0)   1.000 us    |                                          __enqueue_entity();
 0)   0.666 us    |                                          hrtick_update();
 0) + 38.667 us   |                                        }
 0) + 54.333 us   |                                      }
 0) + 61.667 us   |                                    }
 0)               |                                    ttwu_do_wakeup() {
 0)               |                                      check_preempt_curr() {
 0)               |                                        check_preempt_wakeup() {
 0)   0.667 us    |                                          update_curr();
 0)   0.666 us    |                                          wakeup_preempt_entity();
 0)   0.667 us    |                                          resched_curr();
 0) + 23.000 us   |                                        }
 0) + 30.333 us   |                                      }
 0) + 38.000 us   |                                    }
 0) ! 112.000 us  |                                  }
 0)   0.667 us    |                                  preempt_count_sub();
 0)   0.667 us    |                                  preempt_count_sub();
 0) ! 184.667 us  |                                }
 0) ! 193.334 us  |                              }
 0) ! 199.333 us  |                            }
 0) ! 206.000 us  |                          }
 0)   0.667 us    |                          preempt_count_sub();
 0) ! 226.333 us  |                        }
 0) ! 435.334 us  |                      }
 0)               |                      add_interrupt_randomness() {
 0)               |                        read_current_timer() {
 0)   1.000 us    |                          imx_read_current_timer();
 0)   8.000 us    |                        }
 0) + 14.667 us   |                      }
 0)   0.667 us    |                      note_interrupt();
 0) ! 469.334 us  |                    }
 0)   0.667 us    |                    preempt_count_add();
 0) ! 491.333 us  |                  }
 0)               |                  irq_chip_eoi_parent() {
 0)   0.667 us    |                    gic_eoi_irq();
 0) + 12.000 us   |                  }
 0)   2.000 us    |                  preempt_count_sub();
 0) ! 193.334 us  |                              } /* default_wake_function */
 0) ! 199.333 us  |                            } /* __wake_up_common */
 0) ! 206.000 us  |                          } /* __wake_up_locked */
 0)   0.667 us    |                          preempt_count_sub();
 0) ! 226.333 us  |                        } /* complete */
 0) ! 435.334 us  |                      } /* spi_imx_isr */
 0)               |                      add_interrupt_randomness() {
 0)               |                        read_current_timer() {
 0)   1.000 us    |                          imx_read_current_timer();
 0)   8.000 us    |                        }
 0) + 14.667 us   |                      }
 0)   0.667 us    |                      note_interrupt();
 0) ! 469.334 us  |                    } /* handle_irq_event_percpu */
 0)   0.667 us    |                    preempt_count_add();
 0) ! 491.333 us  |                  } /* handle_irq_event */
 0)               |                  irq_chip_eoi_parent() {
 0)   0.667 us    |                    gic_eoi_irq();
 0) + 12.000 us   |                  }
 0)   2.000 us    |                  preempt_count_sub();
 0) ! 534.666 us  |                }
 0) ! 541.333 us  |              }
 0)               |              irq_exit() {
 0)   0.667 us    |                preempt_count_sub();
 0)   1.000 us    |                idle_cpu();
 0)   1.000 us    |                rcu_irq_exit();
 0) + 22.667 us   |              }
 0) ! 603.333 us  |            }
 0) ! 610.667 us  |          }
 0)   <========== |
 0)   1.000 us    |          preempt_count_sub();
 0) ! 625.667 us  |        }
 0)   0.666 us    |        preempt_count_sub();
 0) ! 874.000 us  |      }
 0)               |      __schedule() {
 0)   0.667 us    |        preempt_count_add();
 0)               |        rcu_note_context_switch() {
 0)   1.000 us    |          rcu_sched_qs();
 0)   1.000 us    |          rcu_preempt_qs();
 0) + 15.000 us   |        }
 0)   0.667 us    |        preempt_count_add();
 0)               |        pick_next_task_fair() {
 0)               |          put_prev_task_fair() {
 0)   0.667 us    |            update_curr();
 0)   1.000 us    |            __enqueue_entity();
 0) + 15.000 us   |          }
 0)   0.667 us    |          wakeup_preempt_entity();
 0)   0.667 us    |          clear_buddies();
 0)   2.334 us    |          set_next_entity();
 0) + 43.666 us   |        }
 0)               |        atomic_notifier_call_chain() {
 0)   0.666 us    |          __rcu_read_lock();
 0)               |          notifier_call_chain() {
 0)   1.000 us    |            vfp_notifier();
 0)   7.666 us    |          }
 0)   0.667 us    |          __rcu_read_unlock();
 0) + 27.333 us   |        }
 0)               |        finish_task_switch() {
 0)   1.000 us    |          preempt_count_sub();
 0)   8.666 us    |        }
 0)   0.666 us    |        preempt_count_sub();
 0) ! 247.333 us  |      }
 0)   1.000 us    |    }
 0) # 1413.666 us |  }

总结

上述内容就是我基于正点原子imx6ull开发板研究linux内核spi驱动调用关系的分析方法,可以类推查看i2c、usart等驱动。

本文参考文档如下:
trace参考:
https://blog.csdn.net/u013836909/article/details/129894966?spm=1001.2014.3001.5506
https://mp.weixin.qq.com/s/thJRf7QFt0gK_4F2jWCW6g
spidev参考:
https://blog.csdn.net/yyz_1987/article/details/131918983?spm=1001.2014.3001.5506

  • 29
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值