📄 ethernet.c
字号:
*R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) | IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do); /* now, we might have gotten another packet so we have to loop back and check if so */ } }}/* the transmit dma channel interrupt * * this is supposed to free the skbuff which was pending during transmission, * and inform the kernel that we can send one more buffer */static voide100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs){ struct net_device *dev = (struct net_device *)dev_id; unsigned long irqbits = *R_IRQ_MASK2_RD; struct net_local *np = (struct net_local *)dev->priv; /* check for a dma0_eop interrupt */ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { /* This protects us from concurrent execution of * our dev->hard_start_xmit function above. */ spin_lock(&np->lock); /* acknowledge the eop interrupt */ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); if (*R_DMA_CH0_FIRST == 0 && tx_skb) { np->stats.tx_bytes += tx_skb->len; np->stats.tx_packets++; /* dma is ready with the transmission of the data in tx_skb, so now we can release the skb memory */ dev_kfree_skb_irq(tx_skb); tx_skb = 0; netif_wake_queue(dev); } else { printk(KERN_WARNING "%s: tx weird interrupt\n", cardname); } spin_unlock(&np->lock); }}static voide100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs){ struct net_device *dev = (struct net_device *)dev_id; struct net_local *np = (struct net_local *)dev->priv; unsigned long irqbits = *R_IRQ_MASK0_RD; /* check for underrun irq */ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); np->stats.tx_errors++; D(printk("ethernet receiver underrun!\n")); } /* check for overrun irq */ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { update_rx_stats(&np->stats); /* this will ack the irq */ D(printk("ethernet receiver overrun!\n")); } /* check for excessive collision irq */ if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); np->stats.tx_errors++; D(printk("ethernet excessive collisions!\n")); }}/* We have a good packet(s), get it/them out of the buffers. */static voide100_rx(struct net_device *dev){ struct sk_buff *skb; int length = 0; struct net_local *np = (struct net_local *)dev->priv; struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc; unsigned char *skb_data_ptr;#ifdef ETHDEBUG int i;#endif if (!led_active && jiffies > led_next_time) { /* light the network leds depending on the current speed. */ e100_set_network_leds(NETWORK_ACTIVITY); /* Set the earliest time we may clear the LED */ led_next_time = jiffies + NET_FLASH_TIME; led_active = 1; mod_timer(&clear_led_timer, jiffies + HZ/10); } /* If the packet is broken down in many small packages then merge * count how much space we will need to alloc with skb_alloc() for * it to fit. */ while (!(myNextRxDesc->status & d_eop)) { length += myNextRxDesc->sw_len; /* use sw_len for the first descs */ myNextRxDesc->status = 0; myNextRxDesc = phys_to_virt(myNextRxDesc->next); } length += myNextRxDesc->hw_len; /* use hw_len for the last descr */ ((struct net_local *)dev->priv)->stats.rx_bytes += length;#ifdef ETHDEBUG printk("Got a packet of length %d:\n", length); /* dump the first bytes in the packet */ skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf); for (i = 0; i < 8; i++) { printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3], skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]); skb_data_ptr += 8; }#endif skb = dev_alloc_skb(length - ETHER_HEAD_LEN); if (!skb) { np->stats.rx_errors++; printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); return; } skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */#ifdef ETHDEBUG printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", skb->head, skb->data, skb->tail, skb->end); printk("copying packet to 0x%x.\n", skb_data_ptr);#endif /* this loop can be made using max two memcpy's if optimized */ while (mySaveRxDesc != myNextRxDesc) { memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), mySaveRxDesc->sw_len); skb_data_ptr += mySaveRxDesc->sw_len; mySaveRxDesc = phys_to_virt(mySaveRxDesc->next); } memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), mySaveRxDesc->hw_len); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); /* Send the packet to the upper layers */ netif_rx(skb); /* Prepare for next packet */ myNextRxDesc->status = 0; myPrevRxDesc = myNextRxDesc; myNextRxDesc = phys_to_virt(myNextRxDesc->next); myPrevRxDesc->ctrl |= d_eol; myLastRxDesc->ctrl &= ~d_eol; myLastRxDesc = myPrevRxDesc; return;}/* The inverse routine to net_open(). */static inte100_close(struct net_device *dev){ struct net_local *np = (struct net_local *)dev->priv; printk("Closing %s.\n", dev->name); netif_stop_queue(dev); *R_NETWORK_GEN_CONFIG = IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | IO_STATE(R_NETWORK_GEN_CONFIG, enable, off); *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr); *R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) | IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) | IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) | IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr); /* Stop the receiver and the transmitter */ RESET_DMA(NETWORK_TX_DMA_NBR); RESET_DMA(NETWORK_RX_DMA_NBR); /* Flush the Tx and disable Rx here. */ free_irq(NETWORK_DMA_RX_IRQ_NBR, (void *)dev); free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); free_dma(NETWORK_TX_DMA_NBR); free_dma(NETWORK_RX_DMA_NBR); /* Update the statistics here. */ update_rx_stats(&np->stats); update_tx_stats(&np->stats); return 0;}static inte100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ /* Maybe default should return -EINVAL instead? */ switch (cmd) { case SET_ETH_SPEED_10: /* 10 Mbps */ e100_set_speed(10); break; case SET_ETH_SPEED_100: /* 100 Mbps */ e100_set_speed(100); break; case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */ e100_set_speed(0); break; case SET_ETH_DUPLEX_HALF: /* Hhalf duplex. */ e100_set_duplex(half); break; case SET_ETH_DUPLEX_FULL: /* Full duplex. */ e100_set_duplex(full); break; case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex*/ e100_set_duplex(autoneg); break; default: /* Auto neg */ e100_set_speed(0); e100_set_duplex(autoneg); break; } return 0;}static voidupdate_rx_stats(struct net_device_stats *es){ unsigned long r = *R_REC_COUNTERS; /* update stats relevant to reception errors */ es->rx_fifo_errors += IO_EXTRACT(R_REC_COUNTERS, congestion, r); es->rx_crc_errors += IO_EXTRACT(R_REC_COUNTERS, crc_error, r); es->rx_frame_errors += IO_EXTRACT(R_REC_COUNTERS, alignment_error, r); es->rx_length_errors += IO_EXTRACT(R_REC_COUNTERS, oversize, r);}static voidupdate_tx_stats(struct net_device_stats *es){ unsigned long r = *R_TR_COUNTERS; /* update stats relevant to transmission errors */ es->collisions += IO_EXTRACT(R_TR_COUNTERS, single_col, r) + IO_EXTRACT(R_TR_COUNTERS, multiple_col, r); es->tx_errors += IO_EXTRACT(R_TR_COUNTERS, deferred, r);}/* * Get the current statistics. * This may be called with the card open or closed. */static struct net_device_stats *e100_get_stats(struct net_device *dev){ struct net_local *lp = (struct net_local *)dev->priv; update_rx_stats(&lp->stats); update_tx_stats(&lp->stats); return &lp->stats;}/* * Set or clear the multicast filter for this adaptor. * num_addrs == -1 Promiscuous mode, receive all packets * num_addrs == 0 Normal mode, clear multicast list * num_addrs > 0 Multicast mode, receive normal and MC packets, * and do best-effort filtering. */static voidset_multicast_list(struct net_device *dev){ int num_addr = dev->mc_count; unsigned long int lo_bits; unsigned long int hi_bits; if (dev->flags & IFF_PROMISC) { /* promiscuous mode */ lo_bits = 0xfffffffful; hi_bits = 0xfffffffful; /* Enable individual receive */ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, receive); *R_NETWORK_REC_CONFIG = network_rec_config_shadow; } else if (dev->flags & IFF_ALLMULTI) { /* enable all multicasts */ lo_bits = 0xfffffffful; hi_bits = 0xfffffffful; /* Disable individual receive */ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); *R_NETWORK_REC_CONFIG = network_rec_config_shadow; } else if (num_addr == 0) { /* Normal, clear the mc list */ lo_bits = 0x00000000ul; hi_bits = 0x00000000ul; /* Disable individual receive */ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); *R_NETWORK_REC_CONFIG = network_rec_config_shadow; } else { /* MC mode, receive normal and MC packets */ char hash_ix; struct dev_mc_list *dmi = dev->mc_list; int i; char *baddr; lo_bits = 0x00000000ul; hi_bits = 0x00000000ul; for (i=0; i<num_addr; i++) { /* Calculate the hash index for the GA registers */ hash_ix = 0; baddr = dmi->dmi_addr; hash_ix ^= (*baddr) & 0x3f; hash_ix ^= ((*baddr) >> 6) & 0x03; ++baddr; hash_ix ^= ((*baddr) << 2) & 0x03c; hash_ix ^= ((*baddr) >> 4) & 0xf; ++baddr; hash_ix ^= ((*baddr) << 4) & 0x30; hash_ix ^= ((*baddr) >> 2) & 0x3f; ++baddr; hash_ix ^= (*baddr) & 0x3f; hash_ix ^= ((*baddr) >> 6) & 0x03; ++baddr; hash_ix ^= ((*baddr) << 2) & 0x03c; hash_ix ^= ((*baddr) >> 4) & 0xf; ++baddr; hash_ix ^= ((*baddr) << 4) & 0x30; hash_ix ^= ((*baddr) >> 2) & 0x3f; hash_ix &= 0x3f; if (hash_ix > 32) { hi_bits |= (1 << (hash_ix-32)); } else { lo_bits |= (1 << hash_ix); } dmi = dmi->next; } /* Disable individual receive */ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, individual, discard); *R_NETWORK_REC_CONFIG = network_rec_config_shadow; } *R_NETWORK_GA_0 = lo_bits; *R_NETWORK_GA_1 = hi_bits;}voide100_hardware_send_packet(char *buf, int length){ D(printk("e100 send pack, buf 0x%x len %d\n", buf, length)); if (!led_active && jiffies > led_next_time) { /* light the network leds depending on the current speed. */ e100_set_network_leds(NETWORK_ACTIVITY); /* Set the earliest time we may clear the LED */ led_next_time = jiffies + NET_FLASH_TIME; led_active = 1; mod_timer(&clear_led_timer, jiffies + HZ/10); } /* configure the tx dma descriptor */ TxDesc.sw_len = length; TxDesc.ctrl = d_eop | d_eol | d_wait; TxDesc.buf = virt_to_phys(buf); /* setup the dma channel and start it */ *R_DMA_CH0_FIRST = virt_to_phys(&TxDesc); *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, start);}static voide100_clear_network_leds(unsigned long dummy){ if (led_active && jiffies > led_next_time) { e100_set_network_leds(NO_NETWORK_ACTIVITY); /* Set the earliest time we may set the LED */ led_next_time = jiffies + NET_FLASH_PAUSE; led_active = 0; }}static voide100_set_network_leds(int active){#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK) int light_leds = (active == NO_NETWORK_ACTIVITY);#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY) int light_leds = (active == NETWORK_ACTIVITY);#else#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY"#endif if (!current_speed) { /* Make LED red, link is down */ LED_NETWORK_SET(LED_RED); } else if (light_leds) { if (current_speed == 10) { LED_NETWORK_SET(LED_ORANGE); } else { LED_NETWORK_SET(LED_GREEN); } } else { LED_NETWORK_SET(LED_OFF); }}static struct net_device dev_etrax_ethernet; /* only got one */static intetrax_init_module(void){ struct net_device *d = &dev_etrax_ethernet; d->init = etrax_ethernet_init; if (register_netdev(d) == 0) return 0; else return -ENODEV;}module_init(etrax_init_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -