⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipmi_si_intf.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
static void mem_outb(struct si_sm_io *io, unsigned int offset,		     unsigned char b){	writeb(b, (io->addr)+(offset * io->regspacing));}static unsigned char mem_inw(struct si_sm_io *io, unsigned int offset){	return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)		&& 0xff;}static void mem_outw(struct si_sm_io *io, unsigned int offset,		     unsigned char b){	writeb(b << io->regshift, (io->addr)+(offset * io->regspacing));}static unsigned char mem_inl(struct si_sm_io *io, unsigned int offset){	return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)		&& 0xff;}static void mem_outl(struct si_sm_io *io, unsigned int offset,		     unsigned char b){	writel(b << io->regshift, (io->addr)+(offset * io->regspacing));}#ifdef readqstatic unsigned char mem_inq(struct si_sm_io *io, unsigned int offset){	return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift)		&& 0xff;}static void mem_outq(struct si_sm_io *io, unsigned int offset,		     unsigned char b){	writeq(b << io->regshift, (io->addr)+(offset * io->regspacing));}#endifstatic void mem_cleanup(struct smi_info *info){	unsigned long *addr = info->io.info;	int           mapsize;	if (info->io.addr) {		iounmap(info->io.addr);		mapsize = ((info->io_size * info->io.regspacing)			   - (info->io.regspacing - info->io.regsize));		release_mem_region(*addr, mapsize);	}	kfree(info);}static int mem_setup(struct smi_info *info){	unsigned long *addr = info->io.info;	int           mapsize;	if (!addr || (!*addr))		return -ENODEV;	info->io_cleanup = mem_cleanup;	/* Figure out the actual readb/readw/readl/etc routine to use based	   upon the register size. */	switch (info->io.regsize) {	case 1:		info->io.inputb = mem_inb;		info->io.outputb = mem_outb;		break;	case 2:		info->io.inputb = mem_inw;		info->io.outputb = mem_outw;		break;	case 4:		info->io.inputb = mem_inl;		info->io.outputb = mem_outl;		break;#ifdef readq	case 8:		info->io.inputb = mem_inq;		info->io.outputb = mem_outq;		break;#endif	default:		printk("ipmi_si: Invalid register size: %d\n",		       info->io.regsize);		return -EINVAL;	}	/* Calculate the total amount of memory to claim.  This is an	 * unusual looking calculation, but it avoids claiming any	 * more memory than it has to.  It will claim everything	 * between the first address to the end of the last full	 * register. */	mapsize = ((info->io_size * info->io.regspacing)		   - (info->io.regspacing - info->io.regsize));	if (request_mem_region(*addr, mapsize, DEVICE_NAME) == NULL)		return -EIO;	info->io.addr = ioremap(*addr, mapsize);	if (info->io.addr == NULL) {		release_mem_region(*addr, mapsize);		return -EIO;	}	return 0;}static int try_init_mem(int intf_num, struct smi_info **new_info){	struct smi_info *info;	if (!addrs[intf_num])		return -ENODEV;	if (!is_new_interface(intf_num, IPMI_MEM_ADDR_SPACE,			      addrs[intf_num]))		return -ENODEV;	info = kmalloc(sizeof(*info), GFP_KERNEL);	if (!info) {		printk(KERN_ERR "ipmi_si: Could not allocate SI data (2)\n");		return -ENOMEM;	}	memset(info, 0, sizeof(*info));	info->io_setup = mem_setup;	info->io.info = &addrs[intf_num];	info->io.addr = NULL;	info->io.regspacing = regspacings[intf_num];	if (!info->io.regspacing)		info->io.regspacing = DEFAULT_REGSPACING;	info->io.regsize = regsizes[intf_num];	if (!info->io.regsize)		info->io.regsize = DEFAULT_REGSPACING;	info->io.regshift = regshifts[intf_num];	info->irq = 0;	info->irq_setup = NULL;	*new_info = info;	if (si_type[intf_num] == NULL)		si_type[intf_num] = "kcs";	printk("ipmi_si: Trying \"%s\" at memory address 0x%lx\n",	       si_type[intf_num], addrs[intf_num]);	return 0;}#ifdef CONFIG_ACPI_INTERPRETER#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 = 0;/* 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);	if (smi_info->stop_operation)		goto out;#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); out:	spin_unlock_irqrestore(&(smi_info->si_lock), flags);	return ACPI_INTERRUPT_HANDLED;}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 {		printk("  Using ACPI GPE %d\n", info->irq);		return 0;	}}static void acpi_gpe_irq_cleanup(struct smi_info *info){	if (!info->irq)		return;	acpi_remove_gpe_handler(NULL, info->irq, &ipmi_acpi_gpe);}/* * 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 int try_init_acpi(int intf_num, struct smi_info **new_info){	struct smi_info  *info;	acpi_status      status;	struct SPMITable *spmi;	char             *io_type;	u8 		 addr_space;	if (acpi_failure)		return -ENODEV;	status = acpi_get_firmware_table("SPMI", intf_num+1,					 ACPI_LOGICAL_ADDRESSING,					 (struct acpi_table_header **) &spmi);	if (status != AE_OK) {		acpi_failure = 1;		return -ENODEV;	}	if (spmi->IPMIlegacy != 1) {	    printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy);  	    return -ENODEV;	}	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)		addr_space = IPMI_MEM_ADDR_SPACE;	else		addr_space = IPMI_IO_ADDR_SPACE;	if (!is_new_interface(-1, addr_space, spmi->addr.address))		return -ENODEV;	/* Figure out the interface type. */	switch (spmi->InterfaceType)	{	case 1:	/* KCS */		si_type[intf_num] = "kcs";		break;	case 2:	/* SMIC */		si_type[intf_num] = "smic";		break;	case 3:	/* BT */		si_type[intf_num] = "bt";		break;	default:		printk(KERN_INFO "ipmi_si: Unknown ACPI/SPMI SI type %d\n",			spmi->InterfaceType);		return -EIO;	}	info = kmalloc(sizeof(*info), GFP_KERNEL);	if (!info) {		printk(KERN_ERR "ipmi_si: Could not allocate SI data (3)\n");		return -ENOMEM;	}	memset(info, 0, sizeof(*info));	if (spmi->InterruptType & 1) {		/* We've got a GPE interrupt. */		info->irq = spmi->GPE;		info->irq_setup = acpi_gpe_irq_setup;		info->irq_cleanup = acpi_gpe_irq_cleanup;	} else if (spmi->InterruptType & 2) {		/* We've got an APIC/SAPIC interrupt. */		info->irq = spmi->GlobalSystemInterrupt;		info->irq_setup = std_irq_setup;		info->irq_cleanup = std_irq_cleanup;	} else {		/* Use the default interrupt setting. */		info->irq = 0;		info->irq_setup = NULL;	}	regspacings[intf_num] = spmi->addr.register_bit_width / 8;	info->io.regspacing = spmi->addr.register_bit_width / 8;	regsizes[intf_num] = regspacings[intf_num];	info->io.regsize = regsizes[intf_num];	regshifts[intf_num] = spmi->addr.register_bit_offset;	info->io.regshift = regshifts[intf_num];	if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {		io_type = "memory";		info->io_setup = mem_setup;		addrs[intf_num] = spmi->addr.address;		info->io.info = &(addrs[intf_num]);	} else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {		io_type = "I/O";		info->io_setup = port_setup;		ports[intf_num] = spmi->addr.address;		info->io.info = &(ports[intf_num]);	} else {		kfree(info);		printk("ipmi_si: Unknown ACPI I/O Address type\n");		return -EIO;	}	*new_info = info;	printk("ipmi_si: ACPI/SPMI specifies \"%s\" %s SI @ 0x%lx\n",	       si_type[intf_num], io_type, (unsigned long) spmi->addr.address);	return 0;}#endif#ifdef CONFIG_X86typedef struct dmi_ipmi_data{	u8   		type;	u8   		addr_space;	unsigned long	base_addr;	u8   		irq;	u8              offset;}dmi_ipmi_data_t;typedef struct dmi_header{	u8	type;	u8	length;	u16	handle;}dmi_header_t;static int decode_dmi(dmi_header_t *dm, dmi_ipmi_data_t *ipmi_data){	u8		*data = (u8 *)dm;	unsigned long  	base_addr;	u8		reg_spacing;	u8              len = dm->length;	ipmi_data->type = data[4];	memcpy(&base_addr, data+8, sizeof(unsigned long));	if (len >= 0x11) {		if (base_addr & 1) {			/* I/O */			base_addr &= 0xFFFE;			ipmi_data->addr_space = IPMI_IO_ADDR_SPACE;		}		else {			/* Memory */			ipmi_data->addr_space = IPMI_MEM_ADDR_SPACE;		}		/* If bit 4 of byte 0x10 is set, then the lsb for the address		   is odd. */		ipmi_data->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);		ipmi_data->irq = data[0x11];		/* The top two bits of byte 0x10 hold the register spacing. */		reg_spacing = (data[0x10] & 0xC0) >> 6;		switch(reg_spacing){		case 0x00: /* Byte boundaries */		    ipmi_data->offset = 1;		    break;		case 0x01: /* 32-bit boundaries */		    ipmi_data->offset = 4;		    break;		case 0x02: /* 16-byte boundaries */		    ipmi_data->offset = 16;		    break;		default:		    /* Some other interface, just ignore it. */		    return -EIO;		}	} else {		/* Old DMI spec. */		ipmi_data->base_addr = base_addr;		ipmi_data->addr_space = IPMI_IO_ADDR_SPACE;		ipmi_data->offset = 1;	}	if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr))		return 0;	memset(ipmi_data, 0, sizeof(dmi_ipmi_data_t));	return -1;}static int dmi_table(u32 base, int len, int num,	dmi_ipmi_data_t *ipmi_data){	u8 		  *buf;	struct dmi_header *dm;	u8 		  *data;	int 		  i=1;	int		  status=-1;	buf = ioremap(base, len);	if(buf==NULL)		return -1;	data = buf;	while(i<num && (data - buf) < len)	{		dm=(dmi_header_t *)data;		if((data-buf+dm->length) >= len)        		break;		if (dm->type == 38) {			if (decode_dmi(dm, ipmi_data) == 0) {				status = 0;				break;			}		}	        data+=dm->length;		while((data-buf) < len && (*data || data[1]))			data++;		data+=2;		i++;	}	iounmap(buf);	return status;}inline static int dmi_checksum(u8 *buf){	u8   sum=0;	int  a;	for(a=0; a<15; a++)		sum+=buf[a];	return (sum==0);}static int dmi_iterator(dmi_ipmi_data_t *ipmi_data){	u8   buf[15];	u32  fp=0xF0000;#ifdef CONFIG_SIMNOW	return -1;#endif	while(fp < 0xFFFFF)	{		isa_memcpy_fromio(buf, fp, 15);		if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))		{			u16 num=buf[13]<<8|buf[12];			u16 len=buf[7]<<8|buf[6];			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];			if(dmi_table(base, len, num, ipmi_data) == 0)				return 0;		}		fp+=16;	}	return -1;}static int try_init_smbios(int intf_num, struct smi_info **new_info){	struct smi_info   *info;	dmi_ipmi_data_t   ipmi_data;	char              *io_type;	int               status;	status = dmi_iterator(&ipmi_data);	if (status < 0)		return -ENODEV;	switch(ipmi_data.type) {		case 0x01: /* KCS */			si_type[intf_num] = "kcs";			break;		case 0x02: /* SMIC */			si_type[intf_num] = "smic";			break;		case 0x03: /* BT */			si_type[intf_num] = "bt";			break;		default:			printk("ipmi_si: Unknown SMBIOS SI type.\n");			return -EIO;	}	info = kmalloc(sizeof(*info), GFP_KERNEL);	if (!info) {		printk(KERN_ERR "ipmi_si: Could not allocate SI data (4)\n");		return -ENOMEM;	}	memset(info, 0, sizeof(*info));	if (ipmi_data.addr_space == 1) {		io_type = "memory";		info->io_setup = mem_setup;		addrs[intf_num] = ipmi_data.base_addr;		info->io.info = &(addrs[intf_num]);	} else if (ipmi_data.addr_space == 2) {		io_type = "I/O";		info->io_setup = port_setup;		ports[intf_num] = ipmi_data.base_addr;		info->io.info = &(ports[intf_num]);	} else {		kfree(info);		printk("ipmi_si: Unknown SMBIOS I/O Address type.\n");		return -EIO;	}	regspacings[intf_num] = ipmi_data.offset;	info->io.regspacing = regspacings[intf_num];	if (!info->io.regspacing)		info->io.regspacing = DEFAULT_REGSPACING;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -