📄 ethernet.c
字号:
myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next); } } spin_unlock_irq(&np->lock); return 0;}/* * The typical workload of the driver: * Handle the network interface interrupts. */static voide100rx_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; if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { /* acknowledge the eop interrupt */ *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do); /* check if one or more complete packets were indeed received */ while (*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) { /* Take out the buffer and give it to the OS, then * allocate a new buffer to put a packet in. */ e100_rx(dev); ((struct net_local *)dev->priv)->stats.rx_packets++; /* restart/continue on the channel, for safety */ *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart); /* clear dma channel 1 eop/descr irq bits */ *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)) { /* Report all sent packets */ do { /* acknowledge the eop interrupt */ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); np->stats.tx_bytes += myFirstTxDesc->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(myFirstTxDesc->skb); myFirstTxDesc->skb = 0; if (netif_queue_stopped(dev)) { /* Queue is running, disable tx IRQ */ *R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr); netif_wake_queue(dev); } myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next); } while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) && myFirstTxDesc != myNextTxDesc); }}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; unsigned char *skb_data_ptr;#ifdef ETHDEBUG int i;#endif if (!led_active && time_after(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); } length = myNextRxDesc->descr.hw_len - 4; ((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(myNextRxDesc->descr.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 if (length < RX_COPYBREAK) { /* Small packet, copy data */ 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 memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length); } else { /* Large packet, send directly to upper layers and allocate new memory */ skb = myNextRxDesc->skb; skb_put(skb, length); myNextRxDesc->skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE); myNextRxDesc->descr.buf = virt_to_phys(myNextRxDesc->skb->data); } 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->descr.status = 0; myPrevRxDesc = myNextRxDesc; myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next); rx_queue_len++; /* Check if descriptors should be returned */ if (rx_queue_len == RX_QUEUE_THRESHOLD) { flush_etrax_cache(); myPrevRxDesc->descr.ctrl |= d_eol; myLastRxDesc->descr.ctrl &= ~d_eol; myLastRxDesc = myPrevRxDesc; rx_queue_len = 0; }}/* 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 && time_after(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 */ myNextTxDesc->descr.sw_len = length; myNextTxDesc->descr.ctrl = d_eop | d_eol | d_wait; myNextTxDesc->descr.buf = virt_to_phys(buf); /* Move end of list */ myLastTxDesc->descr.ctrl &= ~d_eol; myLastTxDesc = myNextTxDesc; /* Restart DMA channel */ *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, restart);}static voide100_clear_network_leds(unsigned long dummy){ if (led_active && time_after(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 + -