qeth_main.c
来自「linux 内核源代码」· C语言 代码 · 共 2,480 行 · 第 1/5 页
C
2,480 行
static inline voidqeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, char prot_type){ memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data),&prot_type,1); memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);}static intqeth_osn_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, int data_len){ u16 s1, s2; QETH_DBF_TEXT(trace,4,"osndipa"); qeth_prepare_ipa_cmd(card, iob, QETH_PROT_OSN2); s1 = (u16)(IPA_PDU_HEADER_SIZE + data_len); s2 = (u16)data_len; memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2); memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2); memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2); memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2); return qeth_osn_send_control_data(card, s1, iob);}static intqeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, int (*reply_cb) (struct qeth_card *,struct qeth_reply*, unsigned long), void *reply_param){ int rc; char prot_type; QETH_DBF_TEXT(trace,4,"sendipa"); if (card->options.layer2) if (card->info.type == QETH_CARD_TYPE_OSN) prot_type = QETH_PROT_OSN2; else prot_type = QETH_PROT_LAYER2; else prot_type = QETH_PROT_TCPIP; qeth_prepare_ipa_cmd(card,iob,prot_type); rc = qeth_send_control_data(card, IPA_CMD_LENGTH, iob, reply_cb, reply_param); return rc;}static intqeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data){ struct qeth_cmd_buffer *iob; QETH_DBF_TEXT(setup, 2, "cmenblcb"); iob = (struct qeth_cmd_buffer *) data; memcpy(&card->token.cm_filter_r, QETH_CM_ENABLE_RESP_FILTER_TOKEN(iob->data), QETH_MPC_TOKEN_LENGTH); QETH_DBF_TEXT_(setup, 2, " rc%d", iob->rc); return 0;}static intqeth_cm_enable(struct qeth_card *card){ int rc; struct qeth_cmd_buffer *iob; QETH_DBF_TEXT(setup,2,"cmenable"); iob = qeth_wait_for_buffer(&card->write); memcpy(iob->data, CM_ENABLE, CM_ENABLE_SIZE); memcpy(QETH_CM_ENABLE_ISSUER_RM_TOKEN(iob->data), &card->token.issuer_rm_r, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_CM_ENABLE_FILTER_TOKEN(iob->data), &card->token.cm_filter_w, QETH_MPC_TOKEN_LENGTH); rc = qeth_send_control_data(card, CM_ENABLE_SIZE, iob, qeth_cm_enable_cb, NULL); return rc;}static intqeth_cm_setup_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data){ struct qeth_cmd_buffer *iob; QETH_DBF_TEXT(setup, 2, "cmsetpcb"); iob = (struct qeth_cmd_buffer *) data; memcpy(&card->token.cm_connection_r, QETH_CM_SETUP_RESP_DEST_ADDR(iob->data), QETH_MPC_TOKEN_LENGTH); QETH_DBF_TEXT_(setup, 2, " rc%d", iob->rc); return 0;}static intqeth_cm_setup(struct qeth_card *card){ int rc; struct qeth_cmd_buffer *iob; QETH_DBF_TEXT(setup,2,"cmsetup"); iob = qeth_wait_for_buffer(&card->write); memcpy(iob->data, CM_SETUP, CM_SETUP_SIZE); memcpy(QETH_CM_SETUP_DEST_ADDR(iob->data), &card->token.issuer_rm_r, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_CM_SETUP_CONNECTION_TOKEN(iob->data), &card->token.cm_connection_w, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_CM_SETUP_FILTER_TOKEN(iob->data), &card->token.cm_filter_r, QETH_MPC_TOKEN_LENGTH); rc = qeth_send_control_data(card, CM_SETUP_SIZE, iob, qeth_cm_setup_cb, NULL); return rc;}static intqeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data){ __u16 mtu, framesize; __u16 len; __u8 link_type; struct qeth_cmd_buffer *iob; QETH_DBF_TEXT(setup, 2, "ulpenacb"); iob = (struct qeth_cmd_buffer *) data; memcpy(&card->token.ulp_filter_r, QETH_ULP_ENABLE_RESP_FILTER_TOKEN(iob->data), QETH_MPC_TOKEN_LENGTH); if (qeth_get_mtu_out_of_mpc(card->info.type)) { memcpy(&framesize, QETH_ULP_ENABLE_RESP_MAX_MTU(iob->data), 2); mtu = qeth_get_mtu_outof_framesize(framesize); if (!mtu) { iob->rc = -EINVAL; QETH_DBF_TEXT_(setup, 2, " rc%d", iob->rc); return 0; } card->info.max_mtu = mtu; card->info.initial_mtu = mtu; card->qdio.in_buf_size = mtu + 2 * PAGE_SIZE; } else { card->info.initial_mtu = qeth_get_initial_mtu_for_card(card); card->info.max_mtu = qeth_get_max_mtu_for_card(card->info.type); card->qdio.in_buf_size = QETH_IN_BUF_SIZE_DEFAULT; } memcpy(&len, QETH_ULP_ENABLE_RESP_DIFINFO_LEN(iob->data), 2); if (len >= QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE) { memcpy(&link_type, QETH_ULP_ENABLE_RESP_LINK_TYPE(iob->data), 1); card->info.link_type = link_type; } else card->info.link_type = 0; QETH_DBF_TEXT_(setup, 2, " rc%d", iob->rc); return 0;}static intqeth_ulp_enable(struct qeth_card *card){ int rc; char prot_type; struct qeth_cmd_buffer *iob; /*FIXME: trace view callbacks*/ QETH_DBF_TEXT(setup,2,"ulpenabl"); iob = qeth_wait_for_buffer(&card->write); memcpy(iob->data, ULP_ENABLE, ULP_ENABLE_SIZE); *(QETH_ULP_ENABLE_LINKNUM(iob->data)) = (__u8) card->info.portno; if (card->options.layer2) if (card->info.type == QETH_CARD_TYPE_OSN) prot_type = QETH_PROT_OSN2; else prot_type = QETH_PROT_LAYER2; else prot_type = QETH_PROT_TCPIP; memcpy(QETH_ULP_ENABLE_PROT_TYPE(iob->data),&prot_type,1); memcpy(QETH_ULP_ENABLE_DEST_ADDR(iob->data), &card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_ULP_ENABLE_FILTER_TOKEN(iob->data), &card->token.ulp_filter_w, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_ULP_ENABLE_PORTNAME_AND_LL(iob->data), card->info.portname, 9); rc = qeth_send_control_data(card, ULP_ENABLE_SIZE, iob, qeth_ulp_enable_cb, NULL); return rc;}static intqeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply, unsigned long data){ struct qeth_cmd_buffer *iob; QETH_DBF_TEXT(setup, 2, "ulpstpcb"); iob = (struct qeth_cmd_buffer *) data; memcpy(&card->token.ulp_connection_r, QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(iob->data), QETH_MPC_TOKEN_LENGTH); QETH_DBF_TEXT_(setup, 2, " rc%d", iob->rc); return 0;}static intqeth_ulp_setup(struct qeth_card *card){ int rc; __u16 temp; struct qeth_cmd_buffer *iob; struct ccw_dev_id dev_id; QETH_DBF_TEXT(setup,2,"ulpsetup"); iob = qeth_wait_for_buffer(&card->write); memcpy(iob->data, ULP_SETUP, ULP_SETUP_SIZE); memcpy(QETH_ULP_SETUP_DEST_ADDR(iob->data), &card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_ULP_SETUP_CONNECTION_TOKEN(iob->data), &card->token.ulp_connection_w, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_ULP_SETUP_FILTER_TOKEN(iob->data), &card->token.ulp_filter_r, QETH_MPC_TOKEN_LENGTH); ccw_device_get_id(CARD_DDEV(card), &dev_id); memcpy(QETH_ULP_SETUP_CUA(iob->data), &dev_id.devno, 2); temp = (card->info.cula << 8) + card->info.unit_addr2; memcpy(QETH_ULP_SETUP_REAL_DEVADDR(iob->data), &temp, 2); rc = qeth_send_control_data(card, ULP_SETUP_SIZE, iob, qeth_ulp_setup_cb, NULL); return rc;}static inline intqeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error, unsigned int siga_error, const char *dbftext){ if (qdio_error || siga_error) { QETH_DBF_TEXT(trace, 2, dbftext); QETH_DBF_TEXT(qerr, 2, dbftext); QETH_DBF_TEXT_(qerr, 2, " F15=%02X", buf->element[15].flags & 0xff); QETH_DBF_TEXT_(qerr, 2, " F14=%02X", buf->element[14].flags & 0xff); QETH_DBF_TEXT_(qerr, 2, " qerr=%X", qdio_error); QETH_DBF_TEXT_(qerr, 2, " serr=%X", siga_error); return 1; } return 0;}static struct sk_buff *qeth_get_skb(unsigned int length, struct qeth_hdr *hdr){ struct sk_buff* skb; int add_len; add_len = 0; if (hdr->hdr.osn.id == QETH_HEADER_TYPE_OSN) add_len = sizeof(struct qeth_hdr);#ifdef CONFIG_QETH_VLAN else add_len = VLAN_HLEN;#endif skb = dev_alloc_skb(length + add_len); if (skb && add_len) skb_reserve(skb, add_len); return skb;}static inline intqeth_create_skb_frag(struct qdio_buffer_element *element, struct sk_buff **pskb, int offset, int *pfrag, int data_len){ struct page *page = virt_to_page(element->addr); if (*pfrag == 0) { /* the upper protocol layers assume that there is data in the * skb itself. Copy a small amount (64 bytes) to make them * happy. */ *pskb = dev_alloc_skb(64 + QETH_FAKE_LL_LEN_ETH); if (!(*pskb)) return -ENOMEM; skb_reserve(*pskb, QETH_FAKE_LL_LEN_ETH); if (data_len <= 64) { memcpy(skb_put(*pskb, data_len), element->addr + offset, data_len); } else { get_page(page); memcpy(skb_put(*pskb, 64), element->addr + offset, 64); skb_fill_page_desc(*pskb, *pfrag, page, offset + 64, data_len - 64); (*pskb)->data_len += data_len - 64; (*pskb)->len += data_len - 64; (*pskb)->truesize += data_len - 64; } } else { get_page(page); skb_fill_page_desc(*pskb, *pfrag, page, offset, data_len); (*pskb)->data_len += data_len; (*pskb)->len += data_len; (*pskb)->truesize += data_len; } (*pfrag)++; return 0;}static inline struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry(struct qeth_card *card){ struct list_head *plh; struct qeth_buffer_pool_entry *entry; int i, free; struct page *page; if (list_empty(&card->qdio.in_buf_pool.entry_list)) return NULL; list_for_each(plh, &card->qdio.in_buf_pool.entry_list) { entry = list_entry(plh, struct qeth_buffer_pool_entry, list); free = 1; for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { if (page_count(virt_to_page(entry->elements[i])) > 1) { free = 0; break; } } if (free) { list_del_init(&entry->list); return entry; } } /* no free buffer in pool so take first one and swap pages */ entry = list_entry(card->qdio.in_buf_pool.entry_list.next, struct qeth_buffer_pool_entry, list); for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { if (page_count(virt_to_page(entry->elements[i])) > 1) { page = alloc_page(GFP_ATOMIC|GFP_DMA); if (!page) { return NULL; } else { free_page((unsigned long)entry->elements[i]); entry->elements[i] = page_address(page); if (card->options.performance_stats) card->perf_stats.sg_alloc_page_rx++; } } } list_del_init(&entry->list); return entry;}static struct sk_buff *qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, struct qdio_buffer_element **__element, int *__offset, struct qeth_hdr **hdr){ struct qdio_buffer_element *element = *__element; int offset = *__offset; struct sk_buff *skb = NULL; int skb_len; void *data_ptr; int data_len; int use_rx_sg = 0; int frag = 0; QETH_DBF_TEXT(trace,6,"nextskb"); /* qeth_hdr must not cross element boundaries */ if (element->length < offset + sizeof(struct qeth_hdr)){ if (qeth_is_last_sbale(element)) return NULL; element++; offset = 0; if (element->length < sizeof(struct qeth_hdr)) return NULL; } *hdr = element->addr + offset; offset += sizeof(struct qeth_hdr); if (card->options.layer2) if (card->info.type == QETH_CARD_TYPE_OSN) skb_len = (*hdr)->hdr.osn.pdu_length; else skb_len = (*hdr)->hdr.l2.pkt_length; else skb_len = (*hdr)->hdr.l3.length; if (!skb_len) return NULL; if ((skb_len >= card->options.rx_sg_cb) && (!(card->info.type == QETH_CARD_TYPE_OSN)) && (!atomic_read(&card->force_alloc_skb))) { use_rx_sg = 1; } else { if (card->options.fake_ll) { if (card->dev->type == ARPHRD_IEEE802_TR) { if (!(skb = qeth_get_skb(skb_len + QETH_FAKE_LL_LEN_TR, *hdr))) goto no_mem; skb_reserve(skb, QETH_FAKE_LL_LEN_TR); } else { if (!(skb = qeth_get_skb(skb_len + QETH_FAKE_LL_LEN_ETH, *hdr))) goto no_mem; skb_reserve(skb, QETH_FAKE_LL_LEN_ETH); } } else { skb = qeth_get_skb(skb_len, *hdr); if (!skb) goto no_mem; } } data_ptr = element->addr + offset; while (skb_len) { data_len = min(skb_len, (int)(element->length - offset)); if (data_len) { if (use_rx_sg) { if (qeth_create_skb_frag(element, &skb, offset, &frag, data_len)) goto no_mem; } else { memcpy(skb_put(skb, data_len), data_ptr, data_len); } } skb_len -= data_len; if (skb_len){ if (qeth_is_last_sbale(element)){ QETH_DBF_TEXT(trace,4,"unexeob"); QETH_DBF_TEXT_(trace,4,"%s",CARD_BUS_ID(card)); QETH_DBF_TEXT(qerr,2,"unexeob"); QETH_DBF_TEXT_(qerr,2,"%s",CARD_BUS_ID(card)); QETH_DBF_HEX(misc,4,buffer,sizeof(*buffer)); dev_kfree_skb_any(skb); card->stats.rx_errors++; return NULL; } element++; offset = 0; data_ptr = element->addr; } else { offset += data_len; } } *__element = element; *__offset = offset; if (use_rx_sg && card->options.performance_stats) { card->perf_stats.sg_skbs_rx++; card->perf_stats.sg_frags_rx += skb_shinfo(skb)->nr_frags; } return skb;no_mem: if (net_ratelimit()){ PRINT_WARN("No memory for packet received on %s.\n", QETH_CARD_IFNAME(card)); QETH_DBF_TEXT(trace,2,"noskbmem"); QETH_DBF_TEXT_(trace,2,"%s",CARD_BUS_ID(card)); } card->stats.rx_dropped++; return NULL;}static __be16qeth_type_trans(struct sk_buff *skb, struct net_device *dev){ struct qeth_card *card; struct ethhdr *eth; QETH_DBF_TEXT(trace,6,"typtrans"); card = (struct qeth_card *)dev->priv;#ifdef CONFIG_TR if ((card->in
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?