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

📄 lcs.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 4 页
字号:
 */static intlcs_stop_channels(struct lcs_card *card){	LCS_DBF_TEXT(2, trace, "chhalt");	lcs_stop_channel(&card->read);	lcs_stop_channel(&card->write);	return 0;}/** * Get empty buffer. */static struct lcs_buffer *__lcs_get_buffer(struct lcs_channel *channel){	int index;	LCS_DBF_TEXT(5, trace, "_getbuff");	index = channel->io_idx;	do {		if (channel->iob[index].state == BUF_STATE_EMPTY) {			channel->iob[index].state = BUF_STATE_LOCKED;			return channel->iob + index;		}		index = (index + 1) & (LCS_NUM_BUFFS - 1);	} while (index != channel->io_idx);	return NULL;}static struct lcs_buffer *lcs_get_buffer(struct lcs_channel *channel){	struct lcs_buffer *buffer;	unsigned long flags;	LCS_DBF_TEXT(5, trace, "getbuff");	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);	buffer = __lcs_get_buffer(channel);	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);	return buffer;}/** * Resume channel program if the channel is suspended. */static int__lcs_resume_channel(struct lcs_channel *channel){	int rc;	if (channel->state != CH_STATE_SUSPENDED)		return 0;	if (channel->ccws[channel->io_idx].flags & CCW_FLAG_SUSPEND)		return 0;	LCS_DBF_TEXT_(5, trace, "rsch%s", channel->ccwdev->dev.bus_id);	rc = ccw_device_resume(channel->ccwdev);	if (rc) {		LCS_DBF_TEXT_(4, trace, "ersc%s", channel->ccwdev->dev.bus_id);		PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc);	} else		channel->state = CH_STATE_RUNNING;	return rc;}/** * Make a buffer ready for processing. */static inline void__lcs_ready_buffer_bits(struct lcs_channel *channel, int index){	int prev, next;	LCS_DBF_TEXT(5, trace, "rdybits");	prev = (index - 1) & (LCS_NUM_BUFFS - 1);	next = (index + 1) & (LCS_NUM_BUFFS - 1);	/* Check if we may clear the suspend bit of this buffer. */	if (channel->ccws[next].flags & CCW_FLAG_SUSPEND) {		/* Check if we have to set the PCI bit. */		if (!(channel->ccws[prev].flags & CCW_FLAG_SUSPEND))			/* Suspend bit of the previous buffer is not set. */			channel->ccws[index].flags |= CCW_FLAG_PCI;		/* Suspend bit of the next buffer is set. */		channel->ccws[index].flags &= ~CCW_FLAG_SUSPEND;	}}static intlcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer){	unsigned long flags;	int index, rc;	LCS_DBF_TEXT(5, trace, "rdybuff");	if (buffer->state != BUF_STATE_LOCKED &&	    buffer->state != BUF_STATE_PROCESSED)		BUG();	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);	buffer->state = BUF_STATE_READY;	index = buffer - channel->iob;	/* Set length. */	channel->ccws[index].count = buffer->count;	/* Check relevant PCI/suspend bits. */	__lcs_ready_buffer_bits(channel, index);	rc = __lcs_resume_channel(channel);	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);	return rc;}/** * Mark the buffer as processed. Take care of the suspend bit * of the previous buffer. This function is called from * interrupt context, so the lock must not be taken. */static int__lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer){	int index, prev, next;	LCS_DBF_TEXT(5, trace, "prcsbuff");	if (buffer->state != BUF_STATE_READY)		BUG();	buffer->state = BUF_STATE_PROCESSED;	index = buffer - channel->iob;	prev = (index - 1) & (LCS_NUM_BUFFS - 1);	next = (index + 1) & (LCS_NUM_BUFFS - 1);	/* Set the suspend bit and clear the PCI bit of this buffer. */	channel->ccws[index].flags |= CCW_FLAG_SUSPEND;	channel->ccws[index].flags &= ~CCW_FLAG_PCI;	/* Check the suspend bit of the previous buffer. */	if (channel->iob[prev].state == BUF_STATE_READY) {		/*		 * Previous buffer is in state ready. It might have		 * happened in lcs_ready_buffer that the suspend bit		 * has not been cleared to avoid an endless loop.		 * Do it now.		 */		__lcs_ready_buffer_bits(channel, prev);	}	/* Clear PCI bit of next buffer. */	channel->ccws[next].flags &= ~CCW_FLAG_PCI;	return __lcs_resume_channel(channel);}/** * Put a processed buffer back to state empty. */static voidlcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer){	unsigned long flags;	LCS_DBF_TEXT(5, trace, "relbuff");	if (buffer->state != BUF_STATE_LOCKED &&	    buffer->state != BUF_STATE_PROCESSED)		BUG();	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);	buffer->state = BUF_STATE_EMPTY;	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);}/** * Get buffer for a lan command. */static struct lcs_buffer *lcs_get_lancmd(struct lcs_card *card, int count){	struct lcs_buffer *buffer;	struct lcs_cmd *cmd;	LCS_DBF_TEXT(4, trace, "getlncmd");	/* Get buffer and wait if none is available. */	wait_event(card->write.wait_q,		   ((buffer = lcs_get_buffer(&card->write)) != NULL));	count += sizeof(struct lcs_header);	*(__u16 *)(buffer->data + count) = 0;	buffer->count = count + sizeof(__u16);	buffer->callback = lcs_release_buffer;	cmd = (struct lcs_cmd *) buffer->data;	cmd->offset = count;	cmd->type = LCS_FRAME_TYPE_CONTROL;	cmd->slot = 0;	return buffer;}static voidlcs_get_reply(struct lcs_reply *reply){	WARN_ON(atomic_read(&reply->refcnt) <= 0);	atomic_inc(&reply->refcnt);}static voidlcs_put_reply(struct lcs_reply *reply){        WARN_ON(atomic_read(&reply->refcnt) <= 0);        if (atomic_dec_and_test(&reply->refcnt)) {		kfree(reply);	}}static struct lcs_reply *lcs_alloc_reply(struct lcs_cmd *cmd){	struct lcs_reply *reply;	LCS_DBF_TEXT(4, trace, "getreply");	reply = kmalloc(sizeof(struct lcs_reply), GFP_ATOMIC);	if (!reply)		return NULL;	memset(reply,0,sizeof(struct lcs_reply));	atomic_set(&reply->refcnt,1);	reply->sequence_no = cmd->sequence_no;	reply->received = 0;	reply->rc = 0;	init_waitqueue_head(&reply->wait_q);	return reply;}/** * Notifier function for lancmd replies. Called from read irq. */static voidlcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd){	struct list_head *l, *n;	struct lcs_reply *reply;	LCS_DBF_TEXT(4, trace, "notiwait");	spin_lock(&card->lock);	list_for_each_safe(l, n, &card->lancmd_waiters) {		reply = list_entry(l, struct lcs_reply, list);		if (reply->sequence_no == cmd->sequence_no) {			lcs_get_reply(reply);			list_del_init(&reply->list);			if (reply->callback != NULL)				reply->callback(card, cmd);			reply->received = 1;			reply->rc = cmd->return_code;			wake_up(&reply->wait_q);			lcs_put_reply(reply);			break;		}	}	spin_unlock(&card->lock);}/** * Emit buffer of a lan comand. */voidlcs_lancmd_timeout(unsigned long data){	struct lcs_reply *reply, *list_reply, *r;	unsigned long flags;	LCS_DBF_TEXT(4, trace, "timeout");	reply = (struct lcs_reply *) data;	spin_lock_irqsave(&reply->card->lock, flags);	list_for_each_entry_safe(list_reply, r,				 &reply->card->lancmd_waiters,list) {		if (reply == list_reply) {			lcs_get_reply(reply);			list_del_init(&reply->list);			spin_unlock_irqrestore(&reply->card->lock, flags);			reply->received = 1;			reply->rc = -ETIME;			wake_up(&reply->wait_q);			lcs_put_reply(reply);			return;		}	}	spin_unlock_irqrestore(&reply->card->lock, flags);}static intlcs_send_lancmd(struct lcs_card *card, struct lcs_buffer *buffer,		void (*reply_callback)(struct lcs_card *, struct lcs_cmd *)){	struct lcs_reply *reply;	struct lcs_cmd *cmd;	struct timer_list timer;	unsigned long flags;	int rc;	LCS_DBF_TEXT(4, trace, "sendcmd");	cmd = (struct lcs_cmd *) buffer->data;	cmd->return_code = 0;	cmd->sequence_no = card->sequence_no++;	reply = lcs_alloc_reply(cmd);	if (!reply)		return -ENOMEM;	reply->callback = reply_callback;	reply->card = card;	spin_lock_irqsave(&card->lock, flags);	list_add_tail(&reply->list, &card->lancmd_waiters);	spin_unlock_irqrestore(&card->lock, flags);	buffer->callback = lcs_release_buffer;	rc = lcs_ready_buffer(&card->write, buffer);	if (rc)		return rc;	init_timer(&timer);	timer.function = lcs_lancmd_timeout;	timer.data = (unsigned long) reply;	timer.expires = jiffies + HZ*card->lancmd_timeout;	add_timer(&timer);	wait_event(reply->wait_q, reply->received);	del_timer_sync(&timer);	LCS_DBF_TEXT_(4, trace, "rc:%d",reply->rc);	rc = reply->rc;	lcs_put_reply(reply);	return rc ? -EIO : 0;}/** * LCS startup command */static intlcs_send_startup(struct lcs_card *card, __u8 initiator){	struct lcs_buffer *buffer;	struct lcs_cmd *cmd;	LCS_DBF_TEXT(2, trace, "startup");	buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE);	cmd = (struct lcs_cmd *) buffer->data;	cmd->cmd_code = LCS_CMD_STARTUP;	cmd->initiator = initiator;	cmd->cmd.lcs_startup.buff_size = LCS_IOBUFFERSIZE;	return lcs_send_lancmd(card, buffer, NULL);}/** * LCS shutdown command */static intlcs_send_shutdown(struct lcs_card *card){	struct lcs_buffer *buffer;	struct lcs_cmd *cmd;	LCS_DBF_TEXT(2, trace, "shutdown");	buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE);	cmd = (struct lcs_cmd *) buffer->data;	cmd->cmd_code = LCS_CMD_SHUTDOWN;	cmd->initiator = LCS_INITIATOR_TCPIP;	return lcs_send_lancmd(card, buffer, NULL);}/** * LCS lanstat command */static void__lcs_lanstat_cb(struct lcs_card *card, struct lcs_cmd *cmd){	LCS_DBF_TEXT(2, trace, "statcb");	memcpy(card->mac, cmd->cmd.lcs_lanstat_cmd.mac_addr, LCS_MAC_LENGTH);}static intlcs_send_lanstat(struct lcs_card *card){	struct lcs_buffer *buffer;	struct lcs_cmd *cmd;	LCS_DBF_TEXT(2,trace, "cmdstat");	buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE);	cmd = (struct lcs_cmd *) buffer->data;	/* Setup lanstat command. */	cmd->cmd_code = LCS_CMD_LANSTAT;	cmd->initiator = LCS_INITIATOR_TCPIP;	cmd->cmd.lcs_std_cmd.lan_type = card->lan_type;	cmd->cmd.lcs_std_cmd.portno = card->portno;	return lcs_send_lancmd(card, buffer, __lcs_lanstat_cb);}/** * send stoplan command */static intlcs_send_stoplan(struct lcs_card *card, __u8 initiator){	struct lcs_buffer *buffer;	struct lcs_cmd *cmd;	LCS_DBF_TEXT(2, trace, "cmdstpln");	buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE);	cmd = (struct lcs_cmd *) buffer->data;	cmd->cmd_code = LCS_CMD_STOPLAN;	cmd->initiator = initiator;	cmd->cmd.lcs_std_cmd.lan_type = card->lan_type;	cmd->cmd.lcs_std_cmd.portno = card->portno;	return lcs_send_lancmd(card, buffer, NULL);}/** * send startlan command */static void__lcs_send_startlan_cb(struct lcs_card *card, struct lcs_cmd *cmd){	LCS_DBF_TEXT(2, trace, "srtlancb");	card->lan_type = cmd->cmd.lcs_std_cmd.lan_type;	card->portno = cmd->cmd.lcs_std_cmd.portno;}static intlcs_send_startlan(struct lcs_card *card, __u8 initiator){	struct lcs_buffer *buffer;	struct lcs_cmd *cmd;	LCS_DBF_TEXT(2, trace, "cmdstaln");	buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE);	cmd = (struct lcs_cmd *) buffer->data;	cmd->cmd_code = LCS_CMD_STARTLAN;	cmd->initiator = initiator;	cmd->cmd.lcs_std_cmd.lan_type = card->lan_type;	cmd->cmd.lcs_std_cmd.portno = card->portno;	return lcs_send_lancmd(card, buffer, __lcs_send_startlan_cb);}#ifdef CONFIG_IP_MULTICAST/** * send setipm command (Multicast) */static intlcs_send_setipm(struct lcs_card *card,struct lcs_ipm_list *ipm_list){	struct lcs_buffer *buffer;	struct lcs_cmd *cmd;	LCS_DBF_TEXT(2, trace, "cmdsetim");	buffer = lcs_get_lancmd(card, LCS_MULTICAST_CMD_SIZE);	cmd = (struct lcs_cmd *) buffer->data;	cmd->cmd_code = LCS_CMD_SETIPM;	cmd->initiator = LCS_INITIATOR_TCPIP;	cmd->cmd.lcs_qipassist.lan_type = card->lan_type;	cmd->cmd.lcs_qipassist.portno = card->portno;	cmd->cmd.lcs_qipassist.version = 4;	cmd->cmd.lcs_qipassist.num_ip_pairs = 1;	memcpy(cmd->cmd.lcs_qipassist.lcs_ipass_ctlmsg.ip_mac_pair,	       &ipm_list->ipm, sizeof (struct lcs_ip_mac_pair));	LCS_DBF_TEXT_(2, trace, "%x",ipm_list->ipm.ip_addr);	return lcs_send_lancmd(card, buffer, NULL);}/** * send delipm command (Multicast) */static intlcs_send_delipm(struct lcs_card *card,struct lcs_ipm_list *ipm_list){	struct lcs_buffer *buffer;	struct lcs_cmd *cmd;	LCS_DBF_TEXT(2, trace, "cmddelim");	buffer = lcs_get_lancmd(card, LCS_MULTICAST_CMD_SIZE);	cmd = (struct lcs_cmd *) buffer->data;	cmd->cmd_code = LCS_CMD_DELIPM;	cmd->initiator = LCS_INITIATOR_TCPIP;	cmd->cmd.lcs_qipassist.lan_type = card->lan_type;	cmd->cmd.lcs_qipassist.portno = card->portno;	cmd->cmd.lcs_qipassist.version = 4;	cmd->cmd.lcs_qipassist.num_ip_pairs = 1;	memcpy(cmd->cmd.lcs_qipassist.lcs_ipass_ctlmsg.ip_mac_pair,	       &ipm_list->ipm, sizeof (struct lcs_ip_mac_pair));	LCS_DBF_TEXT_(2, trace, "%x",ipm_list->ipm.ip_addr);	return lcs_send_lancmd(card, buffer, NULL);}/** * check if multicast is supported by LCS */static void__lcs_check_multicast_cb(struct lcs_card *card, struct lcs_cmd *cmd){	LCS_DBF_TEXT(2, trace, "chkmccb");	card->ip_assists_supported =		cmd->cmd.lcs_qipassist.ip_assists_supported;	card->ip_assists_enabled =		cmd->cmd.lcs_qipassist.ip_assists_enabled;}static intlcs_check_multicast_support(struct lcs_card *card){	struct lcs_buffer *buffer;	struct lcs_cmd *cmd;	int rc;	LCS_DBF_TEXT(2, trace, "cmdqipa");	/* Send query ipassist. */	buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE);	cmd = (struct lcs_cmd *) buffer->data;	cmd->cmd_code = LCS_CMD_QIPASSIST;	cmd->initiator = LCS_INITIATOR_TCPIP;	cmd->cmd.lcs_qipassist.lan_type = card->lan_type;	cmd->cmd.lcs_qipassist.portno = card->portno;	cmd->cmd.lcs_qipassist.version = 4;	cmd->cmd.lcs_qipassist.num_ip_pairs = 1;	rc = lcs_send_lancmd(card, buffer, __lcs_check_multicast_cb);	if (rc != 0) {		PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n");		return -EOPNOTSUPP;	}	if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT)		return 0;	return -EOPNOTSUPP;}/** * set or del multicast address on LCS card */static voidlcs_fix_multicast_list(struct lcs_card *card){	struct list_head failed_list;	struct lcs_ipm_list *ipm, *tmp;	unsigned long flags;	int rc;	LCS_DBF_TEXT(4,trace, "fixipm");	INIT_LIST_HEAD(&failed_list);	spin_lock_irqsave(&card->ipm_lock, flags);list_modified:	list_for_each_entry_safe(ipm, tmp, &card->ipm_list, list){		switch (ipm->ipm_state) {		case LCS_IPM_STATE_SET_REQUIRED:			/* del from ipm_list so noone else can tamper with			 * this entry */			list_del_init(&ipm->list);			spin_unlock_irqrestore(&card->ipm_lock, flags);			rc = lcs_send_setipm(card, ipm);			spin_lock_irqsave(&card->ipm_lock, flags);			if (rc) {				PRINT_INFO("Adding multicast address failed."					   "Table possibly full!\n");				/* store ipm in failed list -> will be added				 * to ipm_list again, so a retry will be done				 * during the next call of this function */				list_add_tail(&ipm->list, &failed_list);			} else {				ipm->ipm_state = LCS_IPM_STATE_ON_CARD;				/* re-insert into ipm_list */				list_add_tail(&ipm->list, &card->ipm_list);			}			goto list_modified;		case LCS_IPM_STATE_DEL_REQUIRED:			list_del(&ipm->list);			spin_unlock_irqrestore(&card->ipm_lock, flags);			lcs_send_delipm(card, ipm);			spin_lock_irqsave(&card->ipm_lock, flags);			kfree(ipm);			goto list_modified;		case LCS_IPM_STATE_ON_CARD:			break;		}	}	/* re-insert all entries from the failed_list into ipm_list */	list_for_each_entry_safe(ipm, tmp, &failed_list, list) {		list_del_init(&ipm->list);		list_add_tail(&ipm->list, &card->ipm_list);	}	spin_unlock_irqrestore(&card->ipm_lock, flags);	if (card->state == DEV_STATE_UP)		netif_wake_queue(card->dev);}/** * get mac address for the relevant Multicast address */static voidlcs_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev){	LCS_DBF_TEXT(4,trace, "getmac");	if (dev->type == ARPHRD_IEEE802_TR)		ip_tr_mc_map(ipm, mac);	else		ip_eth_mc_map(ipm, mac);}

⌨️ 快捷键说明

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