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

📄 ipmi_si_intf.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
		spin_lock(&smi_info->count_lock);		smi_info->hosed_count++;		spin_unlock(&smi_info->count_lock);		/* Do the before return_hosed_msg, because that		   releases the lock. */		smi_info->si_state = SI_NORMAL;		if (smi_info->curr_msg != NULL) {			/* If we were handling a user message, format                           a response to send to the upper layer to                           tell it about the error. */			return_hosed_msg(smi_info);		}		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);	}	/* We prefer handling attn over new messages. */	if (si_sm_result == SI_SM_ATTN)	{		unsigned char msg[2];		spin_lock(&smi_info->count_lock);		smi_info->attentions++;		spin_unlock(&smi_info->count_lock);		/* Got a attn, send down a get message flags to see                   what's causing it.  It would be better to handle                   this in the upper layer, but due to the way                   interrupts work with the SMI, that's not really                   possible. */		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);		msg[1] = IPMI_GET_MSG_FLAGS_CMD;		smi_info->handlers->start_transaction(			smi_info->si_sm, msg, 2);		smi_info->si_state = SI_GETTING_FLAGS;		goto restart;	}	/* If we are currently idle, try to start the next message. */	if (si_sm_result == SI_SM_IDLE) {		spin_lock(&smi_info->count_lock);		smi_info->idles++;		spin_unlock(&smi_info->count_lock);		si_sm_result = start_next_msg(smi_info);		if (si_sm_result != SI_SM_IDLE)			goto restart;        }	if ((si_sm_result == SI_SM_IDLE)	    && (atomic_read(&smi_info->req_events)))	{		/* We are idle and the upper layer requested that I fetch		   events, so do so. */		unsigned char msg[2];		spin_lock(&smi_info->count_lock);		smi_info->flag_fetches++;		spin_unlock(&smi_info->count_lock);		atomic_set(&smi_info->req_events, 0);		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);		msg[1] = IPMI_GET_MSG_FLAGS_CMD;		smi_info->handlers->start_transaction(			smi_info->si_sm, msg, 2);		smi_info->si_state = SI_GETTING_FLAGS;		goto restart;	}	return si_sm_result;}static void sender(void                *send_info,		   struct ipmi_smi_msg *msg,		   int                 priority){	struct smi_info   *smi_info = send_info;	enum si_sm_result result;	unsigned long     flags;#ifdef DEBUG_TIMING	struct timeval    t;#endif	spin_lock_irqsave(&(smi_info->msg_lock), flags);#ifdef DEBUG_TIMING	do_gettimeofday(&t);	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);#endif	if (smi_info->run_to_completion) {		/* If we are running to completion, then throw it in		   the list and run transactions until everything is		   clear.  Priority doesn't matter here. */		list_add_tail(&(msg->link), &(smi_info->xmit_msgs));		/* We have to release the msg lock and claim the smi		   lock in this case, because of race conditions. */		spin_unlock_irqrestore(&(smi_info->msg_lock), flags);		spin_lock_irqsave(&(smi_info->si_lock), flags);		result = smi_event_handler(smi_info, 0);		while (result != SI_SM_IDLE) {			udelay(SI_SHORT_TIMEOUT_USEC);			result = smi_event_handler(smi_info,						   SI_SHORT_TIMEOUT_USEC);		}		spin_unlock_irqrestore(&(smi_info->si_lock), flags);		return;	} else {		if (priority > 0) {			list_add_tail(&(msg->link), &(smi_info->hp_xmit_msgs));		} else {			list_add_tail(&(msg->link), &(smi_info->xmit_msgs));		}	}	spin_unlock_irqrestore(&(smi_info->msg_lock), flags);	spin_lock_irqsave(&(smi_info->si_lock), flags);	if ((smi_info->si_state == SI_NORMAL)	    && (smi_info->curr_msg == NULL))	{		start_next_msg(smi_info);		si_restart_short_timer(smi_info);	}	spin_unlock_irqrestore(&(smi_info->si_lock), flags);}static void set_run_to_completion(void *send_info, int i_run_to_completion){	struct smi_info   *smi_info = send_info;	enum si_sm_result result;	unsigned long     flags;	spin_lock_irqsave(&(smi_info->si_lock), flags);	smi_info->run_to_completion = i_run_to_completion;	if (i_run_to_completion) {		result = smi_event_handler(smi_info, 0);		while (result != SI_SM_IDLE) {			udelay(SI_SHORT_TIMEOUT_USEC);			result = smi_event_handler(smi_info,						   SI_SHORT_TIMEOUT_USEC);		}	}	spin_unlock_irqrestore(&(smi_info->si_lock), flags);}static void poll(void *send_info){	struct smi_info *smi_info = send_info;	smi_event_handler(smi_info, 0);}static void request_events(void *send_info){	struct smi_info *smi_info = send_info;	atomic_set(&smi_info->req_events, 1);}static int initialized = 0;/* Must be called with interrupts off and with the si_lock held. */static void si_restart_short_timer(struct smi_info *smi_info){#if defined(CONFIG_HIGH_RES_TIMERS)	unsigned long flags;	unsigned long jiffies_now;	if (del_timer(&(smi_info->si_timer))) {		/* If we don't delete the timer, then it will go off		   immediately, anyway.  So we only process if we		   actually delete the timer. */		/* We already have irqsave on, so no need for it                   here. */		read_lock(&xtime_lock);		jiffies_now = jiffies;		smi_info->si_timer.expires = jiffies_now;		smi_info->si_timer.sub_expires = get_arch_cycles(jiffies_now);		add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);		add_timer(&(smi_info->si_timer));		spin_lock_irqsave(&smi_info->count_lock, flags);		smi_info->timeout_restarts++;		spin_unlock_irqrestore(&smi_info->count_lock, flags);	}#endif}static void smi_timeout(unsigned long data){	struct smi_info   *smi_info = (struct smi_info *) data;	enum si_sm_result smi_result;	unsigned long     flags;	unsigned long     jiffies_now;	unsigned long     time_diff;#ifdef DEBUG_TIMING	struct timeval    t;#endif	if (smi_info->stop_operation) {		smi_info->timer_stopped = 1;		return;	}	spin_lock_irqsave(&(smi_info->si_lock), flags);#ifdef DEBUG_TIMING	do_gettimeofday(&t);	printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);#endif	jiffies_now = jiffies;	time_diff = ((jiffies_now - smi_info->last_timeout_jiffies)		     * SI_USEC_PER_JIFFY);	smi_result = smi_event_handler(smi_info, time_diff);	spin_unlock_irqrestore(&(smi_info->si_lock), flags);	smi_info->last_timeout_jiffies = jiffies_now;	if ((smi_info->irq) && (! smi_info->interrupt_disabled)) {		/* Running with interrupts, only do long timeouts. */		smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;		spin_lock_irqsave(&smi_info->count_lock, flags);		smi_info->long_timeouts++;		spin_unlock_irqrestore(&smi_info->count_lock, flags);		goto do_add_timer;	}	/* If the state machine asks for a short delay, then shorten           the timer timeout. */	if (smi_result == SI_SM_CALL_WITH_DELAY) {		spin_lock_irqsave(&smi_info->count_lock, flags);		smi_info->short_timeouts++;		spin_unlock_irqrestore(&smi_info->count_lock, flags);#if defined(CONFIG_HIGH_RES_TIMERS)		read_lock(&xtime_lock);                smi_info->si_timer.expires = jiffies;                smi_info->si_timer.sub_expires                        = get_arch_cycles(smi_info->si_timer.expires);                read_unlock(&xtime_lock);		add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);#else		smi_info->si_timer.expires = jiffies + 1;#endif	} else {		spin_lock_irqsave(&smi_info->count_lock, flags);		smi_info->long_timeouts++;		spin_unlock_irqrestore(&smi_info->count_lock, flags);		smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;#if defined(CONFIG_HIGH_RES_TIMERS)		smi_info->si_timer.sub_expires = 0;#endif	} do_add_timer:	add_timer(&(smi_info->si_timer));}static irqreturn_t si_irq_handler(int irq, void *data, struct pt_regs *regs){	struct smi_info *smi_info = data;	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("**Interrupt: %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 IRQ_HANDLED;}static struct ipmi_smi_handlers handlers ={	.owner                  = THIS_MODULE,	.sender			= sender,	.request_events		= request_events,	.set_run_to_completion  = set_run_to_completion,	.poll			= poll,};/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,   a default IO port, and 1 ACPI/SPMI address.  That sets SI_MAX_DRIVERS */#define SI_MAX_PARMS 4#define SI_MAX_DRIVERS ((SI_MAX_PARMS * 2) + 2)static struct smi_info *smi_infos[SI_MAX_DRIVERS] ={ NULL, NULL, NULL, NULL };#define DEVICE_NAME "ipmi_si"#define DEFAULT_KCS_IO_PORT	0xca2#define DEFAULT_SMIC_IO_PORT	0xca9#define DEFAULT_BT_IO_PORT	0xe4#define DEFAULT_REGSPACING	1static int           si_trydefaults = 1;static char          *si_type[SI_MAX_PARMS] = { NULL, NULL, NULL, NULL };#define MAX_SI_TYPE_STR 30static char          si_type_str[MAX_SI_TYPE_STR];static unsigned long addrs[SI_MAX_PARMS] = { 0, 0, 0, 0 };static int num_addrs = 0;static unsigned int  ports[SI_MAX_PARMS] = { 0, 0, 0, 0 };static int num_ports = 0;static int           irqs[SI_MAX_PARMS] = { 0, 0, 0, 0 };static int num_irqs = 0;static int           regspacings[SI_MAX_PARMS] = { 0, 0, 0, 0 };static int num_regspacings = 0;static int           regsizes[SI_MAX_PARMS] = { 0, 0, 0, 0 };static int num_regsizes = 0;static int           regshifts[SI_MAX_PARMS] = { 0, 0, 0, 0 };static int num_regshifts = 0;module_param_named(trydefaults, si_trydefaults, bool, 0);MODULE_PARM_DESC(trydefaults, "Setting this to 'false' will disable the"		 " default scan of the KCS and SMIC interface at the standard"		 " address");module_param_string(type, si_type_str, MAX_SI_TYPE_STR, 0);MODULE_PARM_DESC(type, "Defines the type of each interface, each"		 " interface separated by commas.  The types are 'kcs',"		 " 'smic', and 'bt'.  For example si_type=kcs,bt will set"		 " the first interface to kcs and the second to bt");module_param_array(addrs, long, &num_addrs, 0);MODULE_PARM_DESC(addrs, "Sets the memory address of each interface, the"		 " addresses separated by commas.  Only use if an interface"		 " is in memory.  Otherwise, set it to zero or leave"		 " it blank.");module_param_array(ports, int, &num_ports, 0);MODULE_PARM_DESC(ports, "Sets the port address of each interface, the"		 " addresses separated by commas.  Only use if an interface"		 " is a port.  Otherwise, set it to zero or leave"		 " it blank.");module_param_array(irqs, int, &num_irqs, 0);MODULE_PARM_DESC(irqs, "Sets the interrupt of each interface, the"		 " addresses separated by commas.  Only use if an interface"		 " has an interrupt.  Otherwise, set it to zero or leave"		 " it blank.");module_param_array(regspacings, int, &num_regspacings, 0);MODULE_PARM_DESC(regspacings, "The number of bytes between the start address"		 " and each successive register used by the interface.  For"		 " instance, if the start address is 0xca2 and the spacing"		 " is 2, then the second address is at 0xca4.  Defaults"		 " to 1.");module_param_array(regsizes, int, &num_regsizes, 0);MODULE_PARM_DESC(regsizes, "The size of the specific IPMI register in bytes."		 " This should generally be 1, 2, 4, or 8 for an 8-bit,"		 " 16-bit, 32-bit, or 64-bit register.  Use this if you"		 " the 8-bit IPMI register has to be read from a larger"		 " register.");module_param_array(regshifts, int, &num_regshifts, 0);MODULE_PARM_DESC(regshifts, "The amount to shift the data read from the."		 " IPMI register, in bits.  For instance, if the data"		 " is read from a 32-bit word and the IPMI data is in"		 " bit 8-15, then the shift would be 8");#define IPMI_MEM_ADDR_SPACE 1#define IPMI_IO_ADDR_SPACE  2#if defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_X86) || defined(CONFIG_PCI)static int is_new_interface(int intf, u8 addr_space, unsigned long base_addr){	int i;	for (i = 0; i < SI_MAX_PARMS; ++i) {		/* Don't check our address. */		if (i == intf)			continue;		if (si_type[i] != NULL) {			if ((addr_space == IPMI_MEM_ADDR_SPACE &&			     base_addr == addrs[i]) ||			    (addr_space == IPMI_IO_ADDR_SPACE &&			     base_addr == ports[i]))				return 0;		}		else			break;	}	return 1;}#endifstatic int std_irq_setup(struct smi_info *info){	int rv;	if (!info->irq)		return 0;	rv = request_irq(info->irq,			 si_irq_handler,			 SA_INTERRUPT,			 DEVICE_NAME,			 info);	if (rv) {		printk(KERN_WARNING		       "ipmi_si: %s unable to claim interrupt %d,"		       " running polled\n",		       DEVICE_NAME, info->irq);		info->irq = 0;	} else {		printk("  Using irq %d\n", info->irq);	}	return rv;}static void std_irq_cleanup(struct smi_info *info){	if (!info->irq)		return;	free_irq(info->irq, info);}static unsigned char port_inb(struct si_sm_io *io, unsigned int offset){	unsigned int *addr = io->info;	return inb((*addr)+(offset*io->regspacing));}static void port_outb(struct si_sm_io *io, unsigned int offset,		      unsigned char b){	unsigned int *addr = io->info;	outb(b, (*addr)+(offset * io->regspacing));}static unsigned char port_inw(struct si_sm_io *io, unsigned int offset){	unsigned int *addr = io->info;	return (inw((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff;}static void port_outw(struct si_sm_io *io, unsigned int offset,		      unsigned char b){	unsigned int *addr = io->info;	outw(b << io->regshift, (*addr)+(offset * io->regspacing));}static unsigned char port_inl(struct si_sm_io *io, unsigned int offset){	unsigned int *addr = io->info;	return (inl((*addr)+(offset * io->regspacing)) >> io->regshift) & 0xff;}static void port_outl(struct si_sm_io *io, unsigned int offset,		      unsigned char b){	unsigned int *addr = io->info;	outl(b << io->regshift, (*addr)+(offset * io->regspacing));}static void port_cleanup(struct smi_info *info){	unsigned int *addr = info->io.info;	int           mapsize;	if (addr && (*addr)) {		mapsize = ((info->io_size * info->io.regspacing)			   - (info->io.regspacing - info->io.regsize));		release_region (*addr, mapsize);	}	kfree(info);}static int port_setup(struct smi_info *info){	unsigned int *addr = info->io.info;	int           mapsize;	if (!addr || (!*addr))		return -ENODEV;	info->io_cleanup = port_cleanup;	/* Figure out the actual inb/inw/inl/etc routine to use based	   upon the register size. */	switch (info->io.regsize) {	case 1:		info->io.inputb = port_inb;		info->io.outputb = port_outb;		break;	case 2:		info->io.inputb = port_inw;		info->io.outputb = port_outw;		break;	case 4:		info->io.inputb = port_inl;		info->io.outputb = port_outl;		break;	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_region(*addr, mapsize, DEVICE_NAME) == NULL)		return -EIO;	return 0;}static int try_init_port(int intf_num, struct smi_info **new_info){	struct smi_info *info;	if (!ports[intf_num])		return -ENODEV;	if (!is_new_interface(intf_num, IPMI_IO_ADDR_SPACE,			      ports[intf_num]))		return -ENODEV;	info = kmalloc(sizeof(*info), GFP_KERNEL);	if (!info) {		printk(KERN_ERR "ipmi_si: Could not allocate SI data (1)\n");		return -ENOMEM;	}	memset(info, 0, sizeof(*info));	info->io_setup = port_setup;	info->io.info = &(ports[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 I/O port 0x%x\n",	       si_type[intf_num], ports[intf_num]);	return 0;}static unsigned char mem_inb(struct si_sm_io *io, unsigned int offset){	return readb((io->addr)+(offset * io->regspacing));}

⌨️ 快捷键说明

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