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

📄 ipmi_si_intf.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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 (atomic_read(&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_disabled)		return -ENODEV;	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;	if (! spmi->addr.register_bit_width) {		acpi_failure = 1;		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;	}	if (spmi->addr.register_bit_width) {		/* A (hopefully) properly formed register bit width. */		regspacings[intf_num] = spmi->addr.register_bit_width / 8;		info->io.regspacing = spmi->addr.register_bit_width / 8;	} else {		/* Some broken systems get this wrong and set the value		 * to zero.  Assume it is the default spacing.  If that		 * is wrong, too bad, the vendor should fix the tables. */		regspacings[intf_num] = DEFAULT_REGSPACING;		info->io.regspacing = DEFAULT_REGSPACING;	}	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;	u8              slave_addr;} dmi_ipmi_data_t;static dmi_ipmi_data_t dmi_data[SI_MAX_DRIVERS];static int dmi_data_entries;static int __init decode_dmi(struct dmi_header *dm, int intf_num){	u8              *data = (u8 *)dm;	unsigned long  	base_addr;	u8		reg_spacing;	u8              len = dm->length;	dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;	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. */		/* Note that technically, the lower bit of the base		 * address should be 1 if the address is I/O and 0 if		 * the address is in memory.  So many systems get that		 * wrong (and all that I have seen are I/O) so we just		 * ignore that bit and assume I/O.  Systems that use		 * memory should use the newer spec, anyway. */		ipmi_data->base_addr = base_addr & 0xfffe;		ipmi_data->addr_space = IPMI_IO_ADDR_SPACE;		ipmi_data->offset = 1;	}	ipmi_data->slave_addr = data[6];	if (is_new_interface(-1, ipmi_data->addr_space,ipmi_data->base_addr)) {		dmi_data_entries++;		return 0;	}	memset(ipmi_data, 0, sizeof(dmi_ipmi_data_t));	return -1;}static void __init dmi_find_bmc(void){	struct dmi_device *dev = NULL;	int               intf_num = 0;	while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {		if (intf_num >= SI_MAX_DRIVERS)			break;		decode_dmi((struct dmi_header *) dev->device_data, intf_num++);	}}static int try_init_smbios(int intf_num, struct smi_info **new_info){	struct smi_info *info;	dmi_ipmi_data_t *ipmi_data = dmi_data+intf_num;	char            *io_type;	if (intf_num >= dmi_data_entries)		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:			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;	info->io.regsize = DEFAULT_REGSPACING;	info->io.regshift = regshifts[intf_num];	info->slave_addr = ipmi_data->slave_addr;	irqs[intf_num] = ipmi_data->irq;	*new_info = info;	printk("ipmi_si: Found SMBIOS-specified state machine at %s"	       " address 0x%lx, slave address 0x%x\n",	       io_type, (unsigned long)ipmi_data->base_addr,	       ipmi_data->slave_addr);	return 0;}#endif /* CONFIG_X86 */#ifdef CONFIG_PCI#define PCI_ERMC_CLASSCODE  0x0C0700#define PCI_HP_VENDOR_ID    0x103C#define PCI_MMC_DEVICE_ID   0x121A#define PCI_MMC_ADDR_CW     0x10/* Avoid more than one attempt to probe pci smic. */static int pci_smic_checked = 0;static int find_pci_smic(int intf_num, struct smi_info **new_info){	struct smi_info  *info;	int              error;	struct pci_dev   *pci_dev = NULL;	u16    		 base_addr;	int              fe_rmc = 0;	if (pci_smic_checked)		return -ENODEV;	pci_smic_checked = 1;	pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID, NULL);	if (! pci_dev) {		pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL);		if (pci_dev && (pci_dev->subsystem_vendor == PCI_HP_VENDOR_ID))			fe_rmc = 1;		else			return -ENODEV;	}	error = pci_read_config_word(pci_dev, PCI_MMC_ADDR_CW, &base_addr);	if (error)	{		pci_dev_put(pci_dev);		printk(KERN_ERR		       "ipmi_si: pci_read_config_word() failed (%d).\n",		       error);		return -ENODEV;	}	/* Bit 0: 1 specifies programmed I/O, 0 specifies memory mapped I/O */	if (! (base_addr & 0x0001))	{		pci_dev_put(pci_dev);		printk(KERN_ERR		       "ipmi_si: memory mapped I/O not supported for PCI"		       " smic.\n");		return -ENODEV;	}	base_addr &= 0xFFFE;	if (! fe_rmc)		/* Data register starts at base address + 1 in eRMC */		++base_addr;	if (! is_new_interface(-1, IPMI_IO_ADDR_SPACE, base_addr)) {		pci_dev_put(pci_dev);		return -ENODEV;	}	info = kmalloc(sizeof(*info), GFP_KERNEL);	if (! info) {		pci_dev_put(pci_dev);		printk(KERN_ERR "ipmi_si: Could not allocate SI data (5)\n");		return -ENOMEM;	}	memset(info, 0, sizeof(*info));	info->io_setup = port_setup;	ports[intf_num] = base_addr;	info->io.info = &(ports[intf_num]);	info->io.regspacing = regspacings[intf_num];	if (! info->io.regspacing)		info->io.regspacing = DEFAULT_REGSPACING;	info->io.regsize = DEFAULT_REGSPACING;	info->io.regshift = regshifts[intf_num];	*new_info = info;	irqs[intf_num] = pci_dev->irq;	si_type[intf_num] = "smic";

⌨️ 快捷键说明

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