📄 olympic.c
字号:
#if OLYMPIC_DEBUG printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA)); printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK)); printk("Before the open command \n");#endif do { int i; save_flags(flags); cli(); for(i=0;i<SRB_COMMAND_SIZE;i+=4) writel(0,init_srb+i); if(SRB_COMMAND_SIZE & 2) writew(0,init_srb+(SRB_COMMAND_SIZE & ~3)); if(SRB_COMMAND_SIZE & 1) writeb(0,init_srb+(SRB_COMMAND_SIZE & ~1)); writeb(SRB_OPEN_ADAPTER,init_srb) ; /* open */ writeb(OLYMPIC_CLEAR_RET_CODE,init_srb+2); /* If Network Monitor, instruct card to copy MAC frames through the ARB */#if OLYMPIC_NETWORK_MONITOR writew(swab16(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), init_srb+8);#else writew(swab16(OPEN_ADAPTER_ENABLE_FDX), init_srb+8);#endif if (olympic_priv->olympic_laa[0]) { writeb(olympic_priv->olympic_laa[0],init_srb+12); writeb(olympic_priv->olympic_laa[1],init_srb+13); writeb(olympic_priv->olympic_laa[2],init_srb+14); writeb(olympic_priv->olympic_laa[3],init_srb+15); writeb(olympic_priv->olympic_laa[4],init_srb+16); writeb(olympic_priv->olympic_laa[5],init_srb+17); memcpy(dev->dev_addr,olympic_priv->olympic_laa,dev->addr_len) ; } writeb(1,init_srb+30); olympic_priv->srb_queued=1; writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); while(olympic_priv->srb_queued) { interruptible_sleep_on_timeout(&olympic_priv->srb_wait, 60*HZ); if(signal_pending(current)) { printk(KERN_WARNING "%s: SRB timed out.\n", dev->name); printk(KERN_WARNING "SISR=%x MISR=%x\n", readl(olympic_mmio+SISR), readl(olympic_mmio+LISR)); olympic_priv->srb_queued=0; break; } } restore_flags(flags);#if OLYMPIC_DEBUG printk("init_srb(%p): ",init_srb); for(i=0;i<20;i++) printk("%02x ",readb(init_srb+i)); printk("\n");#endif /* If we get the same return response as we set, the interrupt wasn't raised and the open * timed out. */ if(readb(init_srb+2)== OLYMPIC_CLEAR_RET_CODE) { printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name) ; return -EIO ; } if(readb(init_srb+2)!=0) { if (readb(init_srb+2) == 0x07) { if (!olympic_priv->olympic_ring_speed && open_finished) { /* Autosense , first time around */ printk(KERN_WARNING "%s: Retrying at different ring speed \n", dev->name); open_finished = 0 ; } else { strcpy(open_error, open_maj_error[(readb(init_srb+7) & 0xf0) >> 4]) ; strcat(open_error," - ") ; strcat(open_error, open_min_error[(readb(init_srb+7) & 0x0f)]) ; if (!olympic_priv->olympic_ring_speed && ((readb(init_srb+7) & 0x0f) == 0x0d)) { printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n",dev->name); printk(KERN_WARNING "%s: Please try again with a specified ring speed \n",dev->name); free_irq(dev->irq, dev); return -EIO ; } printk(KERN_WARNING "%s: %s\n",dev->name,open_error); free_irq(dev->irq,dev) ; return -EIO ; } /* if autosense && open_finished */ } else { printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name,init_srb[2]); free_irq(dev->irq, dev); return -EIO; } } else open_finished = 1 ; } while (!(open_finished)) ; /* Will only loop if ring speed mismatch re-open attempted && autosense is on */ if (readb(init_srb+18) & (1<<3)) if (olympic_priv->olympic_message_level) printk(KERN_INFO "%s: Opened in FDX Mode\n",dev->name); if (readb(init_srb+18) & (1<<1)) olympic_priv->olympic_ring_speed = 100 ; else if (readb(init_srb+18) & 1) olympic_priv->olympic_ring_speed = 16 ; else olympic_priv->olympic_ring_speed = 4 ; if (olympic_priv->olympic_message_level) printk(KERN_INFO "%s: Opened in %d Mbps mode\n",dev->name, olympic_priv->olympic_ring_speed); olympic_priv->asb = swab16(readw(init_srb+8)); olympic_priv->srb = swab16(readw(init_srb+10)); olympic_priv->arb = swab16(readw(init_srb+12)); olympic_priv->trb = swab16(readw(init_srb+16)); olympic_priv->olympic_receive_options = 0x01 ; olympic_priv->olympic_copy_all_options = 0 ; /* setup rx ring */ writel((3<<16),olympic_mmio+BMCTL_RWM); /* Ensure end of frame generated interrupts */ writel(BMCTL_RX_DIS|3,olympic_mmio+BMCTL_RWM); /* Yes, this the enables RX channel */ for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) { struct sk_buff *skb; skb=dev_alloc_skb(olympic_priv->pkt_buf_sz); if(skb == NULL) break; skb->dev = dev; olympic_priv->olympic_rx_ring[i].buffer = cpu_to_le32(virt_to_bus(skb->data)); olympic_priv->olympic_rx_ring[i].res_length = cpu_to_le32(olympic_priv->pkt_buf_sz); olympic_priv->rx_ring_skb[i]=skb; } if (i==0) { printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n",dev->name); free_irq(dev->irq, dev); return -EIO; } writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]), olympic_mmio+RXDESCQ); writel(virt_to_bus(&olympic_priv->olympic_rx_ring[0]), olympic_mmio+RXCDA); writew(i, olympic_mmio+RXDESCQCNT); writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]), olympic_mmio+RXSTATQ); writel(virt_to_bus(&olympic_priv->olympic_rx_status_ring[0]), olympic_mmio+RXCSA); olympic_priv->rx_ring_last_received = OLYMPIC_RX_RING_SIZE - 1; /* last processed rx status */ olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE - 1; writew(i, olympic_mmio+RXSTATQCNT);#if OLYMPIC_DEBUG printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ)); printk("RXCSA: %x, rx_status_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]); printk(" stat_ring[1]: %p, stat_ring[2]: %p, stat_ring[3]: %p\n", &(olympic_priv->olympic_rx_status_ring[1]), &(olympic_priv->olympic_rx_status_ring[2]), &(olympic_priv->olympic_rx_status_ring[3]) ); printk(" stat_ring[4]: %p, stat_ring[5]: %p, stat_ring[6]: %p\n", &(olympic_priv->olympic_rx_status_ring[4]), &(olympic_priv->olympic_rx_status_ring[5]), &(olympic_priv->olympic_rx_status_ring[6]) ); printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7]) ); printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);#endif writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ);#if OLYMPIC_DEBUG printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ)); printk("RXCSA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCSA)),&olympic_priv->olympic_rx_status_ring[0]); printk("RXCDA: %x, rx_ring[0]: %p\n",bus_to_virt(readl(olympic_mmio+RXCDA)),&olympic_priv->olympic_rx_ring[0]);#endif writel(SISR_RX_STATUS | SISR_RX_NOBUF,olympic_mmio+SISR_MASK_SUM); /* setup tx ring */ writel(BMCTL_TX1_DIS,olympic_mmio+BMCTL_RWM); /* Yes, this enables TX channel 1 */ for(i=0;i<OLYMPIC_TX_RING_SIZE;i++) olympic_priv->olympic_tx_ring[i].buffer=0xdeadbeef; olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE; writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]), olympic_mmio+TXDESCQ_1); writel(virt_to_bus(&olympic_priv->olympic_tx_ring[0]), olympic_mmio+TXCDA_1); writew(OLYMPIC_TX_RING_SIZE, olympic_mmio+TXDESCQCNT_1); writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXSTATQ_1); writel(virt_to_bus(&olympic_priv->olympic_tx_status_ring[0]),olympic_mmio+TXCSA_1); writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXSTATQCNT_1); olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */ olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */ writel(SISR_TX1_EOF | SISR_ADAPTER_CHECK | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_ASB_FREE,olympic_mmio+SISR_MASK_SUM);#if OLYMPIC_DEBUG printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM)); printk("SISR MASK: %x\n",readl(olympic_mmio+SISR_MASK));#endif#if OLYMPIC_NETWORK_MONITOR oat = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; opt = (__u8 *)(olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1), readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2), readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3), readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4), readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5)); printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3)); printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)), readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1), readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2), readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3), readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4), readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5));#endif netif_start_queue(dev); MOD_INC_USE_COUNT ; return 0; } /* * When we enter the rx routine we do not know how many frames have been * queued on the rx channel. Therefore we start at the next rx status * position and travel around the receive ring until we have completed * all the frames. * * This means that we may process the frame before we receive the end * of frame interrupt. This is why we always test the status instead * of blindly processing the next frame. * */static void olympic_rx(struct net_device *dev){ struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; __u8 *olympic_mmio=olympic_priv->olympic_mmio; struct olympic_rx_status *rx_status; struct olympic_rx_desc *rx_desc ; int rx_ring_last_received,length, buffer_cnt, cpy_length, frag_len; struct sk_buff *skb, *skb2; int i; rx_status=&(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received + 1) & (OLYMPIC_RX_RING_SIZE - 1)]) ; while (rx_status->status_buffercnt) { __u32 l_status_buffercnt; olympic_priv->rx_status_last_received++ ; olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1);#if OLYMPIC_DEBUG printk(" stat_ring addr: %x \n", &(olympic_priv->olympic_rx_status_ring[olympic_priv->rx_status_last_received]) ); printk("rx status: %x rx len: %x \n", le32_to_cpu(rx_status->status_buffercnt), le32_to_cpu(rx_status->fragmentcnt_framelen));#endif length = le32_to_cpu(rx_status->fragmentcnt_framelen) & 0xffff; buffer_cnt = le32_to_cpu(rx_status->status_buffercnt) & 0xffff; i = buffer_cnt ; /* Need buffer_cnt later for rxenq update */ frag_len = le32_to_cpu(rx_status->fragmentcnt_framelen) >> 16; #if OLYMPIC_DEBUG printk("length: %x, frag_len: %x, buffer_cnt: %x\n", length, frag_len, buffer_cnt);#endif l_status_buffercnt = le32_to_cpu(rx_status->status_buffercnt); if(l_status_buffercnt & 0xC0000000) { if (l_status_buffercnt & 0x3B000000) { if (olympic_priv->olympic_message_level) { if (l_status_buffercnt & (1<<29)) /* Rx Frame Truncated */ printk(KERN_WARNING "%s: Rx Frame Truncated \n",dev->name); if (l_status_buffercnt & (1<<28)) /*Rx receive overrun */ printk(KERN_WARNING "%s: Rx Frame Receive overrun \n",dev->name); if (l_status_buffercnt & (1<<27)) /* No receive buffers */ printk(KERN_WARNING "%s: No receive buffers \n",dev->name); if (l_status_buffercnt & (1<<25)) /* Receive frame error detect */ printk(KERN_WARNING "%s: Receive frame error detect \n",dev->name); if (l_status_buffercnt & (1<<24)) /* Received Error Detect */ printk(KERN_WARNING "%s: Received Error Detect \n",dev->name); } olympic_priv->rx_ring_last_received += i ; olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; olympic_priv->olympic_stats.rx_errors++; } else { if (buffer_cnt == 1) { skb = dev_alloc_skb(olympic_priv->pkt_buf_sz) ; } else { skb = dev_alloc_skb(length) ; } if (skb == NULL) { printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers. \n",dev->name) ; olympic_priv->olympic_stats.rx_dropped++ ; /* Update counters even though we don't transfer the frame */ olympic_priv->rx_ring_last_received += i ; olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; } else { skb->dev = dev ; /* Optimise based upon number of buffers used. If only one buffer is used we can simply swap the buffers around. If more than one then we must use the new buffer and copy the information first. Ideally all frames would be in a single buffer, this can be tuned by altering the buffer size. */ if (buffer_cnt==1) { olympic_priv->rx_ring_last_received++ ; olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1); rx_ring_last_received = olympic_priv->rx_ring_last_received ; skb2=olympic_priv->rx_ring_skb[rx_ring_last_received] ; skb_put(skb2,length); skb2->protocol = tr_type_trans(skb2,dev); olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer = cpu_to_le32(virt_to_bus(skb->data)); olympic_priv->olympic_rx_ring[rx_ring_last_received].res_length = cpu_to_le32(olympic_priv->pkt_buf_sz); olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; netif_rx(skb2) ; } else { do { /* Walk the buffers */ olympic_priv->rx_ring_last_received++ ; olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1); rx_ring_last_received = olympic_priv->rx_ring_last_received ; rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]); cpy_length = (i == 1 ? frag_len : le32_to_cpu(rx_desc->res_length)); memcpy(skb_put(skb, cpy_length), bus_to_virt(le32_to_cpu(rx_desc->buffer)), cpy_length) ; } while (--i) ; skb->protocol = tr_type_trans(skb,dev); netif_rx(skb) ; } olympic_priv->olympic_stats.rx_packets++ ; olympic_priv->olympic_stats.rx_bytes += length ; } /* if skb == null */ } /* If status & 0x3b */ } else { /*if buffercnt & 0xC */ olympic_priv->rx_ring_last_received += i ; olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE - 1) ; } rx_status->fragmentcnt_framelen = 0 ; rx_status->status_buffercnt = 0 ; rx_status = &(olympic_priv->olympic_rx_status_ring[(olympic_priv->rx_status_last_received+1) & (OLYMPIC_RX_RING_SIZE -1) ]); writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | buffer_cnt , olympic_mmio+RXENQ); } /* while */}static void olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev= (struct net_device *)dev_id; struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; __u8 *olympic_mmio=olympic_priv->olympic_mmio; __u32 sisr; __u8 *adapter_check_area ; sisr=readl(olympic_mmio+SISR_RR) ; /* Reset sisr */ if (!(sisr & SISR_MI)) /* Interrupt isn't for us */ return ; spin_lock(&olympic_priv->olympic_lock); if (sisr & (SISR_SRB_REPLY | SISR_TX1_EOF | SISR_RX_STATUS | SISR_ADAPTER_CHECK | SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY | SISR_RX_NOBUF)) { if(sisr & SISR_SRB_REPLY) { if(olympic_priv->srb_queued==1) { wake_up_interruptible(&olympic_priv->srb_wait); } else if (olympic_priv->srb_queued==2) { olympic_srb_bh(dev) ; } olympic_priv->srb_queued=0; } /* SISR_SRB_REPLY */ if (sisr & SISR_TX1_EOF) { olympic_priv->tx_ring_last_status++; olympic_priv->tx_ring_last_status &= (OLYMPIC_TX_RING_SIZE-1); olympic_priv->free_tx_ring_entries++; olympic_priv->olympic_stats.tx_bytes += olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len; olympic_priv->olympic_stats.tx_packets++ ; dev_kfree_skb_irq(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]); olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef; olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0; netif_wake_queue(dev); } /* SISR_TX1_EOF */ if (sisr & SISR_RX_STATUS) { olympic_rx(dev); } /* SISR_RX_STATUS */ if (sisr & SISR_ADAPTER_CHECK) { printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name); writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA); adapter_check_area = (__u8 *)(olympic_mmio+LAPWWO) ; printk(KERN_WARNING "%s: Bytes %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, readb(adapter_check_area+0), readb(adapter_check_area+1), readb(adapter_check_area+2), readb(adapter_check_area+3), readb(adapter_check_area+4), readb(adapter_check_area+5), readb(adapter_check_area+6), readb(adapter_check_area+7)) ; free_irq(dev->irq, dev) ; } /* SISR_ADAPTER_CHECK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -