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

📄 ipw2100.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	aligned_len = len & (~0x3);	for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)		read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf);	/* copy the last nibble */	dif_len = len - aligned_len;	write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);	for (i = 0; i < dif_len; i++, buf++)		read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);}static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev){	return (dev->base_addr &&		(readl		 ((void __iomem *)(dev->base_addr +				   IPW_REG_DOA_DEBUG_AREA_START))		 == IPW_DATA_DOA_DEBUG_VALUE));}static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,			       void *val, u32 * len){	struct ipw2100_ordinals *ordinals = &priv->ordinals;	u32 addr;	u32 field_info;	u16 field_len;	u16 field_count;	u32 total_length;	if (ordinals->table1_addr == 0) {		printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals "		       "before they have been loaded.\n");		return -EINVAL;	}	if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {		if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) {			*len = IPW_ORD_TAB_1_ENTRY_SIZE;			printk(KERN_WARNING DRV_NAME			       ": ordinal buffer length too small, need %zd\n",			       IPW_ORD_TAB_1_ENTRY_SIZE);			return -EINVAL;		}		read_nic_dword(priv->net_dev,			       ordinals->table1_addr + (ord << 2), &addr);		read_nic_dword(priv->net_dev, addr, val);		*len = IPW_ORD_TAB_1_ENTRY_SIZE;		return 0;	}	if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) {		ord -= IPW_START_ORD_TAB_2;		/* get the address of statistic */		read_nic_dword(priv->net_dev,			       ordinals->table2_addr + (ord << 3), &addr);		/* get the second DW of statistics ;		 * two 16-bit words - first is length, second is count */		read_nic_dword(priv->net_dev,			       ordinals->table2_addr + (ord << 3) + sizeof(u32),			       &field_info);		/* get each entry length */		field_len = *((u16 *) & field_info);		/* get number of entries */		field_count = *(((u16 *) & field_info) + 1);		/* abort if no enought memory */		total_length = field_len * field_count;		if (total_length > *len) {			*len = total_length;			return -EINVAL;		}		*len = total_length;		if (!total_length)			return 0;		/* read the ordinal data from the SRAM */		read_nic_memory(priv->net_dev, addr, total_length, val);		return 0;	}	printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor "	       "in table 2\n", ord);	return -EINVAL;}static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val,			       u32 * len){	struct ipw2100_ordinals *ordinals = &priv->ordinals;	u32 addr;	if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {		if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) {			*len = IPW_ORD_TAB_1_ENTRY_SIZE;			IPW_DEBUG_INFO("wrong size\n");			return -EINVAL;		}		read_nic_dword(priv->net_dev,			       ordinals->table1_addr + (ord << 2), &addr);		write_nic_dword(priv->net_dev, addr, *val);		*len = IPW_ORD_TAB_1_ENTRY_SIZE;		return 0;	}	IPW_DEBUG_INFO("wrong table\n");	if (IS_ORDINAL_TABLE_TWO(ordinals, ord))		return -EINVAL;	return -EINVAL;}static char *snprint_line(char *buf, size_t count,			  const u8 * data, u32 len, u32 ofs){	int out, i, j, l;	char c;	out = snprintf(buf, count, "%08X", ofs);	for (l = 0, i = 0; i < 2; i++) {		out += snprintf(buf + out, count - out, " ");		for (j = 0; j < 8 && l < len; j++, l++)			out += snprintf(buf + out, count - out, "%02X ",					data[(i * 8 + j)]);		for (; j < 8; j++)			out += snprintf(buf + out, count - out, "   ");	}	out += snprintf(buf + out, count - out, " ");	for (l = 0, i = 0; i < 2; i++) {		out += snprintf(buf + out, count - out, " ");		for (j = 0; j < 8 && l < len; j++, l++) {			c = data[(i * 8 + j)];			if (!isascii(c) || !isprint(c))				c = '.';			out += snprintf(buf + out, count - out, "%c", c);		}		for (; j < 8; j++)			out += snprintf(buf + out, count - out, " ");	}	return buf;}static void printk_buf(int level, const u8 * data, u32 len){	char line[81];	u32 ofs = 0;	if (!(ipw2100_debug_level & level))		return;	while (len) {		printk(KERN_DEBUG "%s\n",		       snprint_line(line, sizeof(line), &data[ofs],				    min(len, 16U), ofs));		ofs += 16;		len -= min(len, 16U);	}}#define MAX_RESET_BACKOFF 10static inline void schedule_reset(struct ipw2100_priv *priv){	unsigned long now = get_seconds();	/* If we haven't received a reset request within the backoff period,	 * then we can reset the backoff interval so this reset occurs	 * immediately */	if (priv->reset_backoff &&	    (now - priv->last_reset > priv->reset_backoff))		priv->reset_backoff = 0;	priv->last_reset = get_seconds();	if (!(priv->status & STATUS_RESET_PENDING)) {		IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n",			       priv->net_dev->name, priv->reset_backoff);		netif_carrier_off(priv->net_dev);		netif_stop_queue(priv->net_dev);		priv->status |= STATUS_RESET_PENDING;		if (priv->reset_backoff)			queue_delayed_work(priv->workqueue, &priv->reset_work,					   priv->reset_backoff * HZ);		else			queue_work(priv->workqueue, &priv->reset_work);		if (priv->reset_backoff < MAX_RESET_BACKOFF)			priv->reset_backoff++;		wake_up_interruptible(&priv->wait_command_queue);	} else		IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n",			       priv->net_dev->name);}#define HOST_COMPLETE_TIMEOUT (2 * HZ)static int ipw2100_hw_send_command(struct ipw2100_priv *priv,				   struct host_command *cmd){	struct list_head *element;	struct ipw2100_tx_packet *packet;	unsigned long flags;	int err = 0;	IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",		     command_types[cmd->host_command], cmd->host_command,		     cmd->host_command_length);	printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters,		   cmd->host_command_length);	spin_lock_irqsave(&priv->low_lock, flags);	if (priv->fatal_error) {		IPW_DEBUG_INFO		    ("Attempt to send command while hardware in fatal error condition.\n");		err = -EIO;		goto fail_unlock;	}	if (!(priv->status & STATUS_RUNNING)) {		IPW_DEBUG_INFO		    ("Attempt to send command while hardware is not running.\n");		err = -EIO;		goto fail_unlock;	}	if (priv->status & STATUS_CMD_ACTIVE) {		IPW_DEBUG_INFO		    ("Attempt to send command while another command is pending.\n");		err = -EBUSY;		goto fail_unlock;	}	if (list_empty(&priv->msg_free_list)) {		IPW_DEBUG_INFO("no available msg buffers\n");		goto fail_unlock;	}	priv->status |= STATUS_CMD_ACTIVE;	priv->messages_sent++;	element = priv->msg_free_list.next;	packet = list_entry(element, struct ipw2100_tx_packet, list);	packet->jiffy_start = jiffies;	/* initialize the firmware command packet */	packet->info.c_struct.cmd->host_command_reg = cmd->host_command;	packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;	packet->info.c_struct.cmd->host_command_len_reg =	    cmd->host_command_length;	packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;	memcpy(packet->info.c_struct.cmd->host_command_params_reg,	       cmd->host_command_parameters,	       sizeof(packet->info.c_struct.cmd->host_command_params_reg));	list_del(element);	DEC_STAT(&priv->msg_free_stat);	list_add_tail(element, &priv->msg_pend_list);	INC_STAT(&priv->msg_pend_stat);	ipw2100_tx_send_commands(priv);	ipw2100_tx_send_data(priv);	spin_unlock_irqrestore(&priv->low_lock, flags);	/*	 * We must wait for this command to complete before another	 * command can be sent...  but if we wait more than 3 seconds	 * then there is a problem.	 */	err =	    wait_event_interruptible_timeout(priv->wait_command_queue,					     !(priv->					       status & STATUS_CMD_ACTIVE),					     HOST_COMPLETE_TIMEOUT);	if (err == 0) {		IPW_DEBUG_INFO("Command completion failed out after %dms.\n",			       1000 * (HOST_COMPLETE_TIMEOUT / HZ));		priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;		priv->status &= ~STATUS_CMD_ACTIVE;		schedule_reset(priv);		return -EIO;	}	if (priv->fatal_error) {		printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n",		       priv->net_dev->name);		return -EIO;	}	/* !!!!! HACK TEST !!!!!	 * When lots of debug trace statements are enabled, the driver	 * doesn't seem to have as many firmware restart cycles...	 *	 * As a test, we're sticking in a 1/100s delay here */	schedule_timeout_uninterruptible(msecs_to_jiffies(10));	return 0;      fail_unlock:	spin_unlock_irqrestore(&priv->low_lock, flags);	return err;}/* * Verify the values and data access of the hardware * No locks needed or used.  No functions called. */static int ipw2100_verify(struct ipw2100_priv *priv){	u32 data1, data2;	u32 address;	u32 val1 = 0x76543210;	u32 val2 = 0xFEDCBA98;	/* Domain 0 check - all values should be DOA_DEBUG */	for (address = IPW_REG_DOA_DEBUG_AREA_START;	     address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) {		read_register(priv->net_dev, address, &data1);		if (data1 != IPW_DATA_DOA_DEBUG_VALUE)			return -EIO;	}	/* Domain 1 check - use arbitrary read/write compare  */	for (address = 0; address < 5; address++) {		/* The memory area is not used now */		write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,			       val1);		write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,			       val2);		read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,			      &data1);		read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,			      &data2);		if (val1 == data1 && val2 == data2)			return 0;	}	return -EIO;}/* * * Loop until the CARD_DISABLED bit is the same value as the * supplied parameter * * TODO: See if it would be more efficient to do a wait/wake *       cycle and have the completion event trigger the wakeup * */#define IPW_CARD_DISABLE_COMPLETE_WAIT		    100	// 100 millistatic int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state){	int i;	u32 card_state;	u32 len = sizeof(card_state);	int err;	for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) {		err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED,					  &card_state, &len);		if (err) {			IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal "				       "failed.\n");			return 0;		}		/* We'll break out if either the HW state says it is		 * in the state we want, or if HOST_COMPLETE command		 * finishes */		if ((card_state == state) ||		    ((priv->status & STATUS_ENABLED) ?		     IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) {			if (state == IPW_HW_STATE_ENABLED)				priv->status |= STATUS_ENABLED;			else				priv->status &= ~STATUS_ENABLED;			return 0;		}		udelay(50);	}	IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n",		       state ? "DISABLED" : "ENABLED");	return -EIO;}/*********************************************************************    Procedure   :   sw_reset_and_clock    Purpose     :   Asserts s/w reset, asserts clock initialization                    and waits for clock stabilization ********************************************************************/static int sw_reset_and_clock(struct ipw2100_priv *priv){	int i;	u32 r;	// assert s/w reset	write_register(priv->net_dev, IPW_REG_RESET_REG,		       IPW_AUX_HOST_RESET_REG_SW_RESET);	// wait for clock stabilization	for (i = 0; i < 1000; i++) {		udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY);		// check clock ready bit		read_register(priv->net_dev, IPW_REG_RESET_REG, &r);		if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET)			break;	}	if (i == 1000)		return -EIO;	// TODO: better error value	/* set "initialization complete" bit to move adapter to	 * D0 state */	write_register(priv->net_dev, IPW_REG_GP_CNTRL,		       IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE);	/* wait for clock stabilization */	for (i = 0; i < 10000; i++) {		udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4);		/* check clock ready bit */		read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);		if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY)			break;	}	if (i == 10000)		return -EIO;	/* TODO: better error value */	/* set D0 standby bit */	read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);	write_register(priv->net_dev, IPW_REG_GP_CNTRL,		       r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);	return 0;}/*********************************************************************    Procedure   :   ipw2100_download_firmware    Purpose     :   Initiaze adapter after power on.                    The sequence is:                    1. assert s/w reset first!                    2. awake clocks & wait for clock stabilization

⌨️ 快捷键说明

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