ipmi 的初始化,其作用是和BMC通信

IPMI的全称是Intelligent Platform Management Interface,是一个用于监控系统的智能设备,其能动态的检测到系统中的传感器并有监控这些传感器工作的能力,当这些传感器的工作异常是能通知系统.IPMI的controller就叫BMC,其全称是Baseboard Management Controller.
我们这里以si_intf.c 为例,其本身就是就是和BMC 通信的。

先看实际IPMI 运行的截图,ipmi 有很多种命令。


static int init_ipmi_si(void)
{
    int  i;
    char *str;
    int  rv;
    struct smi_info *e;
    enum ipmi_addr_src type = SI_INVALID;
// 避免重复初始化,可以理解为简单的单例模式
    if (initialized)
        return 0;
    initialized = 1;
//ipmi controller 可以挂在platform/pci等个个总线上,这里以platform为例.
    if (si_tryplatform) {
        rv = platform_driver_register(&ipmi_driver);
        if (rv) {
            printk(KERN_ERR PFX "Unable to register "
                   "driver: %d\n", rv);
            return rv;
        }
    }
//这里的si_type_str的值有三种SI_KCS/SI_SMIC/SI_BT
    /* Parse out the si_type string into its components. */
    str = si_type_str;
    if (*str != '\0') {
        for (i = 0; (i < SI_MAX_PARMS) && (*str != '\0'); i++) {
            si_type[i] = str;
            str = strchr(str, ',');
            if (str) {
                *str = '\0';
                str++;
            } else {
                break;
            }
        }
    }

    printk(KERN_INFO "IPMI System Interface driver.\n");
//通过hardcode的方式检测是否有BMC,如果没有BMC,也就没有必要往下走了,因为我们这个程序本身就是和BMC 通信的
    /* If the user gave us a device, they presumably want us to use it */
    if (!hardcode_find_bmc())
        return 0;
//这里检测IPMI是否是pci设备
#ifdef CONFIG_PCI
    if (si_trypci) {
        rv = pci_register_driver(&ipmi_pci_driver);
        if (rv)
            printk(KERN_ERR PFX "Unable to register "
                   "PCI driver: %d\n", rv);
        else
            pci_registered = true;
    }
#endif
//检测是否通过DMI告知bmc的信息
#ifdef CONFIG_DMI
    if (si_trydmi)
        dmi_find_bmc();
#endif
//检测是否通过ACPI告知bmc的信息
#ifdef CONFIG_ACPI
    if (si_tryacpi)
        spmi_find_bmc();
#endif

#ifdef CONFIG_PARISC
    register_parisc_driver(&ipmi_parisc_driver);
    parisc_registered = true;
#endif

    /* We prefer devices with interrupts, but in the case of a machine
       with multiple BMCs we assume that there will be several instances
       of a given type so if we succeed in registering a type then also
       try to register everything else of the same type */
//这里针对有多个BMC的情况,一般不会走这里
    mutex_lock(&smi_infos_lock);
    list_for_each_entry(e, &smi_infos, link) {
        /* Try to register a device if it has an IRQ and we either
           haven't successfully registered a device yet or this
           device has the same type as one we successfully registered */
        if (e->irq && (!type || e->addr_source == type)) {
            if (!try_smi_init(e)) {
                type = e->addr_source;
            }
        }
    }

    /* type will only have been set if we successfully registered an si */
    if (type) {
        mutex_unlock(&smi_infos_lock);
        return 0;
    }

    /* Fall back to the preferred device */
//针对smi_infos list上合法的smi_info 调用try_smi_init 继续初始化.
    list_for_each_entry(e, &smi_infos, link) {
        if (!e->irq && (!type || e->addr_source == type)) {
            if (!try_smi_init(e)) {
                type = e->addr_source;
            }
        }
    }
    mutex_unlock(&smi_infos_lock);

    if (type)
        return 0;

    mutex_lock(&smi_infos_lock);
    if (unload_when_empty && list_empty(&smi_infos)) {
        mutex_unlock(&smi_infos_lock);
        cleanup_ipmi_si();
        printk(KERN_WARNING PFX
               "Unable to find any System Interface(s)\n");
        return -ENODEV;
    } else {
        mutex_unlock(&smi_infos_lock);
        return 0;
    }
}
module_init(init_ipmi_si);
总的来说ipmi driver是和BMC通信的interface。在init_ipmi_si中先判断ipmi是挂在哪种总线上,可以选的总线有platform/pci。然后字符串si_type_str 中判断si_type,可以选的有三种SI_KCS/SI_SMIC/SI_BT,然后再以hardcode的方式检测是否有BMC,如果有的话,在分别通过DMI/ACPI来查看bmc的信息。最后针对smi_infos 合法的smi_info调用调用try_smi_init 继续初始化.
下来看看如果通过hardcode的方式发现BMC的
static int hardcode_find_bmc(void)
{
    int ret = -ENODEV;
    int             i;
    struct smi_info *info;

    for (i = 0; i < SI_MAX_PARMS; i++) {
        if (!ports[i] && !addrs[i])
            continue;

        info = smi_info_alloc();
        if (!info)
            return -ENOMEM;

        info->addr_source = SI_HARDCODED;
        printk(KERN_INFO PFX "probing via hardcoded address\n");

        if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
            info->si_type = SI_KCS;
        } else if (strcmp(si_type[i], "smic") == 0) {
            info->si_type = SI_SMIC;
        } else if (strcmp(si_type[i], "bt") == 0) {
            info->si_type = SI_BT;
        } else {
            printk(KERN_WARNING PFX "Interface type specified "
                   "for interface %d, was invalid: %s\n",
                   i, si_type[i]);
            kfree(info);
            continue;
        }

        if (ports[i]) {
            /* An I/O port */
            info->io_setup = port_setup;
            info->io.addr_data = ports[i];
            info->io.addr_type = IPMI_IO_ADDR_SPACE;
        } else if (addrs[i]) {
            /* A memory port */
            info->io_setup = mem_setup;
            info->io.addr_data = addrs[i];
            info->io.addr_type = IPMI_MEM_ADDR_SPACE;
        } else {
            printk(KERN_WARNING PFX "Interface type specified "
                   "for interface %d, but port and address were "
                   "not set or set to zero.\n", i);
            kfree(info);
            continue;
        }

        info->io.addr = NULL;
        info->io.regspacing = regspacings[i];
        if (!info->io.regspacing)
            info->io.regspacing = DEFAULT_REGSPACING;
        info->io.regsize = regsizes[i];
        if (!info->io.regsize)
            info->io.regsize = DEFAULT_REGSPACING;
        info->io.regshift = regshifts[i];
        info->irq = irqs[i];
        if (info->irq)
            info->irq_setup = std_irq_setup;
        info->slave_addr = slave_addrs[i];
//前面都是按照和BMC通讯的协议赋值,重点是add_smi 返回0,调用try_smi_init来发现BMC的
        if (!add_smi(info)) {
            if (try_smi_init(info))
                cleanup_one_si(info);
            ret = 0;
        } else {
            kfree(info);
        }
    }
    return ret;
}
static int add_smi(struct smi_info *new_smi)
{
    int rv = 0;

    printk(KERN_INFO PFX "Adding %s-specified %s state machine",
           ipmi_addr_src_to_str(new_smi->addr_source),
           si_to_str[new_smi->si_type]);
    mutex_lock(&smi_infos_lock);

    if (!is_new_interface(new_smi)) {
        printk(KERN_CONT " duplicate interface\n");
        rv = -EBUSY;
        goto out_err;
    }

    printk(KERN_CONT "\n");

    /* So we know not to free it unless we have allocated one. */
    new_smi->intf = NULL;
    new_smi->si_sm = NULL;
    new_smi->handlers = NULL;

    list_add_tail(&new_smi->link, &smi_infos);

out_err:
    mutex_unlock(&smi_infos_lock);
    return rv;
}
由于是第一次,所以is_new_interface 返回1,因此在add_smi中最终返回0,并把smi_info *new_smi 添加到smi_infos lise中,从这里知道原来smi_infos 中的成员都是通过add_smi 添加的,在try_smi_init 中最终是通过
    if (new_smi->handlers->detect(new_smi->si_sm)) {
        if (new_smi->addr_source)
            printk(KERN_INFO PFX "Interface detection failed\n");
        rv = -ENODEV;
        goto out_err;
    }
来检测是否有BMC的。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值