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", &regspacing);			if (rv < 0)				goto out;			else if (rv)				continue;			rv = check_hotmod_int_op(curr, o, "rsi", &regsize);			if (rv < 0)				goto out;			else if (rv)				continue;			rv = check_hotmod_int_op(curr, o, "rsh", &regshift);			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 + -
显示快捷键?