📄 ibmtr.c
字号:
writew(htons(MAX_I_FIELD), ti->srb + offsetof(struct dlc_open_sap, max_i_field)); writeb(SAP_OPEN_IND_SAP | SAP_OPEN_PRIORITY, ti->srb + offsetof(struct dlc_open_sap, sap_options)); writeb(SAP_OPEN_STATION_CNT, ti->srb + offsetof(struct dlc_open_sap, station_count)); writeb(type, ti->srb + offsetof(struct dlc_open_sap, sap_value)); writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);}void tok_open_adapter(unsigned long dev_addr){ struct device *dev=(struct device *)dev_addr; struct tok_info *ti; int i; ti=(struct tok_info *) dev->priv;#if !TR_NEWFORMAT DPRINTK("now opening the board...\n");#endif writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD); writeb(~CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_RESET + ISRA_ODD); for (i=0; i<sizeof(struct dir_open_adapter); i++) writeb(0, ti->init_srb+i); writeb(DIR_OPEN_ADAPTER, ti->init_srb + offsetof(struct dir_open_adapter, command)); writew(htons(OPEN_PASS_BCON_MAC), ti->init_srb + offsetof(struct dir_open_adapter, open_options)); if (ti->ring_speed == 16) { writew(htons(ti->dhb_size16mb), ti->init_srb + offsetof(struct dir_open_adapter, dhb_length)); writew(htons(ti->rbuf_cnt16), ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf)); writew(htons(ti->rbuf_len16), ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len)); } else { writew(htons(ti->dhb_size4mb), ti->init_srb + offsetof(struct dir_open_adapter, dhb_length)); writew(htons(ti->rbuf_cnt4), ti->init_srb + offsetof(struct dir_open_adapter, num_rcv_buf)); writew(htons(ti->rbuf_len4), ti->init_srb + offsetof(struct dir_open_adapter, rcv_buf_len)); } writeb(NUM_DHB, /* always 2 */ ti->init_srb + offsetof(struct dir_open_adapter, num_dhb)); writeb(DLC_MAX_SAP, ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sap)); writeb(DLC_MAX_STA, ti->init_srb + offsetof(struct dir_open_adapter, dlc_max_sta)); ti->srb=ti->init_srb; /* We use this one in the interrupt handler */ writeb(INT_ENABLE, ti->mmio + ACA_OFFSET + ACA_SET + ISRP_EVEN); writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);}static void tr_tx(struct device *dev){ struct tok_info *ti=(struct tok_info *) dev->priv; struct trh_hdr *trhdr=(struct trh_hdr *)ti->current_skb->data; unsigned int hdr_len; __u32 dhb; unsigned char xmit_command; int i; struct trllc *llc; if (readb(ti->asb + offsetof(struct asb_xmit_resp, ret_code))!=0xFF) DPRINTK("ASB not free !!!\n"); /* in providing the transmit interrupts, is telling us it is ready for data and providing a shared memory address for us to stuff with data. Here we compute the effective address where we will place data.*/ dhb=ti->sram +ntohs(readw(ti->arb + offsetof(struct arb_xmit_req, dhb_address))); /* 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); xmit_command = readb(ti->srb + offsetof(struct srb_xmit, command)); writeb(xmit_command, ti->asb + offsetof(struct asb_xmit_resp, command)); writew(readb(ti->srb + offsetof(struct srb_xmit, station_id)), ti->asb + offsetof(struct asb_xmit_resp, station_id)); writeb(llc->ssap, ti->asb + offsetof(struct asb_xmit_resp, rsap_value)); writeb(readb(ti->srb + offsetof(struct srb_xmit, cmd_corr)), ti->asb + offsetof(struct asb_xmit_resp, cmd_corr)); writeb(0, ti->asb + offsetof(struct asb_xmit_resp, ret_code)); if ((xmit_command==XMIT_XID_CMD) || (xmit_command==XMIT_TEST_CMD)) { writew(htons(0x11), ti->asb + offsetof(struct asb_xmit_resp, frame_length)); writeb(0x0e, ti->asb + offsetof(struct asb_xmit_resp, hdr_length)); 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 + offsetof(struct asb_xmit_resp, hdr_length)); writew(htons(ti->current_skb->len), ti->asb + offsetof(struct asb_xmit_resp, frame_length)); memcpy_toio(dhb, ti->current_skb->data, ti->current_skb->len); writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); ti->tr_stats.tx_bytes+=ti->current_skb->len; dev->tbusy=0; dev_kfree_skb(ti->current_skb); ti->current_skb=NULL; mark_bh(NET_BH); if (ti->readlog_pending) ibmtr_readlog(dev);}static void tr_rx(struct device *dev){ struct tok_info *ti=(struct tok_info *) dev->priv; __u32 rbuffer, rbufdata; __u32 llc; unsigned char *data; unsigned int rbuffer_len, lan_hdr_len, hdr_len, ip_len, length; struct sk_buff *skb; unsigned int skb_size = 0; int IPv4_p = 0; unsigned int chksum = 0; struct iphdr *iph; rbuffer=(ti->sram +ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))))+2; if(readb(ti->asb + offsetof(struct asb_rec, ret_code))!=0xFF) DPRINTK("ASB not free !!!\n"); writeb(REC_DATA, ti->asb + offsetof(struct asb_rec, command)); writew(readw(ti->arb + offsetof(struct arb_rec_req, station_id)), ti->asb + offsetof(struct asb_rec, station_id)); writew(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr)), ti->asb + offsetof(struct asb_rec, rec_buf_addr)); lan_hdr_len=readb(ti->arb + offsetof(struct arb_rec_req, lan_hdr_len)); llc=(rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len);#if TR_VERBOSE DPRINTK("offsetof data: %02X lan_hdr_len: %02X\n", (unsigned int)offsetof(struct rec_buf,data), (unsigned int)lan_hdr_len); DPRINTK("llc: %08X rec_buf_addr: %04X ti->sram: %p\n", llc, ntohs(readw(ti->arb + offsetof(struct arb_rec_req, rec_buf_addr))), ti->sram); DPRINTK("dsap: %02X, ssap: %02X, llc: %02X, protid: %02X%02X%02X, " "ethertype: %04X\n", (int)readb(llc + offsetof(struct trllc, dsap)), (int)readb(llc + offsetof(struct trllc, ssap)), (int)readb(llc + offsetof(struct trllc, llc)), (int)readb(llc + offsetof(struct trllc, protid)), (int)readb(llc + offsetof(struct trllc, protid)+1), (int)readb(llc + offsetof(struct trllc, protid)+2), (int)readw(llc + offsetof(struct trllc, ethertype)));#endif if (readb(llc + offsetof(struct trllc, llc))!=UI_CMD) { writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code)); ti->tr_stats.rx_dropped++; writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); return; } if ((readb(llc + offsetof(struct trllc, dsap))==EXTENDED_SAP) && (readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP)) { IPv4_p = 1; }#if TR_VERBOSE 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", (int)readb(llc + offsetof(struct trllc, ssap)), (int)readb(llc + offsetof(struct trllc, dsap)), (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)), (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+1), (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+2), (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+3), (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+4), (int)readb(trhhdr + offsetof(struct trh_hdr, saddr)+5), (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)), (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+1), (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+2), (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+3), (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+4), (int)readb(trhhdr + offsetof(struct trh_hdr, daddr)+5)); }#endif length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len))); 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++; writeb(DATA_LOST, ti->asb + offsetof(struct asb_rec, ret_code)); writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); return; } skb_put(skb, length); skb_reserve(skb, sizeof(struct trh_hdr)-lan_hdr_len+sizeof(struct trllc)); 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 */ hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr); 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... */ for (;;) { if (IPv4_p) chksum = csum_partial_copy(bus_to_virt(rbufdata), data, length < rbuffer_len ? length : rbuffer_len, chksum); else memcpy_fromio(data, rbufdata, rbuffer_len); rbuffer = ntohs(readw(rbuffer)); if (!rbuffer) break; length -= rbuffer_len; data += rbuffer_len; rbuffer += ti->sram; rbuffer_len = ntohs(readw(rbuffer + offsetof(struct rec_buf, buf_len))); rbufdata = rbuffer + offsetof(struct rec_buf, data); } 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);}static int tok_send_packet(struct sk_buff *skb, struct device *dev){ struct tok_info *ti; ti=(struct tok_info *) dev->priv; if (dev->tbusy) { int ticks_waited; ticks_waited=jiffies - dev->trans_start; if (ticks_waited<TR_BUSY_INTERVAL) return 1; DPRINTK("Arrg. Transmitter busy.\n"); dev->trans_start+=5; /* we fake the transmission start time... */ return 1; } if (test_and_set_bit(0,(void *)&dev->tbusy)!=0) DPRINTK("Transmitter access conflict\n"); else { int flags; /* lock against other CPUs */ spin_lock_irqsave(&(ti->lock), flags); /* Save skb; we'll need it when the adapter asks for the data */ ti->current_skb=skb; writeb(XMIT_UI_FRAME, ti->srb + offsetof(struct srb_xmit, command)); writew(ti->exsap_station_id, ti->srb +offsetof(struct srb_xmit, station_id)); writeb(CMD_IN_SRB, (ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD)); spin_unlock_irqrestore(&(ti->lock), flags); dev->trans_start=jiffies; } return 0;}void ibmtr_reset_timer(struct timer_list *tmr, struct device *dev) { tmr->expires = jiffies + TR_RETRY_INTERVAL; tmr->data = (unsigned long) dev; tmr->function = tok_open_adapter; init_timer(tmr); add_timer(tmr);}void ibmtr_readlog(struct device *dev) { struct tok_info *ti; ti=(struct tok_info *) dev->priv; ti->readlog_pending = 0; 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); dev->tbusy=1; /* really srb busy... */}/* 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 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 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 device* dev_ibmtr[IBMTR_MAX_ADAPTERS];static int io[IBMTR_MAX_ADAPTERS] = {0xa20,0xa24};static int irq[IBMTR_MAX_ADAPTERS] = {0,0};static int mem[IBMTR_MAX_ADAPTERS] = {0,0};MODULE_PARM(io, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");MODULE_PARM(irq, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");MODULE_PARM(mem, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");int init_module(void){ int i; for (i = 0; io[i] && (i<IBMTR_MAX_ADAPTERS); i++) { irq[i] = 0; mem[i] = 0; dev_ibmtr[i] = NULL; dev_ibmtr[i] = init_trdev(dev_ibmtr[i], 0); if (dev_ibmtr[i] == NULL) return -ENOMEM; dev_ibmtr[i]->base_addr = io[i]; dev_ibmtr[i]->irq = irq[i]; dev_ibmtr[i]->mem_start = mem[i]; dev_ibmtr[i]->init = &ibmtr_probe; if (register_trdev(dev_ibmtr[i]) != 0) { kfree_s(dev_ibmtr[i], sizeof(struct device)); dev_ibmtr[i] = NULL; if (i == 0) { printk("ibmtr: register_trdev() returned non-zero.\n"); return -EIO; } else { return 0; } } } return 0;}void cleanup_module(void){ int i; for (i = 0; i < IBMTR_MAX_ADAPTERS; i++) if (dev_ibmtr[i]) { unregister_trdev(dev_ibmtr[i]); free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]); release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT); kfree_s(dev_ibmtr[i]->priv, sizeof(struct tok_info)); kfree_s(dev_ibmtr[i], sizeof(struct device)); dev_ibmtr[i] = NULL; }}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -