📄 1005.tango2enet.patch
字号:
+ }+ }+ }++ return IRQ_HANDLED;+}++/*+ * start/stop dma engine+ */+static __inline void enet_start_dma(struct tango2_enet_priv *priv)+{+ /* send start command to rx & tx dma */+ enet_writel(ENET_DMA_CR, CR_SF | CR_SR | CR_ST);+}++static __inline void enet_stop_dma(struct tango2_enet_priv *priv)+{+ unsigned long val;++ /* send stop command to rx & tx dma */+ enet_writel(ENET_DMA_CR, 0);++ /* wait for them to reach stopped state, should not be long */+ do {+ udelay(1);+ val = enet_readl(ENET_DMA_SR);+ if ((val & SR_TPS) && (val & SR_RPS))+ break;+ } while (1);+}++/*+ * reconfigure mac for new link state+ */+static void enet_link_reconfigure(struct net_device *dev)+{+ struct tango2_enet_priv *priv;+ unsigned long val;++ priv = netdev_priv(dev);++ if (dev->flags & IFF_UP)+ enet_stop_dma(priv);++ /* reflect duplex status in dma register */+ spin_lock(&priv->maccr_lock);+ val = enet_readl(ENET_MAC_MACCR);+ if (priv->mii.full_duplex)+ val |= MACCR_F;+ else+ val &= ~MACCR_F;+ enet_writel(ENET_MAC_MACCR, val);+ spin_unlock(&priv->maccr_lock);++ if (dev->flags & IFF_UP)+ enet_start_dma(priv);+}++/*+ * link check timer callback+ */+static void enet_link_check(unsigned long data)+{+ struct net_device *dev;+ struct tango2_enet_priv *priv;+ int ret;++ dev = (struct net_device *)data;+ priv = netdev_priv(dev);++ /* check for duplex change */+ spin_lock(&priv->mii_lock);+ ret = mii_check_media(&priv->mii, 1, 0);+ spin_unlock(&priv->mii_lock);++ if (ret)+ enet_link_reconfigure(dev);++ /* reschedule timer */+ priv->link_check_timer.expires = jiffies + LINK_CHECK_TIMER_FREQ;+ add_timer(&priv->link_check_timer);+}++/*+ * program given mac address in hw registers+ */+static int enet_set_mac_address(struct net_device *dev, void *addr)+{+ unsigned long hi_mac, low_mac;++ /* to make it safe, we won't do this while running */+ if (netif_running(dev))+ return -EBUSY;++ memcpy(dev->dev_addr, addr, ETH_ALEN);++ hi_mac = (dev->dev_addr[5] << 8) | dev->dev_addr[4];+ low_mac = (dev->dev_addr[3] << 24)| (dev->dev_addr[2] << 16) |+ (dev->dev_addr[1] << 8) | dev->dev_addr[0];++ enet_writel(ENET_MAC_MACAHR, hi_mac);+ enet_writel(ENET_MAC_MACALR, low_mac);++ return 0;+}++/*+ * update hash table to reflect new device multicast address list+ */+static void enet_set_multicast_list(struct net_device *dev)+{+ struct tango2_enet_priv *priv;+ struct dev_mc_list *mclist;+ unsigned long val;+ uint32_t mc_filter[2];+ int i;++ priv = netdev_priv(dev);++ /* the link check timer might change MACCR, we need to protect+ * against it */+ spin_lock_bh(&priv->maccr_lock);+ val = enet_readl(ENET_MAC_MACCR);++ if (dev->flags & IFF_PROMISC) {+ val |= MACCR_PR | MACCR_PM;+ } else {+ val &= ~MACCR_PR;+ /* if we want all multicast or if address count is too+ * high, don't try to compute hash value */+ if (dev->mc_count > 64 || dev->flags & IFF_ALLMULTI) {+ val |= MACCR_PM;+ }+ }+ enet_writel(ENET_MAC_MACCR, val);+ spin_unlock_bh(&priv->maccr_lock);++ /* we don't need to update hash table if we pass all+ * multicast */+ if (val & MACCR_PM)+ return;++ mc_filter[0] = mc_filter[1] = 0;+ mclist = dev->mc_list;++ for (i = 0; i < dev->mc_count; i++) {+ unsigned int n;+ char *addr;++ addr = mclist->dmi_addr;+ mclist = mclist->next;+ if (!(*addr & 1))+ continue;++ n = ether_crc(ETH_ALEN, addr) >> 26;+ mc_filter[n >> 5] |= 1 << (n & 31);+ }++ enet_writel(ENET_MAC_MALR, mc_filter[0]);+ enet_writel(ENET_MAC_MAHR, mc_filter[1]);+}++/*+ * open callback+ */+static int enet_open(struct net_device *dev)+{+ struct tango2_enet_priv *priv;+ unsigned long val;++ priv = netdev_priv(dev);++ /* check link */+ if (mii_check_media(&priv->mii, 1, 1))+ enet_link_reconfigure(dev);++ /* start rx & tx dma engine */+ enet_start_dma(priv);++ /* enable mac rx & tx */+ val = enet_readl(ENET_MAC_MACCR);+ val |= MACCR_TE | MACCR_RE;+ enet_writel(ENET_MAC_MACCR, val);++ /*+ * clear & enable interrupts, we want:+ * - receive complete+ * - transmit complete+ */+ enet_writel(ENET_DMA_SR, SR_NIS | SR_R | SR_T);+ enet_enable_interrupts(priv, 0);++ /* start link check & tx reclaim timer */+ priv->link_check_timer.expires = jiffies + LINK_CHECK_TIMER_FREQ;+ add_timer(&priv->link_check_timer);++ priv->tx_reclaim_timer.expires = jiffies + TX_RECLAIM_TIMER_FREQ;+ add_timer(&priv->tx_reclaim_timer);++ /* and finally start tx queue */+ netif_start_queue(dev);++ return 0;+}++/*+ * stop callback+ */+static int enet_stop(struct net_device *dev)+{+ struct tango2_enet_priv *priv;+ unsigned long val;+ int i;++ priv = netdev_priv(dev);++ /* stop link timer */+ del_timer_sync(&priv->link_check_timer);++ /* stop tx queue */+ netif_stop_queue(dev);++ /* wait for all tx buffers to be reclaimed */+ while (priv->free_tx_desc_count != ENET_TX_DESC_COUNT)+ yield();++ /* stop tx reclaim timer */+ del_timer_sync(&priv->tx_reclaim_timer);++ /* disable all interrupts */+ enet_disable_interrupts(priv, 0);++ /* stop dma */+ enet_stop_dma(priv);++ /* stop mac rx & tx */+ val = enet_readl(ENET_MAC_MACCR);+ val &= ~(MACCR_TE | MACCR_RE);+ enet_writel(ENET_MAC_MACCR, val);++ /* while we were stopping it, the rx dma may have filled some+ * buffer, consider it junk and rearm all descriptor */+ for (i = 0; i < ENET_RX_DESC_COUNT; i++) {+ volatile struct enet_rx_desc *rx;++ rx = &priv->rx_descs[i];+ rx->rdes0 = RDES0_OWN;+ }++ /* make the dma engine restarts at first descriptor in the+ * list */+ enet_writel(ENET_DMA_RBAR, PHYSADDR(priv->rx_descs));+ enet_writel(ENET_DMA_TBAR, PHYSADDR(priv->tx_descs));+ priv->dirty_tx_desc = priv->next_tx_desc = 0;+ priv->last_rx_desc = 0;++ return 0;+}++/*+ * get_stats callback+ */+static struct net_device_stats *enet_get_stats(struct net_device *dev)+{+ struct tango2_enet_priv *priv;++ priv = netdev_priv(dev);++ return &priv->stats;+}++/*+ * ethtool callbacks+ */+static int enet_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)+{+ struct tango2_enet_priv *priv;+ int ret;++ priv = netdev_priv(dev);++ spin_lock_bh(&priv->mii_lock);+ ret = mii_ethtool_gset(&priv->mii, cmd);+ spin_unlock_bh(&priv->mii_lock);++ return ret;+}++static int enet_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)+{+ struct tango2_enet_priv *priv;+ int ret;++ priv = netdev_priv(dev);++ spin_lock_bh(&priv->mii_lock);+ ret = mii_ethtool_sset(&priv->mii, cmd);+ spin_unlock_bh(&priv->mii_lock);++ return ret;+}++static int enet_nway_reset(struct net_device *dev)+{+ struct tango2_enet_priv *priv;+ int ret;++ priv = netdev_priv(dev);++ spin_lock_bh(&priv->mii_lock);+ ret = mii_nway_restart(&priv->mii);+ spin_unlock_bh(&priv->mii_lock);++ return ret;+}++static u32 enet_get_link(struct net_device *dev)+{+ struct tango2_enet_priv *priv;+ int ret;++ priv = netdev_priv(dev);++ spin_lock_bh(&priv->mii_lock);+ ret = mii_link_ok(&priv->mii);+ spin_unlock_bh(&priv->mii_lock);++ return ret;+}++static struct ethtool_ops enet_ethtool_ops = {+ .get_settings = enet_get_settings,+ .set_settings = enet_set_settings,+ .nway_reset = enet_nway_reset,+ .get_link = enet_get_link,+};++static int enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)+{+ struct tango2_enet_priv *priv;+ int ret;++ priv = netdev_priv(dev);++ spin_lock_bh(&priv->mii);+ ret = generic_mii_ioctl(&priv->mii, if_mii(rq), cmd, NULL);+ spin_unlock_bh(&priv->mii);++ return ret;+}++/*+ * dma ring allocation is done here+ */+static int enet_dma_init(struct tango2_enet_priv *priv)+{+ unsigned int size;+ int i;++ /*+ * allocate rx descriptor list & rx buffers+ *+ * We allocate skb now and fill buffer with their addresses,+ * note that we reserve 4 bytes at beginning of data buffer to+ * store skb address.+ *+ */+ size = ENET_RX_DESC_COUNT * sizeof (struct enet_rx_desc);+ if (!(priv->rx_descs_cached = kmalloc(size, GFP_KERNEL)))+ return -ENOMEM;+ priv->rx_descs = (volatile struct enet_rx_desc *)+ CACHE_TO_NONCACHE((unsigned long)priv->rx_descs_cached);+ dma_cache_wback_inv((unsigned long)priv->rx_descs_cached, size);++ /*+ * initialize all rx descs+ */+ for (i = 0; i < ENET_RX_DESC_COUNT; i++) {+ volatile struct enet_rx_desc *rx;+ struct sk_buff *skb;++ rx = &priv->rx_descs[i];+ rx->rdes0 = RDES0_OWN;++ rx->rdes1 = RDES1_RBS2(0) | RDES1_RBS1(RX_BUF_SIZE);+ if (i == ENET_RX_DESC_COUNT - 1)+ rx->rdes1 |= RDES1_RER;++ skb = dev_alloc_skb(RX_BUF_SIZE + SKB_RESERVE_SIZE);+ if (!skb)+ return -ENOMEM;++ skb_reserve(skb, SKB_RESERVE_SIZE);+ rx->rdes2 = PHYSADDR(skb->data);+ rx->rdes3 = 0;++ dma_cache_inv((unsigned long)skb->data, RX_BUF_SIZE);+ priv->rx_skbs[i] = skb;+ }+ priv->last_rx_desc = 0;++ /*+ * allocate tx descriptor list+ *+ * We allocate only the descriptor list and prepare them for+ * further use. When tx is needed, we will set the right flags+ * and kick the dma.+ */+ size = ENET_TX_DESC_COUNT * sizeof (struct enet_tx_desc);+ if (!(priv->tx_descs_cached = kmalloc(size, GFP_KERNEL)))+ return -ENOMEM;+ priv->tx_descs = (volatile struct enet_tx_desc *)+ CACHE_TO_NONCACHE((unsigned long)priv->tx_descs_cached);+ dma_cache_wback_inv((unsigned long)priv->tx_descs_cached, size);++ /*+ * initialize tx descs+ */+ for (i = 0; i < ENET_TX_DESC_COUNT; i++) {+ volatile struct enet_tx_desc *tx;++ tx = &priv->tx_descs[i];+ tx->tdes0 = 0;+ tx->tdes1 = 0;+ if (i == ENET_TX_DESC_COUNT - 1)+ tx->tdes1 |= TDES1_TER;+ tx->tdes2 = 0;+ tx->tdes3 = 0;+ }+ priv->dirty_tx_desc = priv->next_tx_desc = 0;+ priv->free_tx_desc_count = ENET_TX_DESC_COUNT;++ /*+ * write rx desc list & tx desc list addresses in registers+ */+ enet_writel(ENET_DMA_RBAR, PHYSADDR(priv->rx_descs));+ enet_writel(ENET_DMA_TBAR, PHYSADDR(priv->tx_descs));++ return 0;+}++/*+ * free all dma rings memory, called at uninit time or when error+ * occurs at init time+ */+static void enet_dma_free(struct tango2_enet_priv *priv)+{+ int i;++ /* note: kfree(NULL) is ok */+ kfree(priv->rx_descs_cached);+ kfree(priv->tx_descs_cached);++ /* note: kfree_skb(NULL) is _not_ ok */+ for (i = 0; i < ENET_RX_DESC_COUNT; i++) {+ if (priv->rx_skbs[i])+ kfree_skb(priv->rx_skbs[i]);+ }+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -