gtdt的作用之一注册sbsa watchdog device

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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值