当通过hardcode_find_bmc以hardcode的方式确定有bmc后,后面就要判断是通过DMI还是ACPI的方式来初始化smi_info添加到smi_infos 这个list中。
例如在init_ipmi_si 根据dmi初始化smi_info的函数为dmi_find_bmc
static void dmi_find_bmc(void)
{
const struct dmi_device *dev = NULL;
struct dmi_ipmi_data data;
int rv;
while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
memset(&data, 0, sizeof(data));
rv = decode_dmi((const struct dmi_header *) dev->device_data,
&data);
if (!rv)
try_init_dmi(&data);
}
}
可以看是通过dmi_find_device 来查找DMI_DEV_TYPE_IPMI,除此之外通过dmi_find_device 查找的其他设备如下:
enum dmi_device_type {
DMI_DEV_TYPE_ANY = 0,
DMI_DEV_TYPE_OTHER,
DMI_DEV_TYPE_UNKNOWN,
DMI_DEV_TYPE_VIDEO,
DMI_DEV_TYPE_SCSI,
DMI_DEV_TYPE_ETHERNET,
DMI_DEV_TYPE_TOKENRING,
DMI_DEV_TYPE_SOUND,
DMI_DEV_TYPE_PATA,
DMI_DEV_TYPE_SATA,
DMI_DEV_TYPE_SAS,
DMI_DEV_TYPE_IPMI = -1,
DMI_DEV_TYPE_OEM_STRING = -2,
DMI_DEV_TYPE_DEV_ONBOARD = -3,
DMI_DEV_TYPE_DEV_SLOT = -4,
};
在dmi_find_bmc 中如果找到设备后,就通过decode_dmi 将DMI_DEV_TYPE_IPMI的信息存在struct dmi_ipmi_data data中,然后调用try_init_dmi 初始化smi_info添加到smi_infos 这个list中
static void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
{
struct smi_info *info;
info = smi_info_alloc();
if (!info) {
printk(KERN_ERR PFX "Could not allocate SI data\n");
return;
}
info->addr_source = SI_SMBIOS;
printk(KERN_INFO PFX "probing via SMBIOS\n");
switch (ipmi_data->type) {
case 0x01: /* KCS */
info->si_type = SI_KCS;
break;
case 0x02: /* SMIC */
info->si_type = SI_SMIC;
break;
case 0x03: /* BT */
info->si_type = SI_BT;
break;
default:
kfree(info);
return;
}
switch (ipmi_data->addr_space) {
case IPMI_MEM_ADDR_SPACE:
info->io_setup = mem_setup;
info->io.addr_type = IPMI_MEM_ADDR_SPACE;
break;
case IPMI_IO_ADDR_SPACE:
info->io_setup = port_setup;
info->io.addr_type = IPMI_IO_ADDR_SPACE;
break;
default:
kfree(info);
printk(KERN_WARNING PFX "Unknown SMBIOS I/O Address type: %d\n",
ipmi_data->addr_space);
return;
}
info->io.addr_data = ipmi_data->base_addr;
info->io.regspacing = ipmi_data->offset;
if (!info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = 0;
info->slave_addr = ipmi_data->slave_addr;
info->irq = ipmi_data->irq;
if (info->irq)
info->irq_setup = std_irq_setup;
pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n",
(info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem",
info->io.addr_data, info->io.regsize, info->io.regspacing,
info->irq);
//前面是基本的赋值,这里调用add_smi添加到smi_infos 这个list中
if (add_smi(info))
kfree(info);
}
除了通过DMI外和可以通过APCI 其函数是spmi_find_bmc
static void spmi_find_bmc(void)
{
acpi_status status;
struct SPMITable *spmi;
int i;
if (acpi_disabled)
return;
if (acpi_failure)
return;
for (i = 0; ; i++) {
status = acpi_get_table(ACPI_SIG_SPMI, i+1,
(struct acpi_table_header **)&spmi);
if (status != AE_OK)
return;
try_init_spmi(spmi);
}
}
在spmi_find_bmc 中通过acpi_get_table得到ACPI_SIG_SPMI 表后,就调用try_init_spmi 来初始化smi_info调用add_smi添加到smi_infos 这个list中
再通过add_smi 将smi_info *new_smi 添加到smi_infos中时,先通过is_new_interface 是否已经添加
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 如下,可见主要是判断io的addr_type和addr_data
static int is_new_interface(struct smi_info *info)
{
struct smi_info *e;
list_for_each_entry(e, &smi_infos, link) {
if (e->io.addr_type != info->io.addr_type)
continue;
if (e->io.addr_data == info->io.addr_data)
return 0;
}
return 1;
}
例如在init_ipmi_si 根据dmi初始化smi_info的函数为dmi_find_bmc
static void dmi_find_bmc(void)
{
const struct dmi_device *dev = NULL;
struct dmi_ipmi_data data;
int rv;
while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
memset(&data, 0, sizeof(data));
rv = decode_dmi((const struct dmi_header *) dev->device_data,
&data);
if (!rv)
try_init_dmi(&data);
}
}
可以看是通过dmi_find_device 来查找DMI_DEV_TYPE_IPMI,除此之外通过dmi_find_device 查找的其他设备如下:
enum dmi_device_type {
DMI_DEV_TYPE_ANY = 0,
DMI_DEV_TYPE_OTHER,
DMI_DEV_TYPE_UNKNOWN,
DMI_DEV_TYPE_VIDEO,
DMI_DEV_TYPE_SCSI,
DMI_DEV_TYPE_ETHERNET,
DMI_DEV_TYPE_TOKENRING,
DMI_DEV_TYPE_SOUND,
DMI_DEV_TYPE_PATA,
DMI_DEV_TYPE_SATA,
DMI_DEV_TYPE_SAS,
DMI_DEV_TYPE_IPMI = -1,
DMI_DEV_TYPE_OEM_STRING = -2,
DMI_DEV_TYPE_DEV_ONBOARD = -3,
DMI_DEV_TYPE_DEV_SLOT = -4,
};
在dmi_find_bmc 中如果找到设备后,就通过decode_dmi 将DMI_DEV_TYPE_IPMI的信息存在struct dmi_ipmi_data data中,然后调用try_init_dmi 初始化smi_info添加到smi_infos 这个list中
static void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
{
struct smi_info *info;
info = smi_info_alloc();
if (!info) {
printk(KERN_ERR PFX "Could not allocate SI data\n");
return;
}
info->addr_source = SI_SMBIOS;
printk(KERN_INFO PFX "probing via SMBIOS\n");
switch (ipmi_data->type) {
case 0x01: /* KCS */
info->si_type = SI_KCS;
break;
case 0x02: /* SMIC */
info->si_type = SI_SMIC;
break;
case 0x03: /* BT */
info->si_type = SI_BT;
break;
default:
kfree(info);
return;
}
switch (ipmi_data->addr_space) {
case IPMI_MEM_ADDR_SPACE:
info->io_setup = mem_setup;
info->io.addr_type = IPMI_MEM_ADDR_SPACE;
break;
case IPMI_IO_ADDR_SPACE:
info->io_setup = port_setup;
info->io.addr_type = IPMI_IO_ADDR_SPACE;
break;
default:
kfree(info);
printk(KERN_WARNING PFX "Unknown SMBIOS I/O Address type: %d\n",
ipmi_data->addr_space);
return;
}
info->io.addr_data = ipmi_data->base_addr;
info->io.regspacing = ipmi_data->offset;
if (!info->io.regspacing)
info->io.regspacing = DEFAULT_REGSPACING;
info->io.regsize = DEFAULT_REGSPACING;
info->io.regshift = 0;
info->slave_addr = ipmi_data->slave_addr;
info->irq = ipmi_data->irq;
if (info->irq)
info->irq_setup = std_irq_setup;
pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n",
(info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem",
info->io.addr_data, info->io.regsize, info->io.regspacing,
info->irq);
//前面是基本的赋值,这里调用add_smi添加到smi_infos 这个list中
if (add_smi(info))
kfree(info);
}
除了通过DMI外和可以通过APCI 其函数是spmi_find_bmc
static void spmi_find_bmc(void)
{
acpi_status status;
struct SPMITable *spmi;
int i;
if (acpi_disabled)
return;
if (acpi_failure)
return;
for (i = 0; ; i++) {
status = acpi_get_table(ACPI_SIG_SPMI, i+1,
(struct acpi_table_header **)&spmi);
if (status != AE_OK)
return;
try_init_spmi(spmi);
}
}
在spmi_find_bmc 中通过acpi_get_table得到ACPI_SIG_SPMI 表后,就调用try_init_spmi 来初始化smi_info调用add_smi添加到smi_infos 这个list中
再通过add_smi 将smi_info *new_smi 添加到smi_infos中时,先通过is_new_interface 是否已经添加
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 如下,可见主要是判断io的addr_type和addr_data
static int is_new_interface(struct smi_info *info)
{
struct smi_info *e;
list_for_each_entry(e, &smi_infos, link) {
if (e->io.addr_type != info->io.addr_type)
continue;
if (e->io.addr_data == info->io.addr_data)
return 0;
}
return 1;
}