700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 高通看门狗驱动源码分析

高通看门狗驱动源码分析

时间:2019-03-01 05:25:55

相关推荐

高通看门狗驱动源码分析

内核版本

linux 3.10.84

函数调用关系

设备树分析

qcom,wdt@f9017000 {compatible = "qcom,msm-watchdog";reg = <0xf9017000 0x1000>;reg-names = "wdt-base";interrupts = <0 3 0>, <0 4 0>;qcom,bark-time = <11000>;qcom,pet-time = <10000>;qcom,ipi-ping;qcom,userspace-watchdog;};

bark-time:喂狗超时时间(狗叫),11s

pet-time:喂狗时间,10s

qcom,ipi-ping:如有此行,开启ipi-ping功能,则会在每次喂狗时ping所有CPU,如果任意CPU没响应,则不会喂狗。

qcom,userspace-watchdog:如有此行,则可进行用户空间喂狗:

将1写入 “user_pet_enabled” 文件,以启用对用户空间看门狗的硬件支持。需要用户空间通过在预期的间隔内继续向该文件写入1来监视看门狗。用户空间可以通过将0写入同一文件来禁用此要求。

源码分析

static int msm_watchdog_probe(struct platform_device *pdev)

和设备树的看门狗设备匹配上后执行

static int msm_watchdog_probe(struct platform_device *pdev){int ret;struct msm_watchdog_data *wdog_dd;wdog_wq = alloc_workqueue("wdog", WQ_HIGHPRI, 0);if (!wdog_wq) {pr_err("Failed to allocate watchdog workqueue\n");return -EIO;}if (!pdev->dev.of_node || !enable)return -ENODEV;wdog_dd = kzalloc(sizeof(struct msm_watchdog_data), GFP_KERNEL);if (!wdog_dd)return -EIO;ret = msm_wdog_dt_to_pdata(pdev, wdog_dd);if (ret)goto err;wdog_data = wdog_dd;wdog_dd->dev = &pdev->dev;platform_set_drvdata(pdev, wdog_dd);cpumask_clear(&wdog_dd->alive_mask);// 将初始化程序init_watchdog_work 加入任务队列,其实挺没必要,直接执行该函数就行。INIT_WORK(&wdog_dd->init_dogwork_struct, init_watchdog_work);// 将喂狗程序加入任务队列,负责定时喂狗INIT_DELAYED_WORK(&wdog_dd->dogwork_struct, pet_watchdog_work);// 启动刚才初始化程序 init_watchdog_workqueue_work(wdog_wq, &wdog_dd->init_dogwork_struct);return 0;err:destroy_workqueue(wdog_wq);kzfree(wdog_dd);return ret;}

static void init_watchdog_work(struct work_struct *work)

初始化看门狗程序

static void init_watchdog_work(struct work_struct *work){struct msm_watchdog_data *wdog_dd = container_of(work,struct msm_watchdog_data,init_dogwork_struct);unsigned long delay_time;uint32_t val;u64 timeout;int ret;/** Disable the watchdog for cluster 1 so that cluster 0 watchdog will* be mapped to the entire sub-system.*/if (wdog_dd->wdog_absent_base)__raw_writel(2, wdog_dd->wdog_absent_base + WDOG_ABSENT);if (wdog_dd->irq_ppi) {wdog_dd->wdog_cpu_dd = alloc_percpu(struct msm_watchdog_data *);if (!wdog_dd->wdog_cpu_dd) {dev_err(wdog_dd->dev, "fail to allocate cpu data\n");return;}*__this_cpu_ptr(wdog_dd->wdog_cpu_dd) = wdog_dd;ret = request_percpu_irq(wdog_dd->bark_irq, wdog_ppi_bark,"apps_wdog_bark",wdog_dd->wdog_cpu_dd);if (ret) {dev_err(wdog_dd->dev, "failed to request bark irq\n");free_percpu(wdog_dd->wdog_cpu_dd);return;}} else {ret = devm_request_irq(wdog_dd->dev, wdog_dd->bark_irq,wdog_bark_handler, IRQF_TRIGGER_RISING,"apps_wdog_bark", wdog_dd);if (ret) {dev_err(wdog_dd->dev, "failed to request bark irq\n");return;}}delay_time = msecs_to_jiffies(wdog_dd->pet_time);wdog_dd->min_slack_ticks = UINT_MAX;wdog_dd->min_slack_ns = ULLONG_MAX;configure_bark_dump(wdog_dd);timeout = (wdog_dd->bark_time * WDT_HZ)/1000;// 超过bark时间没有喂狗,则触发bark,bark是1个中断信号,__raw_writel(timeout, wdog_dd->base + WDT0_BARK_TIME);// 超过bark+3s仍没有喂狗,则触发bite,bite是个复位信号__raw_writel(timeout + 3*WDT_HZ, wdog_dd->base + WDT0_BITE_TIME);wdog_dd->panic_blk.notifier_call = panic_wdog_handler;atomic_notifier_chain_register(&panic_notifier_list,&wdog_dd->panic_blk);mutex_init(&wdog_dd->disable_lock);wdog_dd->user_pet_complete = true;wdog_dd->user_pet_enabled = false;// 初始化等待队列,这个队列主要是给用户空间喂狗用的init_waitqueue_head(&wdog_dd->pet_complete);// 启动在msm_watchdog_probe初始化了的喂狗程序queue_delayed_work(wdog_wq, &wdog_dd->dogwork_struct,delay_time);val = BIT(EN);if (wdog_dd->wakeup_irq_enable)val |= BIT(UNMASKED_INT_EN);__raw_writel(val, wdog_dd->base + WDT0_EN);__raw_writel(1, wdog_dd->base + WDT0_RST);wdog_dd->last_pet = sched_clock();wdog_dd->enabled = true;// 初始化看门狗的sysfs,主要还用来在用户空间喂狗init_watchdog_sysfs(wdog_dd);if (wdog_dd->irq_ppi)enable_percpu_irq(wdog_dd->bark_irq, 0);if (ipi_opt_en)cpu_pm_register_notifier(&wdog_cpu_pm_nb);dev_info(wdog_dd->dev, "MSM Watchdog Initialized\n");return;}

static void pet_watchdog_work(struct work_struct *work)

定时喂狗程序,对应wdog_dd->dogwork_struct任务

static void pet_watchdog_work(struct work_struct *work){unsigned long delay_time;struct delayed_work *delayed_work = to_delayed_work(work);struct msm_watchdog_data *wdog_dd = container_of(delayed_work,struct msm_watchdog_data,dogwork_struct);// 如果在设备树里开启了ipi_ping,会在这ping所有cpu,如果任意cpu没响应,会阻塞在这,阻止喂狗if (wdog_dd->do_ipi_ping)ping_other_cpus(wdog_dd);// 如果开启了用户空间喂狗(user_pet_complete = 1),会阻塞在这,// 等待用户空间写user_pet_enabled文件,触发wake_upwhile (wait_event_interruptible(wdog_dd->pet_complete,wdog_dd->user_pet_complete) != 0);/* Reset work and wait_event */wdog_dd->user_pet_complete = !wdog_dd->user_pet_enabled;delay_time = msecs_to_jiffies(wdog_dd->pet_time);/* Check again before scheduling ** Could have been changed on other cpu */// 只要开启看门狗,enable一般为非0// 启动下一次定时喂狗任务if (enable)queue_delayed_work(wdog_wq,&wdog_dd->dogwork_struct, delay_time);// 喂狗if (enable)pet_watchdog(wdog_dd);}

static int init_watchdog_sysfs(struct msm_watchdog_data *wdog_dd)

初始化看门狗的用户空间配置

static int init_watchdog_sysfs(struct msm_watchdog_data *wdog_dd){int error = 0;// 对应用户空间disable文件,可配置是否关闭看门狗error |= device_create_file(wdog_dd->dev, &dev_attr_disable);if (of_property_read_bool(wdog_dd->dev->of_node,"qcom,userspace-watchdog")) {// 对应用户空间pet_time文件,可查看喂狗周期,数值和设备树中pet-time配置项相同error |= device_create_file(wdog_dd->dev, &dev_attr_pet_time);// 对应用户空间user_pet_enabled文件,可配置是否开启用户空间喂狗功能// 读该文件时调用wdog_user_pet_enabled_get,// 写该文件时调用wdog_user_pet_enabled_set。error |= device_create_file(wdog_dd->dev,&dev_attr_user_pet_enabled);}if (error)dev_err(wdog_dd->dev, "cannot create sysfs attribute\n");return error;}

static ssize_t wdog_user_pet_enabled_set(struct device *dev,struct device_attribute *attr,const char *buf, size_t count)

static void __wdog_user_pet(struct msm_watchdog_data *wdog_dd)

用户空间写user_pet_enabled文件时,执行该函数,进行喂狗和开关用户空间喂狗操作

static ssize_t wdog_user_pet_enabled_set(struct device *dev,struct device_attribute *attr,const char *buf, size_t count){int ret;struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);// 如果写入的是'Y' 'y' '1',user_pet_enabled设置为'1'// 如果写入的是'N' 'n' '0',user_pet_enabled设置为'0'ret = strtobool(buf, &wdog_dd->user_pet_enabled);if (ret) {dev_err(wdog_dd->dev, "invalid user input\n");return ret;}// 进行喂狗__wdog_user_pet(wdog_dd);return count;}/** Userspace Watchdog Support:* Write 1 to the "user_pet_enabled" file to enable hw support for a* userspace watchdog.* Userspace is required to pet the watchdog by continuing to write 1* to this file in the expected interval.* Userspace may disable this requirement by writing 0 to this same* file.*//** 用户空间看门狗支持:* 将1写入 “user_pet_enabled” 文件,以启用对用户空间看门狗的硬件支持。* 需要用户空间通过在预期的间隔内继续向该文件写入1来监视看门狗。* 用户空间可以通过将0写入同一文件来禁用此要求。*/static void __wdog_user_pet(struct msm_watchdog_data *wdog_dd){wdog_dd->user_pet_complete = true;// wake up pet_watchdog_work 程序,进行喂狗wake_up(&wdog_dd->pet_complete);}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。