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

📄 ipmi_si_intf.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
	info->io.regsize = DEFAULT_REGSPACING;	info->io.regshift = regshifts[intf_num];	irqs[intf_num] = ipmi_data.irq;	*new_info = info;	printk("ipmi_si: Found SMBIOS-specified state machine at %s"	       " address 0x%lx\n",	       io_type, (unsigned long)ipmi_data.base_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;	if ((pci_dev = pci_get_device(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID,				       NULL)))		;	else if ((pci_dev = pci_get_class(PCI_ERMC_CLASSCODE, NULL)) &&		 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";	printk("ipmi_si: Found PCI SMIC at I/O address 0x%lx\n",		(long unsigned int) base_addr);	pci_dev_put(pci_dev);	return 0;}#endif /* CONFIG_PCI */static int try_init_plug_and_play(int intf_num, struct smi_info **new_info){#ifdef CONFIG_PCI	if (find_pci_smic(intf_num, new_info)==0)		return 0;#endif	/* Include other methods here. */	return -ENODEV;}static int try_get_dev_id(struct smi_info *smi_info){	unsigned char      msg[2];	unsigned char      *resp;	unsigned long      resp_len;	enum si_sm_result smi_result;	int               rv = 0;	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);	if (!resp)		return -ENOMEM;	/* Do a Get Device ID command, since it comes back with some	   useful info. */	msg[0] = IPMI_NETFN_APP_REQUEST << 2;	msg[1] = IPMI_GET_DEVICE_ID_CMD;	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);	smi_result = smi_info->handlers->event(smi_info->si_sm, 0);	for (;;)	{		if (smi_result == SI_SM_CALL_WITH_DELAY) {			set_current_state(TASK_UNINTERRUPTIBLE);			schedule_timeout(1);			smi_result = smi_info->handlers->event(				smi_info->si_sm, 100);		}		else if (smi_result == SI_SM_CALL_WITHOUT_DELAY)		{			smi_result = smi_info->handlers->event(				smi_info->si_sm, 0);		}		else			break;	}	if (smi_result == SI_SM_HOSED) {		/* We couldn't get the state machine to run, so whatever's at		   the port is probably not an IPMI SMI interface. */		rv = -ENODEV;		goto out;	}	/* Otherwise, we got some data. */	resp_len = smi_info->handlers->get_result(smi_info->si_sm,						  resp, IPMI_MAX_MSG_LENGTH);	if (resp_len < 6) {		/* That's odd, it should be longer. */		rv = -EINVAL;		goto out;	}	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0)) {		/* That's odd, it shouldn't be able to fail. */		rv = -EINVAL;		goto out;	}	/* Record info from the get device id, in case we need it. */	smi_info->ipmi_si_dev_rev = resp[4] & 0xf;	smi_info->ipmi_si_fw_rev_major = resp[5] & 0x7f;	smi_info->ipmi_si_fw_rev_minor = resp[6];	smi_info->ipmi_version_major = resp[7] & 0xf;	smi_info->ipmi_version_minor = resp[7] >> 4; out:	kfree(resp);	return rv;}static int type_file_read_proc(char *page, char **start, off_t off,			       int count, int *eof, void *data){	char            *out = (char *) page;	struct smi_info *smi = data;	switch (smi->si_type) {	    case SI_KCS:		return sprintf(out, "kcs\n");	    case SI_SMIC:		return sprintf(out, "smic\n");	    case SI_BT:		return sprintf(out, "bt\n");	    default:		return 0;	}}static int stat_file_read_proc(char *page, char **start, off_t off,			       int count, int *eof, void *data){	char            *out = (char *) page;	struct smi_info *smi = data;	out += sprintf(out, "interrupts_enabled:    %d\n",		       smi->irq && !smi->interrupt_disabled);	out += sprintf(out, "short_timeouts:        %ld\n",		       smi->short_timeouts);	out += sprintf(out, "long_timeouts:         %ld\n",		       smi->long_timeouts);	out += sprintf(out, "timeout_restarts:      %ld\n",		       smi->timeout_restarts);	out += sprintf(out, "idles:                 %ld\n",		       smi->idles);	out += sprintf(out, "interrupts:            %ld\n",		       smi->interrupts);	out += sprintf(out, "attentions:            %ld\n",		       smi->attentions);	out += sprintf(out, "flag_fetches:          %ld\n",		       smi->flag_fetches);	out += sprintf(out, "hosed_count:           %ld\n",		       smi->hosed_count);	out += sprintf(out, "complete_transactions: %ld\n",		       smi->complete_transactions);	out += sprintf(out, "events:                %ld\n",		       smi->events);	out += sprintf(out, "watchdog_pretimeouts:  %ld\n",		       smi->watchdog_pretimeouts);	out += sprintf(out, "incoming_messages:     %ld\n",		       smi->incoming_messages);	return (out - ((char *) page));}/* Returns 0 if initialized, or negative on an error. */static int init_one_smi(int intf_num, struct smi_info **smi){	int		rv;	struct smi_info *new_smi;	rv = try_init_mem(intf_num, &new_smi);	if (rv)		rv = try_init_port(intf_num, &new_smi);#ifdef CONFIG_ACPI_INTERPRETER	if ((rv) && (si_trydefaults)) {		rv = try_init_acpi(intf_num, &new_smi);	}#endif#ifdef CONFIG_X86	if ((rv) && (si_trydefaults)) {		rv = try_init_smbios(intf_num, &new_smi);        }#endif	if ((rv) && (si_trydefaults)) {		rv = try_init_plug_and_play(intf_num, &new_smi);	}	if (rv)		return rv;	/* 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;	if (!new_smi->irq_setup) {		new_smi->irq = irqs[intf_num];		new_smi->irq_setup = std_irq_setup;		new_smi->irq_cleanup = std_irq_cleanup;	}	/* Default to KCS if no type is specified. */	if (si_type[intf_num] == NULL) {		if (si_trydefaults)			si_type[intf_num] = "kcs";		else {			rv = -EINVAL;			goto out_err;		}	}	/* Set up the state machine to use. */	if (strcmp(si_type[intf_num], "kcs") == 0) {		new_smi->handlers = &kcs_smi_handlers;		new_smi->si_type = SI_KCS;	} else if (strcmp(si_type[intf_num], "smic") == 0) {		new_smi->handlers = &smic_smi_handlers;		new_smi->si_type = SI_SMIC;	} else if (strcmp(si_type[intf_num], "bt") == 0) {		new_smi->handlers = &bt_smi_handlers;		new_smi->si_type = SI_BT;	} else {		/* No support for anything else yet. */		rv = -EIO;		goto out_err;	}	/* Allocate the state machine's data and initialize it. */	new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);	if (!new_smi->si_sm) {		printk(" Could not allocate state machine memory\n");		rv = -ENOMEM;		goto out_err;	}	new_smi->io_size = new_smi->handlers->init_data(new_smi->si_sm,							&new_smi->io);	/* Now that we know the I/O size, we can set up the I/O. */	rv = new_smi->io_setup(new_smi);	if (rv) {		printk(" Could not set up I/O space\n");		goto out_err;	}	spin_lock_init(&(new_smi->si_lock));	spin_lock_init(&(new_smi->msg_lock));	spin_lock_init(&(new_smi->count_lock));	/* Do low-level detection first. */	if (new_smi->handlers->detect(new_smi->si_sm)) {		rv = -ENODEV;		goto out_err;	}	/* Attempt a get device id command.  If it fails, we probably           don't have a SMI here. */	rv = try_get_dev_id(new_smi);	if (rv)		goto out_err;	/* Try to claim any interrupts. */	new_smi->irq_setup(new_smi);	INIT_LIST_HEAD(&(new_smi->xmit_msgs));	INIT_LIST_HEAD(&(new_smi->hp_xmit_msgs));	new_smi->curr_msg = NULL;	atomic_set(&new_smi->req_events, 0);	new_smi->run_to_completion = 0;	new_smi->interrupt_disabled = 0;	new_smi->timer_stopped = 0;	new_smi->stop_operation = 0;	/* Start clearing the flags before we enable interrupts or the	   timer to avoid racing with the timer. */	start_clear_flags(new_smi);	/* IRQ is defined to be set when non-zero. */	if (new_smi->irq)		new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ;	/* The ipmi_register_smi() code does some operations to	   determine the channel information, so we must be ready to	   handle operations before it is called.  This means we have	   to stop the timer if we get an error after this point. */	init_timer(&(new_smi->si_timer));	new_smi->si_timer.data = (long) new_smi;	new_smi->si_timer.function = smi_timeout;	new_smi->last_timeout_jiffies = jiffies;	new_smi->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;	add_timer(&(new_smi->si_timer));	rv = ipmi_register_smi(&handlers,			       new_smi,			       new_smi->ipmi_version_major,			       new_smi->ipmi_version_minor,			       &(new_smi->intf));	if (rv) {		printk(KERN_ERR		       "ipmi_si: Unable to register device: error %d\n",		       rv);		goto out_err_stop_timer;	}	rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",				     type_file_read_proc, NULL,				     new_smi, THIS_MODULE);	if (rv) {		printk(KERN_ERR		       "ipmi_si: Unable to create proc entry: %d\n",		       rv);		goto out_err_stop_timer;	}	rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",				     stat_file_read_proc, NULL,				     new_smi, THIS_MODULE);	if (rv) {		printk(KERN_ERR		       "ipmi_si: Unable to create proc entry: %d\n",		       rv);		goto out_err_stop_timer;	}	*smi = new_smi;	printk(" IPMI %s interface initialized\n", si_type[intf_num]);	return 0; out_err_stop_timer:	new_smi->stop_operation = 1;	/* Wait for the timer to stop.  This avoids problems with race	   conditions removing the timer here. */	while (!new_smi->timer_stopped) {		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(1);	} out_err:	if (new_smi->intf)		ipmi_unregister_smi(new_smi->intf);	new_smi->irq_cleanup(new_smi);	/* Wait until we know that we are out of any interrupt	   handlers might have been running before we freed the	   interrupt. */	synchronize_kernel();	if (new_smi->si_sm) {		if (new_smi->handlers)			new_smi->handlers->cleanup(new_smi->si_sm);		kfree(new_smi->si_sm);	}	new_smi->io_cleanup(new_smi);	return rv;}static __init int init_ipmi_si(void){	int  rv = 0;	int  pos = 0;	int  i;	char *str;	if (initialized)		return 0;	initialized = 1;	/* Parse out the si_type string into its components. */	str = si_type_str;	if (*str != '\0') {		for (i=0; (i<SI_MAX_PARMS) && (*str != '\0'); i++) {			si_type[i] = str;			str = strchr(str, ',');			if (str) {				*str = '\0';				str++;			} else {				break;			}		}	}	printk(KERN_INFO "IPMI System Interface driver version "	       IPMI_SI_VERSION);	if (kcs_smi_handlers.version)		printk(", KCS version %s", kcs_smi_handlers.version);	if (smic_smi_handlers.version)		printk(", SMIC version %s", smic_smi_handlers.version);	if (bt_smi_handlers.version)   	        printk(", BT version %s", bt_smi_handlers.version);	printk("\n");	rv = init_one_smi(0, &(smi_infos[pos]));	if (rv && !ports[0] && si_trydefaults) {		/* If we are trying defaults and the initial port is                   not set, then set it. */		si_type[0] = "kcs";		ports[0] = DEFAULT_KCS_IO_PORT;		rv = init_one_smi(0, &(smi_infos[pos]));		if (rv) {			/* No KCS - try SMIC */			si_type[0] = "smic";			ports[0] = DEFAULT_SMIC_IO_PORT;			rv = init_one_smi(0, &(smi_infos[pos]));		}		if (rv) {			/* No SMIC - try BT */			si_type[0] = "bt";			ports[0] = DEFAULT_BT_IO_PORT;			rv = init_one_smi(0, &(smi_infos[pos]));		}	}	if (rv == 0)		pos++;	for (i=1; i < SI_MAX_PARMS; i++) {		rv = init_one_smi(i, &(smi_infos[pos]));		if (rv == 0)			pos++;	}	if (smi_infos[0] == NULL) {		printk("ipmi_si: Unable to find any System Interface(s)\n");		return -ENODEV;	}	return 0;}module_init(init_ipmi_si);static void __exit cleanup_one_si(struct smi_info *to_clean){	int           rv;	unsigned long flags;	if (! to_clean)		return;	/* Tell the timer and interrupt handlers that we are shutting	   down. */	spin_lock_irqsave(&(to_clean->si_lock), flags);	spin_lock(&(to_clean->msg_lock));	to_clean->stop_operation = 1;	to_clean->irq_cleanup(to_clean);	spin_unlock(&(to_clean->msg_lock));	spin_unlock_irqrestore(&(to_clean->si_lock), flags);	/* Wait until we know that we are out of any interrupt	   handlers might have been running before we freed the	   interrupt. */	synchronize_kernel();	/* Wait for the timer to stop.  This avoids problems with race	   conditions removing the timer here. */	while (!to_clean->timer_stopped) {		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(1);	}	/* Interrupts and timeouts are stopped, now make sure the	   interface is in a clean state. */	while ((to_clean->curr_msg) || (to_clean->si_state != SI_NORMAL)) {		poll(to_clean);		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(1);	}	rv = ipmi_unregister_smi(to_clean->intf);	if (rv) {		printk(KERN_ERR		       "ipmi_si: Unable to unregister device: errno=%d\n",		       rv);	}	to_clean->handlers->cleanup(to_clean->si_sm);	kfree(to_clean->si_sm);	to_clean->io_cleanup(to_clean);}static __exit void cleanup_ipmi_si(void){	int i;	if (!initialized)		return;	for (i=0; i<SI_MAX_DRIVERS; i++) {		cleanup_one_si(smi_infos[i]);	}}module_exit(cleanup_ipmi_si);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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