📄 ibmtr.c
字号:
dhb=dhb_base & ~(ti->page_mask << 8); } dhb += ti->sram_virt; /* Figure out the size of the 802.5 header */ if (!(trhdr->saddr[0] & 0x80)) /* RIF present? */ hdr_len = sizeof(struct trh_hdr) - TR_MAXRIFLEN; else hdr_len = ((ntohs(trhdr->rcf) & TR_RCF_LEN_MASK) >> 8) + sizeof(struct trh_hdr) - TR_MAXRIFLEN; llc = (struct trllc *) (ti->current_skb->data + hdr_len); llc_ssap = llc->ssap; SET_PAGE(ti->srb_page); memcpy_fromio(&xsrb, ti->srb, sizeof(xsrb)); SET_PAGE(ti->asb_page); xmit_command = xsrb.command; writeb(xmit_command, ti->asb + COMMAND_OFST); writew(xsrb.station_id, ti->asb + STATION_ID_OFST); writeb(llc_ssap, ti->asb + RSAP_VALUE_OFST); writeb(xsrb.cmd_corr, ti->asb + CMD_CORRELATE_OFST); writeb(0, ti->asb + RETCODE_OFST); if ((xmit_command == XMIT_XID_CMD) || (xmit_command == XMIT_TEST_CMD)) { writew(htons(0x11), ti->asb + FRAME_LENGTH_OFST); writeb(0x0e, ti->asb + HEADER_LENGTH_OFST); SET_PAGE(dhb_page); writeb(AC, dhb); writeb(LLC_FRAME, dhb + 1); for (i = 0; i < TR_ALEN; i++) writeb((int) 0x0FF, dhb + i + 2); for (i = 0; i < TR_ALEN; i++) writeb(0, dhb + i + TR_ALEN + 2); writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); return; } /* * the token ring packet is copied from sk_buff to the adapter * buffer identified in the command data received with the interrupt. */ writeb(hdr_len, ti->asb + HEADER_LENGTH_OFST); writew(htons(ti->current_skb->len), ti->asb + FRAME_LENGTH_OFST); src_len=ti->current_skb->len; src_offset=0; dhb=dhb_base; while(1) { if (ti->page_mask) { dhb_page=(dhb >> 8) & ti->page_mask; dhb=dhb & ~(ti->page_mask << 8); dhb_len=0x4000-dhb; /* remaining size of this page */ } dhb+=ti->sram_virt; SET_PAGE(dhb_page); if (src_len > dhb_len) { memcpy_toio(dhb,&ti->current_skb->data[src_offset], dhb_len); src_len -= dhb_len; src_offset += dhb_len; dhb_base+=dhb_len; dhb=dhb_base; continue; } memcpy_toio(dhb, &ti->current_skb->data[src_offset], src_len); break; } writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); ti->tr_stats.tx_bytes += ti->current_skb->len; dev_kfree_skb_irq(ti->current_skb); ti->current_skb = NULL; netif_wake_queue(dev); if (ti->readlog_pending) ibmtr_readlog(dev);} /*tr_tx *//*****************************************************************************/#define RECEIVE_BUFFER_OFST 6#define LAN_HDR_LENGTH_OFST 8#define DLC_HDR_LENGTH_OFST 9#define DSAP_OFST 0#define SSAP_OFST 1#define LLC_OFST 2#define PROTID_OFST 3#define ETHERTYPE_OFST 6static void tr_rx(struct net_device *dev){ struct tok_info *ti = (struct tok_info *) dev->priv; __u32 rbuffer, rbufdata; __u8 rbuffer_page = 0; __u32 llc; unsigned char *data; unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length; unsigned char dlc_hdr_len; struct sk_buff *skb; unsigned int skb_size = 0; int IPv4_p = 0; unsigned int chksum = 0; struct iphdr *iph; struct arb_rec_req rarb; SET_PAGE(ti->arb_page); memcpy_fromio(&rarb, ti->arb, sizeof(rarb)); rbuffer = ntohs(rarb.rec_buf_addr) ; if (ti->page_mask) { rbuffer_page = (rbuffer >> 8) & ti->page_mask; rbuffer &= ~(ti->page_mask << 8); } rbuffer += ti->sram_virt; SET_PAGE(ti->asb_page); if (readb(ti->asb + RETCODE_OFST) !=0xFF) DPRINTK("ASB not free !!!\n"); writeb(REC_DATA, ti->asb + COMMAND_OFST); writew(rarb.station_id, ti->asb + STATION_ID_OFST); writew(rarb.rec_buf_addr, ti->asb + RECEIVE_BUFFER_OFST); lan_hdr_len = rarb.lan_hdr_len; if (lan_hdr_len > sizeof(struct trh_hdr)) { DPRINTK("Linux cannot handle greater than 18 bytes RIF\n"); return; } /*BMS I added this above just to be very safe */ dlc_hdr_len = readb(ti->arb + DLC_HDR_LENGTH_OFST); hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr); SET_PAGE(rbuffer_page); llc = (rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len);#if TR_VERBOSE DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n", (__u32) offsetof(struct rec_buf, data), (unsigned int) lan_hdr_len); DPRINTK("llc: %08X rec_buf_addr: %04X dev->mem_start: %lX\n", llc, ntohs(rarb.rec_buf_addr), dev->mem_start); DPRINTK("dsap: %02X, ssap: %02X, llc: %02X, protid: %02X%02X%02X, " "ethertype: %04X\n", (int) readb(llc + DSAP_OFST), (int) readb(llc + SSAP_OFST), (int) readb(llc + LLC_OFST), (int) readb(llc + PROTID_OFST), (int) readb(llc+PROTID_OFST+1),(int)readb(llc+PROTID_OFST + 2), (int) ntohs(readw(llc + ETHERTYPE_OFST)));#endif if (readb(llc + offsetof(struct trllc, llc)) != UI_CMD) { SET_PAGE(ti->asb_page); writeb(DATA_LOST, ti->asb + RETCODE_OFST); ti->tr_stats.rx_dropped++; writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); return; } length = ntohs(rarb.frame_len); if (readb(llc + DSAP_OFST) == EXTENDED_SAP && readb(llc + SSAP_OFST) == EXTENDED_SAP && length >= hdr_len) IPv4_p = 1;#if TR_VERBOSE#define SADDR_OFST 8#define DADDR_OFST 2 if (!IPv4_p) { __u32 trhhdr; trhhdr = (rbuffer + offsetof(struct rec_buf, data)); DPRINTK("Probably non-IP frame received.\n"); DPRINTK("ssap: %02X dsap: %02X " "saddr: %02X:%02X:%02X:%02X:%02X:%02X " "daddr: %02X:%02X:%02X:%02X:%02X:%02X\n", readb(llc + SSAP_OFST), readb(llc + DSAP_OFST), readb(trhhdr+SADDR_OFST), readb(trhhdr+ SADDR_OFST+1), readb(trhhdr+SADDR_OFST+2), readb(trhhdr+SADDR_OFST+3), readb(trhhdr+SADDR_OFST+4), readb(trhhdr+SADDR_OFST+5), readb(trhhdr+DADDR_OFST), readb(trhhdr+DADDR_OFST + 1), readb(trhhdr+DADDR_OFST+2), readb(trhhdr+DADDR_OFST+3), readb(trhhdr+DADDR_OFST+4), readb(trhhdr+DADDR_OFST+5)); }#endif /*BMS handle the case she comes in with few hops but leaves with many */ skb_size=length-lan_hdr_len+sizeof(struct trh_hdr)+sizeof(struct trllc); if (!(skb = dev_alloc_skb(skb_size))) { DPRINTK("out of memory. frame dropped.\n"); ti->tr_stats.rx_dropped++; SET_PAGE(ti->asb_page); writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code)); writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); return; } /*BMS again, if she comes in with few but leaves with many */ skb_reserve(skb, sizeof(struct trh_hdr) - lan_hdr_len); skb_put(skb, length); skb->dev = dev; data = skb->data; rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len))); rbufdata = rbuffer + offsetof(struct rec_buf, data); if (IPv4_p) { /* Copy the headers without checksumming */ memcpy_fromio(data, rbufdata, hdr_len); /* Watch for padded packets and bogons */ iph= (struct iphdr *)(data+ lan_hdr_len + sizeof(struct trllc)); ip_len = ntohs(iph->tot_len) - sizeof(struct iphdr); length -= hdr_len; if ((ip_len <= length) && (ip_len > 7)) length = ip_len; data += hdr_len; rbuffer_len -= hdr_len; rbufdata += hdr_len; } /* Copy the payload... */#define BUFFER_POINTER_OFST 2#define BUFFER_LENGTH_OFST 6 for (;;) { if (ibmtr_debug_trace&TRC_INITV && length < rbuffer_len) DPRINTK("CURIOUS, length=%d < rbuffer_len=%d\n", length,rbuffer_len); if (IPv4_p) chksum=csum_partial_copy_nocheck((void*)rbufdata, data,length<rbuffer_len?length:rbuffer_len,chksum); else memcpy_fromio(data, rbufdata, rbuffer_len); rbuffer = ntohs(readw(rbuffer+BUFFER_POINTER_OFST)) ; if (!rbuffer) break; rbuffer -= 2; length -= rbuffer_len; data += rbuffer_len; if (ti->page_mask) { rbuffer_page = (rbuffer >> 8) & ti->page_mask; rbuffer &= ~(ti->page_mask << 8); } rbuffer += ti->sram_virt; SET_PAGE(rbuffer_page); rbuffer_len = ntohs(readw(rbuffer + BUFFER_LENGTH_OFST)); rbufdata = rbuffer + offsetof(struct rec_buf, data); } SET_PAGE(ti->asb_page); writeb(0, ti->asb + offsetof(struct asb_rec, ret_code)); writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); ti->tr_stats.rx_bytes += skb->len; ti->tr_stats.rx_packets++; skb->protocol = tr_type_trans(skb, dev); if (IPv4_p) { skb->csum = chksum; skb->ip_summed = 1; } netif_rx(skb); dev->last_rx = jiffies;} /*tr_rx *//*****************************************************************************/void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev){ tmr->expires = jiffies + TR_RETRY_INTERVAL; tmr->data = (unsigned long) dev; tmr->function = tok_rerun; init_timer(tmr); add_timer(tmr);}/*****************************************************************************/void tok_rerun(unsigned long dev_addr){ struct net_device *dev = (struct net_device *)dev_addr; struct tok_info *ti = (struct tok_info *) dev->priv; if ( ti->open_action == RESTART){ ti->do_tok_int = FIRST_INT; outb(0, dev->base_addr + ADAPTRESETREL);#ifdef ENABLE_PAGING if (ti->page_mask) writeb(SRPR_ENABLE_PAGING, ti->mmio + ACA_OFFSET + ACA_RW + SRPR_EVEN);#endif writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); } else tok_open_adapter(dev_addr);}/*****************************************************************************/void ibmtr_readlog(struct net_device *dev){ struct tok_info *ti; ti = (struct tok_info *) dev->priv; ti->readlog_pending = 0; SET_PAGE(ti->srb_page); writeb(DIR_READ_LOG, ti->srb); writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); netif_stop_queue(dev);}/*****************************************************************************//* tok_get_stats(): Basically a scaffold routine which will return the address of the tr_statistics structure associated with this device -- the tr.... structure is an ethnet look-alike so at least for this iteration may suffice. */static struct net_device_stats *tok_get_stats(struct net_device *dev){ struct tok_info *toki; toki = (struct tok_info *) dev->priv; return (struct net_device_stats *) &toki->tr_stats;}/*****************************************************************************/int ibmtr_change_mtu(struct net_device *dev, int mtu){ struct tok_info *ti = (struct tok_info *) dev->priv; if (ti->ring_speed == 16 && mtu > ti->maxmtu16) return -EINVAL; if (ti->ring_speed == 4 && mtu > ti->maxmtu4) return -EINVAL; dev->mtu = mtu; return 0;}/*****************************************************************************/#ifdef MODULE/* 3COM 3C619C supports 8 interrupts, 32 I/O ports */static struct net_device *dev_ibmtr[IBMTR_MAX_ADAPTERS];static int io[IBMTR_MAX_ADAPTERS] = { 0xa20, 0xa24 };static int irq[IBMTR_MAX_ADAPTERS];static int mem[IBMTR_MAX_ADAPTERS];MODULE_LICENSE("GPL");module_param_array(io, int, NULL, 0);module_param_array(irq, int, NULL, 0);module_param_array(mem, int, NULL, 0);static int __init ibmtr_init(void){ int i; int count=0; find_turbo_adapters(io); for (i = 0; io[i] && (i < IBMTR_MAX_ADAPTERS); i++) { struct net_device *dev; irq[i] = 0; mem[i] = 0; dev = alloc_trdev(sizeof(struct tok_info)); if (dev == NULL) { if (i == 0) return -ENOMEM; break; } dev->base_addr = io[i]; dev->irq = irq[i]; dev->mem_start = mem[i]; if (ibmtr_probe_card(dev)) { free_netdev(dev); continue; } dev_ibmtr[i] = dev; count++; } if (count) return 0; printk("ibmtr: register_netdev() returned non-zero.\n"); return -EIO;}module_init(ibmtr_init);static void __exit ibmtr_cleanup(void){ int i; for (i = 0; i < IBMTR_MAX_ADAPTERS; i++){ if (!dev_ibmtr[i]) continue; unregister_netdev(dev_ibmtr[i]); ibmtr_cleanup_card(dev_ibmtr[i]); free_netdev(dev_ibmtr[i]); }}module_exit(ibmtr_cleanup);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -