文章目录
- 1.内核调试手段:debugfs.h中api建立目录/sys/kernel/debug
- 2.性能优化:裸磁盘无法使用,一般都刷文件系统。驱动加上要考虑磁盘io,内存占用,cpu使用情况
- 3.Valgrind内存泄漏排查案例:
- 4.cpu瓶颈:
- 5.主频设置
- 6.驱动稳定性
- 1.platform总线:相对于USB/PCI/I2C/SPI等物理总线来说,platform总线是一种虚拟的总线,实际并不存在,工作是完成总线下的设备和驱动之间的匹配
- 1.1 of_device_id即of_match_table设备树采用的匹配方式:设备树中的每个设备节点的compatible属性会和of_match_table表中的所有成员比较,查看是否有相同的条目,有的话就表示设备和此驱动匹配,设备和驱动匹配成功后probe函数会执行
- 1.2 id_table匹配:id_table不存在的话就直接比较驱动和设备name字段
- 2.platform总线
1.内核调试手段:debugfs.h中api建立目录/sys/kernel/debug
内核开发会遇到内核崩溃,如空指针异常,内存访问越界,如下会打印出异常调用栈信息定位。
2.性能优化:裸磁盘无法使用,一般都刷文件系统。驱动加上要考虑磁盘io,内存占用,cpu使用情况
如下网络调试:
3.Valgrind内存泄漏排查案例:
如下malloc加个死循环就是内存泄漏。
dmesg会显示不全,因为环形buffer会覆盖。
4.cpu瓶颈:
-p pid
5.主频设置
6.驱动稳定性
希望arg有多大
likely一般用在if判断里,cpu会把当前指令后面指令预取出来,等到执行时就去执行,效率提高,但是也要判断后面那条指令大概率执不执行,执行的话取出来,不执行则跳过。
1.platform总线:相对于USB/PCI/I2C/SPI等物理总线来说,platform总线是一种虚拟的总线,实际并不存在,工作是完成总线下的设备和驱动之间的匹配
// include/linux/device.h, Linux系统内核使用bus_type结构体表示总线, Linux系统中文件的体现形式是在/sys/bus下有spi文件夹里有device和driver文件夹
struct bus_type {
const char *name; /* 总线名字 */
const char *dev_name;
struct device *dev_root;
struct device_attribute *dev_attrs; /* use dev_groups instead */
const struct attribute_group **bus_groups; /* 总线属性 */
const struct attribute_group **dev_groups; /* 设备属性 */
const struct attribute_group **drv_groups; /* 驱动属性 */
int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
int (*online)(struct device *dev);
int (*offline)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
const struct dev_pm_ops *pm;
const struct iommu_ops *iommu_ops;
struct subsys_private *p;
struct lock_class_key lock_key;
};
// drivers/base/platform.c
struct bus_type platform_bus_type = { // platform总线是bus_type的一个具体实例
.name = "platform",
.dev_groups = platform_dev_groups,
.match = platform_match, //下面定义
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* When driver_override is set, only bind to the matching driver */
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
// 如下4种设备和驱动匹配方式:
/* 1. Attempt an OF style match first */
if (of_driver_match_device(dev, drv))
return 1;
/* 2. Then try ACPI style match */
// 从device中找到acpi_device设备后就可匹配了,of_driver_match_device没有匹配到,则用这种
if (acpi_driver_match_device(dev, drv))
return 1;
/* 3. Then try to match against the id table */
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* 4. fall-back to driver name match */
return (strcmp(pdev->name, drv->name) == 0);
}
platform总线管理下的platform_device和platform_driver(任何一种Linux设备驱动模型下的总线都由这两个部分组成)。
// include/linux/platform_device.h
struct platform_device {
const char *name;
int id;
bool id_auto;
struct device dev;
u32 num_resources;
struct resource *resource;
const struct platform_device_id *id_entry;
char *driver_override; /* Driver name to force a match */
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
struct platform_driver {
int (*probe)(struct platform_device *); /// 当驱动与设备匹配成功以后 probe 函数就会执行
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver; device_driver基类下面定义
const struct platform_device_id *id_table; // id_table是个表(也就是数组),每个元素的类型为 platform_device_id,下面定义
bool prevent_deferred_probe;
};
//struct platform_device_id {
// char name[PLATFORM_NAME_SIZE];
// kernel_ulong_t driver_data;
//};
1.1 of_device_id即of_match_table设备树采用的匹配方式:设备树中的每个设备节点的compatible属性会和of_match_table表中的所有成员比较,查看是否有相同的条目,有的话就表示设备和此驱动匹配,设备和驱动匹配成功后probe函数会执行
// include/linux/of_device.h
static inline int of_driver_match_device(struct device *dev, // platform_match函数中调用
const struct device_driver *drv) device_driver下面定义
{
return of_match_device(drv->of_match_table, dev) != NULL;
}
struct device_driver { //基类,platform_driver继承了这个基类
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
const struct of_device_id *of_match_table; of_device_id下面定义
const struct acpi_device_id *acpi_match_table;
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
};
//struct of_device_id { //include/linux/mod_devicetable.h
// char name[32];
// char type[32];
// char compatible[128];
// const void *data;
//};
如下不是设备树,spi_driver相当于device_driver。
1.2 id_table匹配:id_table不存在的话就直接比较驱动和设备name字段
2.platform总线
实际存在的总线通过cpu bus直接寻址,访问对应的i2c设备对应的寄存器,linux基于这个共性,在内核的设备模型基础上也就是device,device_driver进一步的封装成platform_bus,platform_device,platform_driver,便于开发,platform总线为实际的总线服务,挂在platform bus不单单是一个虚拟总线,probe里还会注册如i2c_board_info,gpio控制器等实际总线设备驱动,
如下包含device_driver
注册相当于链表
platform_device接触的不多,因为有设备树,设备树里只要写了兼容性名字,都会被内核解析成platform_device,最早没有设备树前,platform_device要自己注册,现在不用。资源具有独占性,如这个中断不允许多个设备同时使用,因为在内核提供很多api用于分配和管理资源,
match是由每个bus自己实现,如以太网有自己的match,最重要工作是driver和device的匹配,规则可以自己定的如下,如以太网的match以phyid进行匹配规则,of开头都是设备树解析函数,所以每个设备树有自己的兼容性名字并且ok,都会在内核初始化时解析成platform_device。所以bus在driver注册时会去扫platform_device链表,反之一样,扫描时调的匹配规则就是下面函数,匹配成功后调用platform_driver里probe函数进行注册自己对应的i2c,spi,i2c_board_info填充,spi_board_info填充,把设备树里设备信息通过获取资源方法拿出来进行解析。