當前位置:首頁 » 操作系統 » suspendlinux

suspendlinux

發布時間: 2022-06-09 08:47:31

linux觸摸屏驅動中什麼時候會調用suspend這個函數

android系統摁下電源鍵後會讓系統進入休眠以達到節電的目的。內核驅動中和休眠相關的就是suspend和resume函數。

suspend函數用於休眠,resume函數用於喚醒。下面分析驅動中的這兩個函數是如何被調用到的。

驅動部分:

首先需要分析驅動的注冊過程,較新的內核都是採用DTS方式來取代在內核中直接定義platform_device數據結構的注冊方式,本文是基於DTS機制的內核來分析。

proct對應的dts文件在編譯時被編譯為dtb文件,uboot在啟動時候會將其地址傳給內核,內核在啟動過程中會去解析,具體解析是在start_kernel()->setup_arch() --> unflatten_device_tree()中具體分析可以參考網上,解析的最終結果會存放在allnodes地址處,這個allnodes隨後在machine的init函數
中被使用,init函數中會根據allnodes中的節點數據組合成platform_device數據結構,然後將其注冊到platform匯流排上,下面簡要分析一下並重點關注這些初始化過程中和
pm相關的初始化。

我參與的項目中machine的init函數就是via_init_machine函數,在這個函數中就是調用了of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL)這個函數來解析allnodes的。of_platform_populate是系統提供的介面。下面分析這個介面的實現:

[html] view plain
int of_platform_populate(struct device_node *root,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent)
{
struct device_node *child;
int rc = 0;

root = root ? of_node_get(root) : of_find_node_by_path("/");
if (!root)
return -EINVAL;

for_each_child_of_node(root, child) {
rc = of_platform_bus_create(child, matches, lookup, parent, true);
if (rc)
break;
}

of_node_put(root);
return rc;
}
root最後就是取到的根節點,然後其作為參數傳遞給of_platform_bus_create,of_platform_device_create_pdata的實現如下:

[html] view plain
static int of_platform_bus_create(struct device_node *bus,
const struct of_device_id *matches,
const struct of_dev_auxdata *lookup,
struct device *parent, bool strict)
{
const struct of_dev_auxdata *auxdata;
struct device_node *child;
struct platform_device *dev;
const char *bus_id = NULL;
void *platform_data = NULL;
int rc = 0;

/* Make sure it has a compatible property */
if (strict && (!of_get_property(bus, "compatible", NULL))) {
pr_debug("%s() - skipping %s, no compatible prop\n",
__func__, bus->full_name);
return 0;
}

auxdata = of_dev_lookup(lookup, bus);
if (auxdata) {
bus_id = auxdata->name;
platform_data = auxdata->platform_data;
}

if (of_device_is_compatible(bus, "arm,primecell")) {
of_amba_device_create(bus, bus_id, platform_data, parent);
return 0;
}

dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
if (!dev || !of_match_node(matches, bus))
return 0;

for_each_child_of_node(bus, child) {
pr_debug(" create child: %s\n", child->full_name);
rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
if (rc) {
of_node_put(child);
break;
}
}
return rc;
}
根據傳入參數,我們這里直接分析of_platform_device_create_padate函數,如下:

[html] view plain
struct platform_device *of_platform_device_create_pdata(
struct device_node *np,
const char *bus_id,
void *platform_data,
struct device *parent)
{
struct platform_device *dev;

if (!of_device_is_available(np))
return NULL;

dev = of_device_alloc(np, bus_id, parent);
if (!dev)
return NULL;

#if defined(CONFIG_MICROBLAZE)
dev->archdata.dma_mask = 0xffffffffUL;
#endif
dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;

/* We do not fill the DMA ops for platform devices by default.
* This is currently the responsibility of the platform code
* to do such, possibly using a device notifier
*/

if (of_device_add(dev) != 0) {
platform_device_put(dev);
return NULL;
}

return dev;
}

of_platform_device_create_padate->of_device_alloc->platform_device_alloc

便在platform_device_alloc函數中進行進行alloc和初始化了,實現如下:

[html] view plain
struct platform_device *platform_device_alloc(const char *name, int id)
{
struct platform_object *pa;

pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
if (pa) {
strcpy(pa->name, name);
pa->pdev.name = pa->name;
pa->pdev.id = id;
device_initialize(&pa->pdev.dev);
pa->pdev.dev.release = platform_device_release;
arch_setup_pdev_archdata(&pa->pdev);
}

return pa ? &pa->pdev : NULL;
}
可以看到有個device_initialize,這裡面對pdev.dev做一些列的初始化,其中有一個函數就是device_pm_init,這個函數就是我們一直關心的device相關的pm函數,具體實現如下:

[html] view plain
void device_pm_init(struct device *dev)
{
dev->power.is_prepared = false;
dev->power.is_suspended = false;
init_completion(&dev->power.completion);
complete_all(&dev->power.completion);
dev->power.wakeup = NULL;
spin_lock_init(&dev->power.lock);
pm_runtime_init(dev);
INIT_LIST_HEAD(&dev->power.entry);
dev->power.power_state = PMSG_INVALID;
}

可以看見它對device和功耗相關的數據做了一些初始化,我們這里先重點關注下dev->power.entry,初始化一個鏈表頭,所以他/它很有可能會在後面加到某個鏈表裡面去,而那個鏈表應該是用來保存所有的device用的。系統中所有的platform_device都是通過這種方式注冊到系統中的,那麼應該所有的platform_device都會初始化一個dev->power.entry,如果到時候把所有的dev->power.entry都添加到某個鏈表上去,那麼系統到時候查詢的時候只要找到這個list head就可以找到所有的platform_device了。嗯,不過這是我們的猜測。我們接下去分析來驗證下。

platform_device通過alloc之後已經初始化好了,那麼接下去就可以添加到系統中了,所以我們再回頭看of_platform_device_create_pdata的實現。
函數在of_device_alloc之後把dev->dev.bus賦值給了platform_bus_type,接著就調用了of_device_add函數,在of_device_add函數中最後通過device_add添加到了bus上,但是device_add中有個函數需要我們關系,就是device_pm_add(dev),實現如下:

[html] view plain
void device_pm_add(struct device *dev)
{
pr_debug("PM: Adding info for %s:%s\n",
dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
mutex_lock(&dpm_list_mtx);
if (dev->parent && dev->parent->power.is_prepared)
dev_warn(dev, "parent %s should not be sleeping\n",
dev_name(dev->parent));
list_add_tail(&dev->power.entry, &dpm_list);
dev_pm_qos_constraints_init(dev);
mutex_unlock(&dpm_list_mtx);
}

可以看到這里list_add_tail(&dev->power.entry, &dpm_list);這就驗證了我們之前的猜測。所有注冊到系統中的設備,最終都是會添加到dpm_list這條鏈表上。

那麼系統在休眠的時候是如何通過dmp_list這表鏈表來suspend設備的呢?接下去就是我們要分析的電源管理部分內容。

系統電源部分:
電源管理相關文件在kernel/power目錄下,前面已經分析到。系統中注冊的設備都是會添加到dmp_list這條鏈表上的。那麼睡眠的時候系統應該是會查找dmp_list這條鏈表,
然後通過這條鏈表依次去查到對應的driver,然後調用driver中的suspend方法。下面我們來驗證。

2.在suspend會輪詢bus下的driver,然後一次調用到driver->pm->suspend方法,然後進入休眠。

3.state_store->pm_suspend->enter_state->suspend_devices_and_enter->dpm_suspend_start->dpm_suspend->device_suspend->__device_suspend->pm_op->(ops->suspend)

Ⅱ linux suspend resume可以使用互斥體嗎

Suspend可以掛起一個線程,就是把這個線程暫停了,它占著資源,但不運行,用Resume是繼續掛起的線程,讓這個線程繼續執行下去

Ⅲ linux 如何立刻suspend usb

suspend:

#disableexternalwake-up;dothisonlyonce
echodisabled>/sys/bus/usb/devices/usb1/power/wakeup

echosuspend>/sys/bus/usb/devices/usb1/power/level#turnoff

wake up:

echoon>/sys/bus/usb/devices/usb1/power/level#turnon

根據你的實際情況修改usb1為usb n

Ⅳ 在linux中,qsub投任務,我想問一下這兩個狀態:pending和suspend 有什麼區別

通常情況下:
Pending是指任務在可以隨時運行,但是因為已經有任務在運行,所以排隊,這種狀態的任務可隨時進入運行態。
Suspend是被掛起的,在等待資源,等待的資源可以是輸入、信號或者硬體設備,在得到想要的資源後會轉成Pending狀態(如果有任務在運行)。

Ⅳ 紅帽linux ctrl+alt+delete第一個選項suspend和第二個選項hibemate是做什麼的

suspend 休眠到內存。。。休眠過程中掉電的話開機工作丟失,但是不掉電的情況下恢復工作速度快
hibernate 休眠到硬碟,即使掉電後開機依然可以繼續先前的工作,但是速度慢一些。。。因為要將硬碟上的狀態拷到內存

Ⅵ 如何在Android 或Linux 下,做Suspend /Resume 的Debug

在Linux或Android下,做power management 的調適時,常遇到沒有足夠的information,可以做為debug時的依據和參考

我們整理了幾個常用的參數或Command,可供設計者,得到足夠的Informaiton 做Suspend / Resume的function Debug。

加boot 參數 no_console_suspend
基本上我們常常使用console做為suspend function的debug的Information source,但原始的source code在suspend過程中,會將console關掉。所以我們看到一定程度後就再也看不到message了。

但是我們並不知道在Suspend的過程中,系統到底發生了什麼事,可能造成無法suspend。
為此,我們就會在kernel 啟動參數中加上no_console_suspend這個參數。在AM/DM37x APM中是修改boot.scr檔案參數
#!/bin/sh
cat <<EOF > boot.cmd
if fatload mmc 0 82000000 uImage
then
echo ***** Kernel: /dev/mmcblk0p1/uImage *****
fi
echo ***** RootFS: /dev/mmcblk0p2 *****
# Pantherboard DVI output
#setenv bootargs 'console=ttyO2,115200n8 androidboot.console=ttyO2 mem=512M root=/dev/mmcblk0p2 rw rootfstype=ext3 rootdelay=1 init=/init ip=off omap_vout.vid1_static_vrfb_alloc=y omapdss.def_disp=dvi vram=32M omapfb.mode=dvi:1280x720MR-32 omapfb.vram=0:16M mpurate=1000'
# Pantherboard LCD output
setenv bootargs 'console=ttyO2,115200n8 androidboot.console=ttyO2 mem=512M root=/dev/mmcblk0p2 rw rootfstype=ext3 rootdelay=1 init=/init ip=off omap_vout.vid1_static_vrfb_alloc=y omapdss.def_disp=lcd omapfb.mode=lcd:800x480MR-32 vram=8M omapfb.vram=0:8M mpurate=1000'

將no_console_suspend加上去到boot 參數後就好了

setenv bootargs 'console=ttyO2,115200n8 androidboot.console=ttyO2 mem=512M root=/dev/mmcblk0p2 rw rootfstype=ext3 rootdelay=1 init=/init ip=off omap_vout.vid1_static_vrfb_alloc=y omapdss.def_disp=lcd omapfb.mode=lcd:800x480MR-32 vram=8M omapfb.vram=0:8M mpurate=1000 no_console_suspend'

如果是OMAP4 APM的話,請修改Kernel 參數的所在檔案即可(在U-boot Source code中)

這個是基本的參數,所以在Android或Linux上都可以使用。 kernel把console suspend掉以後, 不管裡面出了什麼事情, 在Console上都看不到。 而使用這個參數後,大部分在suspend/resume時候的死機都可以通過Console看到kernel Panic的信息, 這樣我們才會知道是哪裡出了問題。 因為有的時候resume出錯, 或者suspend到很後面出錯的console不加這個參數都看不到。

但這個參數在TI OMAP3/OMAP4/AM37x/DM37x有可能造成有時Suspend 完當掉或是resume 失敗的問題,假如已經抓到問題在那的時候,您就可以將這個參數Disable,不然很可能就會Debug不下去。

initcall_debug
這個同樣kernel參數,使用的時機是,當我們不知道是那個driver在suspend/resume過程中出錯的時候,可以使用這個參數來找出問題所在。在下完這個參數後,Kernel在suspend時,會將每個driver或task的狀況report出來。我們可以藉由這些information,Check 在suspend時,每個task和driver是否已經完成進suspend 的相關准備工作…

打開這個參數的方法有二種
一種是在console下Command,啟動這個function…

echo 1 > /sys/mole/kernel/parameters/initcall_debug
echo 9 > /proc/sys/kernel/printk

其中上面的第一條命令是打開initcall_debug, 這個是所有的kernel都會有的。

而第二條命令是要提高kernel message 級別,因為initcall的這些信息都是KERN_DEBUG級別的, 所以需要提高printk的級別才可以看到, 要不然suspend/resume的時候掛了,你就沒有機會看到這些信息了。

另一種啟動方法是寫在kernel的啟動參數下,就可以了。

setenv bootargs 'console=ttyO2,115200n8 androidboot.console=ttyO2 mem=512M root=/dev/mmcblk0p2 rw rootfstype=ext3 rootdelay=1 init=/init ip=off omap_vout.vid1_static_vrfb_alloc=y omapdss.def_disp=lcd omapfb.mode=lcd:800x480MR-32 vram=8M omapfb.vram=0:8M mpurate=1000 initcall_debug no_console_suspend'

同樣的,這個參數也有可能造成AM37x/DM37x/OMAP4 APM發生進suspend當掉的問題。所以一旦知道問題所在,麻煩請將這個參數Disable掉。
suspend_test
這個方法可以用rtc這種軟體的方式來做循環的suspend/resume, 盡管對於Android這樣並不是很足夠, (還要再模擬一個POWER_KEY上去才夠), 但是對於測試Driver的穩定性, 還是有一定用處的。不要認為suspend了幾次可以,那麼就可以通過幾千次的測試。這個suspend是5秒鍾用RTC喚醒,然後回到Android後5秒鍾又會自動睡下去,但是對於通用Linux,你可以寫個script來讓他起來一會再睡下去,或許這個工具比較有用rtcwakeup(google rtcwakeup)。

使用方法:
編譯一個有這個功能的kernel, make menuconfig 以後選上

CONFIG_PM_DEBUG=y
CONFIG_PM_TEST_SUSPEND=y

這兩個選項,燒寫新的kernel,然後打開你需要測試的Device, 比如WIFI,3G

echo "core" > /sys/power/pm_test
echo "mem" > /sys/power/state

這樣, 它就會循環休眠和喚醒了。

wakelock
Android和Linux在Power Management相關的最大的就是wakelock機制的有無。Android有時候會碰到suspend進不去,或者suspend到最後又莫名奇妙的wake up的問題。這些都有可能是wakelock引起的,或者說是wakelock的使用者引起的。怎麼fine tune呢,使用Console在Android 系統下設定:
echo 15 > /sys/mole/wakelock/parameters/debug_mask
echo 15 > /sys/mole/userwakelock/parameters/debug_mask

15是代表16進制的F, 在wakelock裡面就是把所有的debug信息打開, 起碼現在是這樣設定的。如果以後不夠用了,可能就會改成255.
這樣你能看到kernel和frameworks層對於wakelock的操作、申請及釋放。這樣看申請和釋放成對否就可以了。
注意: wakelock有一種是timeout的,就是說多少毫秒以後,會自動釋放,對於這些wakelock,申請和釋放可能是不成對的。

power.0
有時看到系統suspend到了最後, 然後遇到power.0後suspend失敗,然後整個系統又resume回來。這個是android專有的,因為power.0是android注冊到suspend最後的一個行程, 它會在CPU進入suspend之前檢查一下有沒有wakelock存在, 如果這時候還有沒有釋放的wakelock, 那麼它會return -EBUSY然後導致整個suspend失敗。 Check這個問題的方法就是把上面wakelock的debug信息打開,然後看看是哪個去申請了wakelock,然後Release它。

這個錯誤的錯誤信息大概是這樣的:

pm_noirq_op(): platform_pm_suspend_noirq+0x0/0x38 returns -11
PM: Device power.0 failed to suspend late: error -11

earlysuspend
在android裡面中另外一個和Power Management有相關的機制叫earlysuspend, 同樣可以打開debug message,用來做Android earlysuspend debug之用:
echo 15 > /sys/mole/earlysuspend/parameters/debug_mask

來把相關的debug信息印出來, 例如那個earlysuspend要被call之類的。
suspend/resume 時間 fine tune
有的時候你要調試suspend/resume的時間太慢的問題。 一種方法是用initcall_debug, 然後把printk的時間戳打上, 然後看那個process最慢,再來Check原因是什麼
我有一個patch,專門用來調試這個問題的,但是upstream不接受, 說非要用這種折磨人的方法才行, 但是如果你想用可以下下來打上去用一下。
地址在這里:http://www.spinics.net/lists/linux-pm/msg24063.html
用法是, 打上這個PATCH以後, 在KERNEL裡面選擇上PM_DEBUG, SUSPEND_DEVICE_TIME_DEBUG 這兩個選項。
然後
echo 微秒> /sys/power/device_suspend_time_threshold

比如
echo 50000 > /sys/power/device_suspend_time_threshold

注意這里是微秒哦。 。 。 它會把在suspend/resume的時候慢的那些driver打出來,然後你去幹掉它。 。

熱點內容
怎麼給自己手機寫一個腳本 發布:2024-11-01 20:23:41 瀏覽:241
c語言大小寫判斷 發布:2024-11-01 20:21:53 瀏覽:130
php的點餐系統源碼 發布:2024-11-01 20:13:53 瀏覽:714
拜占庭演算法 發布:2024-11-01 20:10:31 瀏覽:357
xcode編譯參數 發布:2024-11-01 20:00:04 瀏覽:665
蘋果5怎麼設置密碼鎖屏 發布:2024-11-01 19:54:55 瀏覽:124
寶塔上傳文件夾 發布:2024-11-01 19:39:50 瀏覽:257
java雲編譯器 發布:2024-11-01 19:34:24 瀏覽:385
免費源碼分享網 發布:2024-11-01 19:29:19 瀏覽:855
硬碟8mb緩存 發布:2024-11-01 19:20:02 瀏覽:192