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 + -
显示快捷键?