ipmi_si_intf.c
来自「linux 内核源代码」· C语言 代码 · 共 2,489 行 · 第 1/5 页
C
2,489 行
{ char *n; if (strcmp(curr, name) == 0) { if (!option) { printk(KERN_WARNING PFX "No option given for '%s'\n", curr); return -EINVAL; } *val = simple_strtoul(option, &n, 0); if ((*n != '\0') || (*option == '\0')) { printk(KERN_WARNING PFX "Bad option given for '%s'\n", curr); return -EINVAL; } return 1; } return 0;}static int hotmod_handler(const char *val, struct kernel_param *kp){ char *str = kstrdup(val, GFP_KERNEL); int rv; char *next, *curr, *s, *n, *o; enum hotmod_op op; enum si_type si_type; int addr_space; unsigned long addr; int regspacing; int regsize; int regshift; int irq; int ipmb; int ival; int len; struct smi_info *info; if (!str) return -ENOMEM; /* Kill any trailing spaces, as we can get a "\n" from echo. */ len = strlen(str); ival = len - 1; while ((ival >= 0) && isspace(str[ival])) { str[ival] = '\0'; ival--; } for (curr = str; curr; curr = next) { regspacing = 1; regsize = 1; regshift = 0; irq = 0; ipmb = 0x20; next = strchr(curr, ':'); if (next) { *next = '\0'; next++; } rv = parse_str(hotmod_ops, &ival, "operation", &curr); if (rv) break; op = ival; rv = parse_str(hotmod_si, &ival, "interface type", &curr); if (rv) break; si_type = ival; rv = parse_str(hotmod_as, &addr_space, "address space", &curr); if (rv) break; s = strchr(curr, ','); if (s) { *s = '\0'; s++; } addr = simple_strtoul(curr, &n, 0); if ((*n != '\0') || (*curr == '\0')) { printk(KERN_WARNING PFX "Invalid hotmod address" " '%s'\n", curr); break; } while (s) { curr = s; s = strchr(curr, ','); if (s) { *s = '\0'; s++; } o = strchr(curr, '='); if (o) { *o = '\0'; o++; } rv = check_hotmod_int_op(curr, o, "rsp", ®spacing); if (rv < 0) goto out; else if (rv) continue; rv = check_hotmod_int_op(curr, o, "rsi", ®size); if (rv < 0) goto out; else if (rv) continue; rv = check_hotmod_int_op(curr, o, "rsh", ®shift); if (rv < 0) goto out; else if (rv) continue; rv = check_hotmod_int_op(curr, o, "irq", &irq); if (rv < 0) goto out; else if (rv) continue; rv = check_hotmod_int_op(curr, o, "ipmb", &ipmb); if (rv < 0) goto out; else if (rv) continue; rv = -EINVAL; printk(KERN_WARNING PFX "Invalid hotmod option '%s'\n", curr); goto out; } if (op == HM_ADD) { info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { rv = -ENOMEM; goto out; } info->addr_source = "hotmod"; info->si_type = si_type; info->io.addr_data = addr; info->io.addr_type = addr_space; if (addr_space == IPMI_MEM_ADDR_SPACE) info->io_setup = mem_setup; else info->io_setup = port_setup; info->io.addr = NULL; info->io.regspacing = regspacing; if (!info->io.regspacing) info->io.regspacing = DEFAULT_REGSPACING; info->io.regsize = regsize; if (!info->io.regsize) info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = regshift; info->irq = irq; if (info->irq) info->irq_setup = std_irq_setup; info->slave_addr = ipmb; try_smi_init(info); } else { /* remove */ struct smi_info *e, *tmp_e; mutex_lock(&smi_infos_lock); list_for_each_entry_safe(e, tmp_e, &smi_infos, link) { if (e->io.addr_type != addr_space) continue; if (e->si_type != si_type) continue; if (e->io.addr_data == addr) cleanup_one_si(e); } mutex_unlock(&smi_infos_lock); } } rv = len; out: kfree(str); return rv;}static __devinit void hardcode_find_bmc(void){ int i; struct smi_info *info; for (i = 0; i < SI_MAX_PARMS; i++) { if (!ports[i] && !addrs[i]) continue; info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return; info->addr_source = "hardcoded"; 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 "ipmi_si: 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 "ipmi_si: 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; try_smi_init(info); }}#ifdef CONFIG_ACPI#include <linux/acpi.h>/* Once we get an ACPI failure, we don't try any more, because we go through the tables sequentially. Once we don't find a table, there are no more. */static int acpi_failure;/* For GPE-type interrupts. */static u32 ipmi_acpi_gpe(void *context){ struct smi_info *smi_info = context; unsigned long flags;#ifdef DEBUG_TIMING struct timeval t;#endif spin_lock_irqsave(&(smi_info->si_lock), flags); spin_lock(&smi_info->count_lock); smi_info->interrupts++; spin_unlock(&smi_info->count_lock);#ifdef DEBUG_TIMING do_gettimeofday(&t); printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec);#endif smi_event_handler(smi_info, 0); spin_unlock_irqrestore(&(smi_info->si_lock), flags); return ACPI_INTERRUPT_HANDLED;}static void acpi_gpe_irq_cleanup(struct smi_info *info){ if (!info->irq) return; acpi_remove_gpe_handler(NULL, info->irq, &ipmi_acpi_gpe);}static int acpi_gpe_irq_setup(struct smi_info *info){ acpi_status status; if (!info->irq) return 0; /* FIXME - is level triggered right? */ status = acpi_install_gpe_handler(NULL, info->irq, ACPI_GPE_LEVEL_TRIGGERED, &ipmi_acpi_gpe, info); if (status != AE_OK) { printk(KERN_WARNING "ipmi_si: %s unable to claim ACPI GPE %d," " running polled\n", DEVICE_NAME, info->irq); info->irq = 0; return -EINVAL; } else { info->irq_cleanup = acpi_gpe_irq_cleanup; printk(" Using ACPI GPE %d\n", info->irq); return 0; }}/* * Defined at * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/Docs/TechPapers/IA64/hpspmi.pdf */struct SPMITable { s8 Signature[4]; u32 Length; u8 Revision; u8 Checksum; s8 OEMID[6]; s8 OEMTableID[8]; s8 OEMRevision[4]; s8 CreatorID[4]; s8 CreatorRevision[4]; u8 InterfaceType; u8 IPMIlegacy; s16 SpecificationRevision; /* * Bit 0 - SCI interrupt supported * Bit 1 - I/O APIC/SAPIC */ u8 InterruptType; /* If bit 0 of InterruptType is set, then this is the SCI interrupt in the GPEx_STS register. */ u8 GPE; s16 Reserved; /* If bit 1 of InterruptType is set, then this is the I/O APIC/SAPIC interrupt. */ u32 GlobalSystemInterrupt; /* The actual register address. */ struct acpi_generic_address addr; u8 UID[4]; s8 spmi_id[1]; /* A '\0' terminated array starts here. */};static __devinit int try_init_acpi(struct SPMITable *spmi){ struct smi_info *info; u8 addr_space; if (spmi->IPMIlegacy != 1) { printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy); return -ENODEV; } if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) addr_space = IPMI_MEM_ADDR_SPACE; else addr_space = IPMI_IO_ADDR_SPACE; info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n"); return -ENOMEM; } info->addr_source = "ACPI"; /* Figure out the interface type. */ switch (spmi->InterfaceType) { case 1: /* KCS */ info->si_type = SI_KCS; break; case 2: /* SMIC */ info->si_type = SI_SMIC; break; case 3: /* BT */ info->si_type = SI_BT; break; default: printk(KERN_INFO "ipmi_si: Unknown ACPI/SPMI SI type %d\n", spmi->InterfaceType); kfree(info); return -EIO; } if (spmi->InterruptType & 1) { /* We've got a GPE interrupt. */ info->irq = spmi->GPE; info->irq_setup = acpi_gpe_irq_setup; } else if (spmi->InterruptType & 2) { /* We've got an APIC/SAPIC interrupt. */ info->irq = spmi->GlobalSystemInterrupt; info->irq_setup = std_irq_setup; } else { /* Use the default interrupt setting. */ info->irq = 0; info->irq_setup = NULL; } if (spmi->addr.bit_width) { /* A (hopefully) properly formed register bit width. */ info->io.regspacing = spmi->addr.bit_width / 8; } else { info->io.regspacing = DEFAULT_REGSPACING; } info->io.regsize = info->io.regspacing; info->io.regshift = spmi->addr.bit_offset; if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { info->io_setup = mem_setup; info->io.addr_type = IPMI_MEM_ADDR_SPACE; } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) { info->io_setup = port_setup; info->io.addr_type = IPMI_IO_ADDR_SPACE; } else { kfree(info); printk("ipmi_si: Unknown ACPI I/O Address type\n"); return -EIO; } info->io.addr_data = spmi->addr.address; try_smi_init(info); return 0;}static __devinit void acpi_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_acpi(spmi); }}#endif#ifdef CONFIG_DMIstruct dmi_ipmi_data{ u8 type; u8 addr_space; unsigned long base_addr; u8 irq; u8 offset; u8 slave_addr;};static int __devinit decode_dmi(const struct dmi_header *dm, struct dmi_ipmi_data *dmi){ const u8 *data = (const u8 *)dm; unsigned long base_addr; u8 reg_spacing; u8 len = dm->length; dmi->type = data[4]; memcpy(&base_addr, data+8, sizeof(unsigned long)); if (len >= 0x11) { if (base_addr & 1) { /* I/O */ base_addr &= 0xFFFE; dmi->addr_space = IPMI_IO_ADDR_SPACE; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?