gtdt是APCI的一个子表,主要用来传递timer相关的resource
其初始化函数在drivers/acpi/gtdt.c 中
static int __init gtdt_sbsa_gwdt_init(void)
{
struct acpi_table_header *table;
void *platform_timer;
int index = 0;
int ret;
//如果ACPI 是disable的,直接返回.
if (acpi_disabled)
return 0;
//通过acpi_get_table 来从APCI的list中找到gtdt子表.
if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0, &table)))
return -EINVAL;
//主要是给acpi_gtdt_desc 这个变量赋值.static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
ret = acpi_gtdt_init(table);
if (ret <= 0)
return ret;
//检查传递过来的timer 如果是watchdog的话,就gtdt_import_sbsa_gwdt 来注册的SBSA generic Watchdog
for_each_platform_timer(platform_timer) {
if (!is_watchdog(platform_timer))
continue;
ret = gtdt_import_sbsa_gwdt(platform_timer, index);
if (ret)
break;
index++;
}
if (index)
pr_info("found %d SBSA generic Watchdog(s).\n", index);
return ret;
}
device_initcall(gtdt_sbsa_gwdt_init);
可见gtdt是通过device_initcall 来初始化的.
int __init acpi_gtdt_init(struct acpi_table_header *table)
{
void *start;
struct acpi_table_gtdt *gtdt;
gtdt = container_of(table, struct acpi_table_gtdt, header);
//给acpi_gtdt_desc 赋值
acpi_gtdt_desc.gtdt = gtdt;
acpi_gtdt_desc.gtdt_end = (void *)table + table->length;
//看起来gtdt有两版version,如果小于1的话,就不支持
if (table->revision < 2) {
pr_debug("Revision:%d doesn't support Platform Timers.\n",
table->revision);
return 0;
}
//如果gtdt主要是传递timer相关的resource,如果gtdt->platform_timer_count 为零的话,就表示传递过来的gtdt表没有timer,也就没有必要给platform_timer_start赋值了。
if (!gtdt->platform_timer_count) {
pr_debug("No Platform Timer.\n");
return 0;
}
//得到platform_timer_start的起始地址,并赋值给acpi_gtdt_desc.platform_timer_start
start = (void *)gtdt + gtdt->platform_timer_offset;
if (start < (void *)table + sizeof(struct acpi_table_gtdt)) {
pr_err(FW_BUG "Failed to retrieve timer info from firmware: invalid data.\n");
return -EINVAL;
}
acpi_gtdt_desc.platform_timer_start = start;
return gtdt->platform_timer_count;
}
回到gtdt_sbsa_gwdt_init 中通过is_watchdog 检测是不是watchdog的timer
static inline bool is_watchdog(void *platform_timer)
{
struct acpi_gtdt_header *gh = platform_timer;
return gh->type == ACPI_GTDT_TYPE_WATCHDOG;
}
现在支持的timer除了watchdog还有timer block。
/* Values for GTDT subtable type above */
enum acpi_gtdt_type {
ACPI_GTDT_TYPE_TIMER_BLOCK = 0,
ACPI_GTDT_TYPE_WATCHDOG = 1,
ACPI_GTDT_TYPE_RESERVED = 2 /* 2 and greater are reserved */
};
如果是watchdog timer的话,继续调用gtdt_import_sbsa_gwdt
static int __init gtdt_import_sbsa_gwdt(struct acpi_gtdt_watchdog *wd,
int index)
{
struct platform_device *pdev;
//通过map_gt_gsi 得到irq number
int irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags);
int no_irq = 1;
/*
* According to SBSA specification the size of refresh and control
* frames of SBSA Generic Watchdog is SZ_4K(Offset 0x000 – 0xFFF).
*/
//watchdog timer的resource 有三种,分别是control_frame_address/refresh_frame_address/irq
struct resource res[] = {
DEFINE_RES_MEM(wd->control_frame_address, SZ_4K),
DEFINE_RES_MEM(wd->refresh_frame_address, SZ_4K),
DEFINE_RES_IRQ(irq),
};
pr_debug("found a Watchdog (0x%llx/0x%llx gsi:%u flags:0x%x).\n",
wd->refresh_frame_address, wd->control_frame_address,
wd->timer_interrupt, wd->timer_flags);
if (!(wd->refresh_frame_address && wd->control_frame_address)) {
pr_err(FW_BUG "failed to get the Watchdog base address.\n");
return -EINVAL;
}
if (!wd->timer_interrupt)
pr_warn(FW_BUG "failed to get the Watchdog interrupt.\n");
else if (irq <= 0)
pr_warn("failed to map the Watchdog interrupt.\n");
else
no_irq = 0;
/*
* Add a platform device named "sbsa-gwdt" to match the platform driver.
* "sbsa-gwdt": SBSA(Server Base System Architecture) Generic Watchdog
* The platform driver (like drivers/watchdog/sbsa_gwdt.c)can get device
* info below by matching this name.
*/
//注册sbsa-gwdt对应的platfrom device
pdev = platform_device_register_simple("sbsa-gwdt", index, res,
ARRAY_SIZE(res) - no_irq);
if (IS_ERR(pdev)) {
acpi_unregister_gsi(wd->timer_interrupt);
return PTR_ERR(pdev);
}
return 0;
}
其初始化函数在drivers/acpi/gtdt.c 中
static int __init gtdt_sbsa_gwdt_init(void)
{
struct acpi_table_header *table;
void *platform_timer;
int index = 0;
int ret;
//如果ACPI 是disable的,直接返回.
if (acpi_disabled)
return 0;
//通过acpi_get_table 来从APCI的list中找到gtdt子表.
if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_GTDT, 0, &table)))
return -EINVAL;
//主要是给acpi_gtdt_desc 这个变量赋值.static struct acpi_gtdt_descriptor acpi_gtdt_desc __initdata;
ret = acpi_gtdt_init(table);
if (ret <= 0)
return ret;
//检查传递过来的timer 如果是watchdog的话,就gtdt_import_sbsa_gwdt 来注册的SBSA generic Watchdog
for_each_platform_timer(platform_timer) {
if (!is_watchdog(platform_timer))
continue;
ret = gtdt_import_sbsa_gwdt(platform_timer, index);
if (ret)
break;
index++;
}
if (index)
pr_info("found %d SBSA generic Watchdog(s).\n", index);
return ret;
}
device_initcall(gtdt_sbsa_gwdt_init);
可见gtdt是通过device_initcall 来初始化的.
int __init acpi_gtdt_init(struct acpi_table_header *table)
{
void *start;
struct acpi_table_gtdt *gtdt;
gtdt = container_of(table, struct acpi_table_gtdt, header);
//给acpi_gtdt_desc 赋值
acpi_gtdt_desc.gtdt = gtdt;
acpi_gtdt_desc.gtdt_end = (void *)table + table->length;
//看起来gtdt有两版version,如果小于1的话,就不支持
if (table->revision < 2) {
pr_debug("Revision:%d doesn't support Platform Timers.\n",
table->revision);
return 0;
}
//如果gtdt主要是传递timer相关的resource,如果gtdt->platform_timer_count 为零的话,就表示传递过来的gtdt表没有timer,也就没有必要给platform_timer_start赋值了。
if (!gtdt->platform_timer_count) {
pr_debug("No Platform Timer.\n");
return 0;
}
//得到platform_timer_start的起始地址,并赋值给acpi_gtdt_desc.platform_timer_start
start = (void *)gtdt + gtdt->platform_timer_offset;
if (start < (void *)table + sizeof(struct acpi_table_gtdt)) {
pr_err(FW_BUG "Failed to retrieve timer info from firmware: invalid data.\n");
return -EINVAL;
}
acpi_gtdt_desc.platform_timer_start = start;
return gtdt->platform_timer_count;
}
回到gtdt_sbsa_gwdt_init 中通过is_watchdog 检测是不是watchdog的timer
static inline bool is_watchdog(void *platform_timer)
{
struct acpi_gtdt_header *gh = platform_timer;
return gh->type == ACPI_GTDT_TYPE_WATCHDOG;
}
现在支持的timer除了watchdog还有timer block。
/* Values for GTDT subtable type above */
enum acpi_gtdt_type {
ACPI_GTDT_TYPE_TIMER_BLOCK = 0,
ACPI_GTDT_TYPE_WATCHDOG = 1,
ACPI_GTDT_TYPE_RESERVED = 2 /* 2 and greater are reserved */
};
如果是watchdog timer的话,继续调用gtdt_import_sbsa_gwdt
static int __init gtdt_import_sbsa_gwdt(struct acpi_gtdt_watchdog *wd,
int index)
{
struct platform_device *pdev;
//通过map_gt_gsi 得到irq number
int irq = map_gt_gsi(wd->timer_interrupt, wd->timer_flags);
int no_irq = 1;
/*
* According to SBSA specification the size of refresh and control
* frames of SBSA Generic Watchdog is SZ_4K(Offset 0x000 – 0xFFF).
*/
//watchdog timer的resource 有三种,分别是control_frame_address/refresh_frame_address/irq
struct resource res[] = {
DEFINE_RES_MEM(wd->control_frame_address, SZ_4K),
DEFINE_RES_MEM(wd->refresh_frame_address, SZ_4K),
DEFINE_RES_IRQ(irq),
};
pr_debug("found a Watchdog (0x%llx/0x%llx gsi:%u flags:0x%x).\n",
wd->refresh_frame_address, wd->control_frame_address,
wd->timer_interrupt, wd->timer_flags);
if (!(wd->refresh_frame_address && wd->control_frame_address)) {
pr_err(FW_BUG "failed to get the Watchdog base address.\n");
return -EINVAL;
}
if (!wd->timer_interrupt)
pr_warn(FW_BUG "failed to get the Watchdog interrupt.\n");
else if (irq <= 0)
pr_warn("failed to map the Watchdog interrupt.\n");
else
no_irq = 0;
/*
* Add a platform device named "sbsa-gwdt" to match the platform driver.
* "sbsa-gwdt": SBSA(Server Base System Architecture) Generic Watchdog
* The platform driver (like drivers/watchdog/sbsa_gwdt.c)can get device
* info below by matching this name.
*/
//注册sbsa-gwdt对应的platfrom device
pdev = platform_device_register_simple("sbsa-gwdt", index, res,
ARRAY_SIZE(res) - no_irq);
if (IS_ERR(pdev)) {
acpi_unregister_gsi(wd->timer_interrupt);
return PTR_ERR(pdev);
}
return 0;
}