qeth_main.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,466 行 · 第 1/5 页

C
2,466
字号
	iob = channel->iob;	index = channel->buf_no;	card = CARD_FROM_CDEV(channel->ccwdev);	while (iob[index].state == BUF_STATE_PROCESSED) {		if (iob[index].callback !=NULL) {			iob[index].callback(channel,iob + index);		}		index = (index + 1) % QETH_CMD_BUFFER_NO;	}	channel->buf_no = index;	wake_up(&card->wait_q);}static int qeth_stop_card(struct qeth_card *);static intqeth_set_offline(struct ccwgroup_device *cgdev){	struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data;	enum qeth_card_states recover_flag;	QETH_DBF_TEXT(setup, 3, "setoffl");	QETH_DBF_HEX(setup, 3, &card, sizeof(void *));	recover_flag = card->state;	if (qeth_stop_card(card) == -ERESTARTSYS){		PRINT_WARN("Stopping card %s interrupted by user!\n",			   CARD_BUS_ID(card));		return -ERESTARTSYS;	}	ccw_device_set_offline(CARD_DDEV(card));	ccw_device_set_offline(CARD_WDEV(card));	ccw_device_set_offline(CARD_RDEV(card));	if (recover_flag == CARD_STATE_UP)		card->state = CARD_STATE_RECOVER;	qeth_notify_processes();	return 0;}static voidqeth_remove_device(struct ccwgroup_device *cgdev){	struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data;	unsigned long flags;	QETH_DBF_TEXT(setup, 3, "rmdev");	QETH_DBF_HEX(setup, 3, &card, sizeof(void *));	if (!card)		return;	if (cgdev->state == CCWGROUP_ONLINE){		card->use_hard_stop = 1;		qeth_set_offline(cgdev);	}	/* remove form our internal list */	write_lock_irqsave(&qeth_card_list.rwlock, flags);	list_del(&card->list);	write_unlock_irqrestore(&qeth_card_list.rwlock, flags);	if (card->dev)		unregister_netdev(card->dev);	qeth_remove_device_attributes(&cgdev->dev);	qeth_free_card(card);	cgdev->dev.driver_data = NULL;	put_device(&cgdev->dev);}static intqeth_register_addr_entry(struct qeth_card *, struct qeth_ipaddr *);static intqeth_deregister_addr_entry(struct qeth_card *, struct qeth_ipaddr *);/** * Add/remove address to/from card's ip list, i.e. try to add or remove * reference to/from an IP address that is already registered on the card. * Returns: * 	0  address was on card and its reference count has been adjusted, * 	   but is still > 0, so nothing has to be done * 	   also returns 0 if card was not on card and the todo was to delete * 	   the address -> there is also nothing to be done * 	1  address was not on card and the todo is to add it to the card's ip * 	   list * 	-1 address was on card and its reference count has been decremented * 	   to <= 0 by the todo -> address must be removed from card */static int__qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,		      struct qeth_ipaddr **__addr){	struct qeth_ipaddr *addr;	int found = 0;	list_for_each_entry(addr, &card->ip_list, entry) {		if ((addr->proto     == QETH_PROT_IPV4)  &&		    (todo->proto     == QETH_PROT_IPV4)  &&		    (addr->type      == todo->type)      &&		    (addr->u.a4.addr == todo->u.a4.addr) &&		    (addr->u.a4.mask == todo->u.a4.mask)   ){			found = 1;			break;		}		if ((addr->proto       == QETH_PROT_IPV6)     &&		    (todo->proto       == QETH_PROT_IPV6)     &&		    (addr->type        == todo->type)         &&		    (addr->u.a6.pfxlen == todo->u.a6.pfxlen)  &&		    (memcmp(&addr->u.a6.addr, &todo->u.a6.addr,			    sizeof(struct in6_addr)) == 0))     {			found = 1;			break;		}	}	if (found){		addr->users += todo->users;		if (addr->users <= 0){			*__addr = addr;			return -1;		} else {			/* for VIPA and RXIP limit refcount to 1 */			if (addr->type != QETH_IP_TYPE_NORMAL)				addr->users = 1;			return 0;		}	}	if (todo->users > 0){		/* for VIPA and RXIP limit refcount to 1 */		if (todo->type != QETH_IP_TYPE_NORMAL)			addr->users = 1;		return 1;	} else		return 0;}static inline int__qeth_address_exists_in_list(struct list_head *list, struct qeth_ipaddr *addr,		              int same_type){	struct qeth_ipaddr *tmp;	list_for_each_entry(tmp, list, entry) {		if ((tmp->proto     == QETH_PROT_IPV4)            &&		    (addr->proto    == QETH_PROT_IPV4)            &&		    ((same_type && (tmp->type == addr->type)) ||		     (!same_type && (tmp->type != addr->type))  ) &&		    (tmp->u.a4.addr == addr->u.a4.addr)             ){			return 1;		}		if ((tmp->proto  == QETH_PROT_IPV6)               &&		    (addr->proto == QETH_PROT_IPV6)               &&		    ((same_type && (tmp->type == addr->type)) ||		     (!same_type && (tmp->type != addr->type))  ) &&		    (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr,			    sizeof(struct in6_addr)) == 0)          ) {			return 1;		}	}	return 0;}/* * Add IP to be added to todo list. If there is already an "add todo" * in this list we just incremenent the reference count. * Returns 0 if we  just incremented reference count. */static int__qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add){	struct qeth_ipaddr *tmp, *t;	int found = 0;	list_for_each_entry_safe(tmp, t, &card->ip_tbd_list, entry) {		if ((tmp->proto        == QETH_PROT_IPV4)     &&		    (addr->proto       == QETH_PROT_IPV4)     &&		    (tmp->type         == addr->type)         &&		    (tmp->is_multicast == addr->is_multicast) &&		    (tmp->u.a4.addr    == addr->u.a4.addr)    &&		    (tmp->u.a4.mask    == addr->u.a4.mask)      ){			found = 1;			break;		}		if ((tmp->proto        == QETH_PROT_IPV6)      &&		    (addr->proto       == QETH_PROT_IPV6)      &&		    (tmp->type         == addr->type)          &&		    (tmp->is_multicast == addr->is_multicast)  &&		    (tmp->u.a6.pfxlen  == addr->u.a6.pfxlen)   &&		    (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr,			    sizeof(struct in6_addr)) == 0)        ){			found = 1;			break;		}	}	if (found){		if (addr->users != 0)			tmp->users += addr->users;		else			tmp->users += add? 1:-1;		if (tmp->users == 0){			list_del(&tmp->entry);			kfree(tmp);		}		return 0;	} else {		if (addr->users == 0)			addr->users += add? 1:-1;		if (add && (addr->type == QETH_IP_TYPE_NORMAL) &&		    qeth_is_addr_covered_by_ipato(card, addr)){			QETH_DBF_TEXT(trace, 2, "tkovaddr");			addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG;		}		list_add_tail(&addr->entry, &card->ip_tbd_list);		return 1;	}}/** * Remove IP address from list */static intqeth_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr){	unsigned long flags;	int rc = 0;	QETH_DBF_TEXT(trace,4,"delip");	if (addr->proto == QETH_PROT_IPV4)		QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);	else {		QETH_DBF_HEX(trace,4,&addr->u.a6.addr,4);		QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4);	}	spin_lock_irqsave(&card->ip_lock, flags);	rc = __qeth_insert_ip_todo(card, addr, 0);	spin_unlock_irqrestore(&card->ip_lock, flags);	return rc;}static intqeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr){	unsigned long flags;	int rc = 0;	QETH_DBF_TEXT(trace,4,"addip");	if (addr->proto == QETH_PROT_IPV4)		QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);	else {		QETH_DBF_HEX(trace,4,&addr->u.a6.addr,4);		QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4);	}	spin_lock_irqsave(&card->ip_lock, flags);	rc = __qeth_insert_ip_todo(card, addr, 1);	spin_unlock_irqrestore(&card->ip_lock, flags);	return rc;}static voidqeth_reinsert_todos(struct qeth_card *card, struct list_head *todos){	struct qeth_ipaddr *todo, *tmp;	list_for_each_entry_safe(todo, tmp, todos, entry){		list_del_init(&todo->entry);		if (todo->users < 0) {			if (!qeth_delete_ip(card, todo))				kfree(todo);		} else {			if (!qeth_add_ip(card, todo))				kfree(todo);		}	}}static voidqeth_set_ip_addr_list(struct qeth_card *card){	struct list_head failed_todos;	struct qeth_ipaddr *todo, *addr;	unsigned long flags;	int rc;	QETH_DBF_TEXT(trace, 2, "sdiplist");	QETH_DBF_HEX(trace, 2, &card, sizeof(void *));	INIT_LIST_HEAD(&failed_todos);	spin_lock_irqsave(&card->ip_lock, flags);	while (!list_empty(&card->ip_tbd_list)) {		todo = list_entry(card->ip_tbd_list.next,				  struct qeth_ipaddr, entry);		list_del_init(&todo->entry);		rc = __qeth_ref_ip_on_card(card, todo, &addr);		if (rc == 0) {			/* nothing to be done; only adjusted refcount */			kfree(todo);		} else if (rc == 1) {			/* new entry to be added to on-card list */			spin_unlock_irqrestore(&card->ip_lock, flags);			rc = qeth_register_addr_entry(card, todo);			spin_lock_irqsave(&card->ip_lock, flags);			if (!rc)				list_add_tail(&todo->entry, &card->ip_list);			else				list_add_tail(&todo->entry, &failed_todos);		} else if (rc == -1) {			/* on-card entry to be removed */			list_del_init(&addr->entry);			spin_unlock_irqrestore(&card->ip_lock, flags);			rc = qeth_deregister_addr_entry(card, addr);			spin_lock_irqsave(&card->ip_lock, flags);			if (!rc) {				kfree(addr);				kfree(todo);			} else {				list_add_tail(&addr->entry, &card->ip_list);				list_add_tail(&todo->entry, &failed_todos);			}		}	}	spin_unlock_irqrestore(&card->ip_lock, flags);	qeth_reinsert_todos(card, &failed_todos);}static void qeth_delete_mc_addresses(struct qeth_card *);static void qeth_add_multicast_ipv4(struct qeth_card *);#ifdef CONFIG_QETH_IPV6static void qeth_add_multicast_ipv6(struct qeth_card *);#endifstatic inline intqeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread){	unsigned long flags;	spin_lock_irqsave(&card->thread_mask_lock, flags);	if ( !(card->thread_allowed_mask & thread) ||	      (card->thread_start_mask & thread) ) {		spin_unlock_irqrestore(&card->thread_mask_lock, flags);		return -EPERM;	}	card->thread_start_mask |= thread;	spin_unlock_irqrestore(&card->thread_mask_lock, flags);	return 0;}static voidqeth_clear_thread_start_bit(struct qeth_card *card, unsigned long thread){	unsigned long flags;	spin_lock_irqsave(&card->thread_mask_lock, flags);	card->thread_start_mask &= ~thread;	spin_unlock_irqrestore(&card->thread_mask_lock, flags);	wake_up(&card->wait_q);}static voidqeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread){	unsigned long flags;	spin_lock_irqsave(&card->thread_mask_lock, flags);	card->thread_running_mask &= ~thread;	spin_unlock_irqrestore(&card->thread_mask_lock, flags);	wake_up(&card->wait_q);}static inline int__qeth_do_run_thread(struct qeth_card *card, unsigned long thread){	unsigned long flags;	int rc = 0;	spin_lock_irqsave(&card->thread_mask_lock, flags);	if (card->thread_start_mask & thread){		if ((card->thread_allowed_mask & thread) &&		    !(card->thread_running_mask & thread)){			rc = 1;			card->thread_start_mask &= ~thread;			card->thread_running_mask |= thread;		} else			rc = -EPERM;	}	spin_unlock_irqrestore(&card->thread_mask_lock, flags);	return rc;}static intqeth_do_run_thread(struct qeth_card *card, unsigned long thread){	int rc = 0;	wait_event(card->wait_q,		   (rc = __qeth_do_run_thread(card, thread)) >= 0);	return rc;}static intqeth_register_mc_addresses(void *ptr){	struct qeth_card *card;	card = (struct qeth_card *) ptr;	daemonize("qeth_reg_mcaddrs");	QETH_DBF_TEXT(trace,4,"regmcth1");	if (!qeth_do_run_thread(card, QETH_SET_MC_THREAD))		return 0;	QETH_DBF_TEXT(trace,4,"regmcth2");	qeth_delete_mc_addresses(card);	qeth_add_multicast_ipv4(card);#ifdef CONFIG_QETH_IPV6	qeth_add_multicast_ipv6(card);#endif	qeth_set_ip_addr_list(card);	qeth_clear_thread_running_bit(card, QETH_SET_MC_THREAD);	return 0;}static intqeth_register_ip_address(void *ptr){	struct qeth_card *card;	card = (struct qeth_card *) ptr;	daemonize("qeth_reg_ip");	QETH_DBF_TEXT(trace,4,"regipth1");	if (!qeth_do_run_thread(card, QETH_SET_IP_THREAD))		return 0;	QETH_DBF_TEXT(trace,4,"regipth2");	qeth_set_ip_addr_list(card);	qeth_clear_thread_running_bit(card, QETH_SET_IP_THREAD);	return 0;}static intqeth_recover(void *ptr){	struct qeth_card *card;	int rc = 0;	card = (struct qeth_card *) ptr;	daemonize("qeth_recover");	QETH_DBF_TEXT(trace,2,"recover1");	QETH_DBF_HEX(trace, 2, &card, sizeof(void *));	if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))		return 0;	QETH_DBF_TEXT(trace,2,"recover2");	PRINT_WARN("Recovery of device %s started ...\n",		   CARD_BUS_ID(card));	card->use_hard_stop = 1;	qeth_set_offline(card->gdev);	rc = qeth_set_online(card->gdev);	if (!rc)		PRINT_INFO("Device %s successfully recovered!\n",			   CARD_BUS_ID(card));	else		PRINT_INFO("Device %s could not be recovered!\n",			   CARD_BUS_ID(card));	/* don't run another scheduled recovery */	qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);	qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);	return 0;}voidqeth_schedule_recovery(struct qeth_card *card){	QETH_DBF_TEXT(trace,2,"startrec");	if (qeth_set_thread_start_bit(card, QETH_RECOVER_THREAD) == 0)		schedule_work(&card->kernel_thread_starter);}static intqeth_do_start_thread(struct qeth_card *card, unsigned long thread){	unsigned long flags;	int rc = 0;	spin_lock_irqsave(&card->thread_mask_lock, flags);	QETH_DBF_TEXT_(trace, 4, "  %02x%02x%02x",			(u8) card->thread_start_mask,			(u8) card->thread_allowed_mask,			(u8) card->thread_running_mask);	rc = (card->thread_start_mask & thread);	spin_unlock_irqrestore(&card->thread_mask_lock, flags);	return rc;}static voidqeth_start_kernel_thread(struct qeth_card *card){	QETH_DBF_TEXT(trace , 2, "strthrd");	if (card->read.state != CH_STATE_UP &&	    card->write.state != CH_STATE_UP)

⌨️ 快捷键说明

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