📄 eth_v10.c
字号:
myNextRxDesc->descr.buf = L1_CACHE_ALIGN(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(KERN_INFO "Closing %s.\n", dev->name); netif_stop_queue(dev); *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); /* Update the statistics here. */ update_rx_stats(&np->stats); update_tx_stats(&np->stats); /* Stop speed/duplex timers */ del_timer(&speed_timer); del_timer(&duplex_timer); return 0;}static inte100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ struct mii_ioctl_data *data = if_mii(ifr); struct net_local *np = netdev_priv(dev); spin_lock(&np->lock); /* Preempt protection */ switch (cmd) { case SIOCGMIIPHY: /* Get PHY address */ data->phy_id = mdio_phy_addr; break; case SIOCGMIIREG: /* Read MII register */ data->val_out = e100_get_mdio_reg(dev, mdio_phy_addr, data->reg_num); break; case SIOCSMIIREG: /* Write MII register */ e100_set_mdio_reg(dev, mdio_phy_addr, data->reg_num, data->val_in); break; /* The ioctls below should be considered obsolete but are */ /* still present for compatability with old scripts/apps */ case SET_ETH_SPEED_10: /* 10 Mbps */ e100_set_speed(dev, 10); break; case SET_ETH_SPEED_100: /* 100 Mbps */ e100_set_speed(dev, 100); break; case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */ e100_set_speed(dev, 0); break; case SET_ETH_DUPLEX_HALF: /* Half duplex. */ e100_set_duplex(dev, half); break; case SET_ETH_DUPLEX_FULL: /* Full duplex. */ e100_set_duplex(dev, full); break; case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex*/ e100_set_duplex(dev, autoneg); break; default: return -EINVAL; } spin_unlock(&np->lock); return 0;}static int e100_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd){ ecmd->supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; ecmd->port = PORT_TP; ecmd->transceiver = XCVR_EXTERNAL; ecmd->phy_address = mdio_phy_addr; ecmd->speed = current_speed; ecmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; ecmd->advertising = ADVERTISED_TP; if (current_duplex == autoneg && current_speed_selection == 0) ecmd->advertising |= ADVERTISED_Autoneg; else { ecmd->advertising |= ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; if (current_speed_selection == 10) ecmd->advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full); else if (current_speed_selection == 100) ecmd->advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full); if (current_duplex == half) ecmd->advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full); else if (current_duplex == full) ecmd->advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half); } ecmd->autoneg = AUTONEG_ENABLE; return 0;}static int e100_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd){ if (ecmd->autoneg == AUTONEG_ENABLE) { e100_set_duplex(dev, autoneg); e100_set_speed(dev, 0); } else { e100_set_duplex(dev, ecmd->duplex == DUPLEX_HALF ? half : full); e100_set_speed(dev, ecmd->speed == SPEED_10 ? 10: 100); } return 0;}static void e100_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ strncpy(info->driver, "ETRAX 100LX", sizeof(info->driver) - 1); strncpy(info->version, "$Revision: 1.31 $", sizeof(info->version) - 1); strncpy(info->fw_version, "N/A", sizeof(info->fw_version) - 1); strncpy(info->bus_info, "N/A", sizeof(info->bus_info) - 1);}static int e100_nway_reset(struct net_device *dev){ if (current_duplex == autoneg && current_speed_selection == 0) e100_negotiate(dev); return 0;}static struct ethtool_ops e100_ethtool_ops = { .get_settings = e100_get_settings, .set_settings = e100_set_settings, .get_drvinfo = e100_get_drvinfo, .nway_reset = e100_nway_reset, .get_link = ethtool_op_get_link,};static inte100_set_config(struct net_device *dev, struct ifmap *map){ struct net_local *np = (struct net_local *)dev->priv; spin_lock(&np->lock); /* Preempt protection */ switch(map->port) { case IF_PORT_UNKNOWN: /* Use autoneg */ e100_set_speed(dev, 0); e100_set_duplex(dev, autoneg); break; case IF_PORT_10BASET: e100_set_speed(dev, 10); e100_set_duplex(dev, autoneg); break; case IF_PORT_100BASET: case IF_PORT_100BASETX: e100_set_speed(dev, 100); e100_set_duplex(dev, autoneg); break; case IF_PORT_100BASEFX: case IF_PORT_10BASE2: case IF_PORT_AUI: spin_unlock(&np->lock); return -EOPNOTSUPP; break; default: printk(KERN_ERR "%s: Invalid media selected", dev->name); spin_unlock(&np->lock); return -EINVAL; } spin_unlock(&np->lock); 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; unsigned long flags; spin_lock_irqsave(&lp->lock, flags); update_rx_stats(&lp->stats); update_tx_stats(&lp->stats); spin_unlock_irqrestore(&lp->lock, flags); 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){ struct net_local *lp = (struct net_local *)dev->priv; int num_addr = dev->mc_count; unsigned long int lo_bits; unsigned long int hi_bits; spin_lock(&lp->lock); 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; spin_unlock(&lp->lock);}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 */#if defined(CONFIG_ETRAX_NETWORK_RED_ON_NO_CONNECTION) LED_NETWORK_SET(LED_RED);#else LED_NETWORK_SET(LED_OFF);#endif } 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 intetrax_init_module(void){ return etrax_ethernet_init();}static int __inite100_boot_setup(char* str){ struct sockaddr sa = {0}; int i; /* Parse the colon separated Ethernet station address */ for (i = 0; i < ETH_ALEN; i++) { unsigned int tmp; if (sscanf(str + 3*i, "%2x", &tmp) != 1) { printk(KERN_WARNING "Malformed station address"); return 0; } sa.sa_data[i] = (char)tmp; } default_mac = sa; return 1;}__setup("etrax100_eth=", e100_boot_setup);module_init(etrax_init_module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -