162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2004-2013 Synopsys, Inc. (www.synopsys.com) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Driver for the ARC EMAC 10100 (hardware revision 5) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Contributors: 862306a36Sopenharmony_ci * Amit Bhor 962306a36Sopenharmony_ci * Sameer Dhavale 1062306a36Sopenharmony_ci * Vineet Gupta 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/crc32.h> 1462306a36Sopenharmony_ci#include <linux/etherdevice.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/io.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/of_address.h> 2062306a36Sopenharmony_ci#include <linux/of_irq.h> 2162306a36Sopenharmony_ci#include <linux/of_mdio.h> 2262306a36Sopenharmony_ci#include <linux/of_net.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "emac.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic void arc_emac_restart(struct net_device *ndev); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/** 2962306a36Sopenharmony_ci * arc_emac_tx_avail - Return the number of available slots in the tx ring. 3062306a36Sopenharmony_ci * @priv: Pointer to ARC EMAC private data structure. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * returns: the number of slots available for transmission in tx the ring. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cistatic inline int arc_emac_tx_avail(struct arc_emac_priv *priv) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci return (priv->txbd_dirty + TX_BD_NUM - priv->txbd_curr - 1) % TX_BD_NUM; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/** 4062306a36Sopenharmony_ci * arc_emac_adjust_link - Adjust the PHY link duplex. 4162306a36Sopenharmony_ci * @ndev: Pointer to the net_device structure. 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * This function is called to change the duplex setting after auto negotiation 4462306a36Sopenharmony_ci * is done by the PHY. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_cistatic void arc_emac_adjust_link(struct net_device *ndev) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 4962306a36Sopenharmony_ci struct phy_device *phy_dev = ndev->phydev; 5062306a36Sopenharmony_ci unsigned int reg, state_changed = 0; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (priv->link != phy_dev->link) { 5362306a36Sopenharmony_ci priv->link = phy_dev->link; 5462306a36Sopenharmony_ci state_changed = 1; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (priv->speed != phy_dev->speed) { 5862306a36Sopenharmony_ci priv->speed = phy_dev->speed; 5962306a36Sopenharmony_ci state_changed = 1; 6062306a36Sopenharmony_ci if (priv->set_mac_speed) 6162306a36Sopenharmony_ci priv->set_mac_speed(priv, priv->speed); 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (priv->duplex != phy_dev->duplex) { 6562306a36Sopenharmony_ci reg = arc_reg_get(priv, R_CTRL); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (phy_dev->duplex == DUPLEX_FULL) 6862306a36Sopenharmony_ci reg |= ENFL_MASK; 6962306a36Sopenharmony_ci else 7062306a36Sopenharmony_ci reg &= ~ENFL_MASK; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci arc_reg_set(priv, R_CTRL, reg); 7362306a36Sopenharmony_ci priv->duplex = phy_dev->duplex; 7462306a36Sopenharmony_ci state_changed = 1; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (state_changed) 7862306a36Sopenharmony_ci phy_print_status(phy_dev); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/** 8262306a36Sopenharmony_ci * arc_emac_get_drvinfo - Get EMAC driver information. 8362306a36Sopenharmony_ci * @ndev: Pointer to net_device structure. 8462306a36Sopenharmony_ci * @info: Pointer to ethtool_drvinfo structure. 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * This implements ethtool command for getting the driver information. 8762306a36Sopenharmony_ci * Issue "ethtool -i ethX" under linux prompt to execute this function. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cistatic void arc_emac_get_drvinfo(struct net_device *ndev, 9062306a36Sopenharmony_ci struct ethtool_drvinfo *info) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci strscpy(info->driver, priv->drv_name, sizeof(info->driver)); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic const struct ethtool_ops arc_emac_ethtool_ops = { 9862306a36Sopenharmony_ci .get_drvinfo = arc_emac_get_drvinfo, 9962306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 10062306a36Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 10162306a36Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#define FIRST_OR_LAST_MASK (FIRST_MASK | LAST_MASK) 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/** 10762306a36Sopenharmony_ci * arc_emac_tx_clean - clears processed by EMAC Tx BDs. 10862306a36Sopenharmony_ci * @ndev: Pointer to the network device. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_cistatic void arc_emac_tx_clean(struct net_device *ndev) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 11362306a36Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 11462306a36Sopenharmony_ci unsigned int i; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci for (i = 0; i < TX_BD_NUM; i++) { 11762306a36Sopenharmony_ci unsigned int *txbd_dirty = &priv->txbd_dirty; 11862306a36Sopenharmony_ci struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty]; 11962306a36Sopenharmony_ci struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty]; 12062306a36Sopenharmony_ci struct sk_buff *skb = tx_buff->skb; 12162306a36Sopenharmony_ci unsigned int info = le32_to_cpu(txbd->info); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if ((info & FOR_EMAC) || !txbd->data || !skb) 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) { 12762306a36Sopenharmony_ci stats->tx_errors++; 12862306a36Sopenharmony_ci stats->tx_dropped++; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (info & DEFR) 13162306a36Sopenharmony_ci stats->tx_carrier_errors++; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (info & LTCL) 13462306a36Sopenharmony_ci stats->collisions++; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (info & UFLO) 13762306a36Sopenharmony_ci stats->tx_fifo_errors++; 13862306a36Sopenharmony_ci } else if (likely(info & FIRST_OR_LAST_MASK)) { 13962306a36Sopenharmony_ci stats->tx_packets++; 14062306a36Sopenharmony_ci stats->tx_bytes += skb->len; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci dma_unmap_single(&ndev->dev, dma_unmap_addr(tx_buff, addr), 14462306a36Sopenharmony_ci dma_unmap_len(tx_buff, len), DMA_TO_DEVICE); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* return the sk_buff to system */ 14762306a36Sopenharmony_ci dev_consume_skb_irq(skb); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci txbd->data = 0; 15062306a36Sopenharmony_ci txbd->info = 0; 15162306a36Sopenharmony_ci tx_buff->skb = NULL; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci *txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Ensure that txbd_dirty is visible to tx() before checking 15762306a36Sopenharmony_ci * for queue stopped. 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci smp_mb(); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (netif_queue_stopped(ndev) && arc_emac_tx_avail(priv)) 16262306a36Sopenharmony_ci netif_wake_queue(ndev); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/** 16662306a36Sopenharmony_ci * arc_emac_rx - processing of Rx packets. 16762306a36Sopenharmony_ci * @ndev: Pointer to the network device. 16862306a36Sopenharmony_ci * @budget: How many BDs to process on 1 call. 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * returns: Number of processed BDs 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * Iterate through Rx BDs and deliver received packages to upper layer. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_cistatic int arc_emac_rx(struct net_device *ndev, int budget) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 17762306a36Sopenharmony_ci unsigned int work_done; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci for (work_done = 0; work_done < budget; work_done++) { 18062306a36Sopenharmony_ci unsigned int *last_rx_bd = &priv->last_rx_bd; 18162306a36Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 18262306a36Sopenharmony_ci struct buffer_state *rx_buff = &priv->rx_buff[*last_rx_bd]; 18362306a36Sopenharmony_ci struct arc_emac_bd *rxbd = &priv->rxbd[*last_rx_bd]; 18462306a36Sopenharmony_ci unsigned int pktlen, info = le32_to_cpu(rxbd->info); 18562306a36Sopenharmony_ci struct sk_buff *skb; 18662306a36Sopenharmony_ci dma_addr_t addr; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (unlikely((info & OWN_MASK) == FOR_EMAC)) 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* Make a note that we saw a packet at this BD. 19262306a36Sopenharmony_ci * So next time, driver starts from this + 1 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci *last_rx_bd = (*last_rx_bd + 1) % RX_BD_NUM; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (unlikely((info & FIRST_OR_LAST_MASK) != 19762306a36Sopenharmony_ci FIRST_OR_LAST_MASK)) { 19862306a36Sopenharmony_ci /* We pre-allocate buffers of MTU size so incoming 19962306a36Sopenharmony_ci * packets won't be split/chained. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci if (net_ratelimit()) 20262306a36Sopenharmony_ci netdev_err(ndev, "incomplete packet received\n"); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* Return ownership to EMAC */ 20562306a36Sopenharmony_ci rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE); 20662306a36Sopenharmony_ci stats->rx_errors++; 20762306a36Sopenharmony_ci stats->rx_length_errors++; 20862306a36Sopenharmony_ci continue; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* Prepare the BD for next cycle. netif_receive_skb() 21262306a36Sopenharmony_ci * only if new skb was allocated and mapped to avoid holes 21362306a36Sopenharmony_ci * in the RX fifo. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci skb = netdev_alloc_skb_ip_align(ndev, EMAC_BUFFER_SIZE); 21662306a36Sopenharmony_ci if (unlikely(!skb)) { 21762306a36Sopenharmony_ci if (net_ratelimit()) 21862306a36Sopenharmony_ci netdev_err(ndev, "cannot allocate skb\n"); 21962306a36Sopenharmony_ci /* Return ownership to EMAC */ 22062306a36Sopenharmony_ci rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE); 22162306a36Sopenharmony_ci stats->rx_errors++; 22262306a36Sopenharmony_ci stats->rx_dropped++; 22362306a36Sopenharmony_ci continue; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci addr = dma_map_single(&ndev->dev, (void *)skb->data, 22762306a36Sopenharmony_ci EMAC_BUFFER_SIZE, DMA_FROM_DEVICE); 22862306a36Sopenharmony_ci if (dma_mapping_error(&ndev->dev, addr)) { 22962306a36Sopenharmony_ci if (net_ratelimit()) 23062306a36Sopenharmony_ci netdev_err(ndev, "cannot map dma buffer\n"); 23162306a36Sopenharmony_ci dev_kfree_skb(skb); 23262306a36Sopenharmony_ci /* Return ownership to EMAC */ 23362306a36Sopenharmony_ci rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE); 23462306a36Sopenharmony_ci stats->rx_errors++; 23562306a36Sopenharmony_ci stats->rx_dropped++; 23662306a36Sopenharmony_ci continue; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* unmap previosly mapped skb */ 24062306a36Sopenharmony_ci dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr), 24162306a36Sopenharmony_ci dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci pktlen = info & LEN_MASK; 24462306a36Sopenharmony_ci stats->rx_packets++; 24562306a36Sopenharmony_ci stats->rx_bytes += pktlen; 24662306a36Sopenharmony_ci skb_put(rx_buff->skb, pktlen); 24762306a36Sopenharmony_ci rx_buff->skb->dev = ndev; 24862306a36Sopenharmony_ci rx_buff->skb->protocol = eth_type_trans(rx_buff->skb, ndev); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci netif_receive_skb(rx_buff->skb); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci rx_buff->skb = skb; 25362306a36Sopenharmony_ci dma_unmap_addr_set(rx_buff, addr, addr); 25462306a36Sopenharmony_ci dma_unmap_len_set(rx_buff, len, EMAC_BUFFER_SIZE); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci rxbd->data = cpu_to_le32(addr); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Make sure pointer to data buffer is set */ 25962306a36Sopenharmony_ci wmb(); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* Return ownership to EMAC */ 26262306a36Sopenharmony_ci rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return work_done; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/** 26962306a36Sopenharmony_ci * arc_emac_rx_miss_handle - handle R_MISS register 27062306a36Sopenharmony_ci * @ndev: Pointer to the net_device structure. 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_cistatic void arc_emac_rx_miss_handle(struct net_device *ndev) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 27562306a36Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 27662306a36Sopenharmony_ci unsigned int miss; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci miss = arc_reg_get(priv, R_MISS); 27962306a36Sopenharmony_ci if (miss) { 28062306a36Sopenharmony_ci stats->rx_errors += miss; 28162306a36Sopenharmony_ci stats->rx_missed_errors += miss; 28262306a36Sopenharmony_ci priv->rx_missed_errors += miss; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/** 28762306a36Sopenharmony_ci * arc_emac_rx_stall_check - check RX stall 28862306a36Sopenharmony_ci * @ndev: Pointer to the net_device structure. 28962306a36Sopenharmony_ci * @budget: How many BDs requested to process on 1 call. 29062306a36Sopenharmony_ci * @work_done: How many BDs processed 29162306a36Sopenharmony_ci * 29262306a36Sopenharmony_ci * Under certain conditions EMAC stop reception of incoming packets and 29362306a36Sopenharmony_ci * continuously increment R_MISS register instead of saving data into 29462306a36Sopenharmony_ci * provided buffer. This function detect that condition and restart 29562306a36Sopenharmony_ci * EMAC. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_cistatic void arc_emac_rx_stall_check(struct net_device *ndev, 29862306a36Sopenharmony_ci int budget, unsigned int work_done) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 30162306a36Sopenharmony_ci struct arc_emac_bd *rxbd; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (work_done) 30462306a36Sopenharmony_ci priv->rx_missed_errors = 0; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (priv->rx_missed_errors && budget) { 30762306a36Sopenharmony_ci rxbd = &priv->rxbd[priv->last_rx_bd]; 30862306a36Sopenharmony_ci if (le32_to_cpu(rxbd->info) & FOR_EMAC) { 30962306a36Sopenharmony_ci arc_emac_restart(ndev); 31062306a36Sopenharmony_ci priv->rx_missed_errors = 0; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/** 31662306a36Sopenharmony_ci * arc_emac_poll - NAPI poll handler. 31762306a36Sopenharmony_ci * @napi: Pointer to napi_struct structure. 31862306a36Sopenharmony_ci * @budget: How many BDs to process on 1 call. 31962306a36Sopenharmony_ci * 32062306a36Sopenharmony_ci * returns: Number of processed BDs 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_cistatic int arc_emac_poll(struct napi_struct *napi, int budget) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct net_device *ndev = napi->dev; 32562306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 32662306a36Sopenharmony_ci unsigned int work_done; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci arc_emac_tx_clean(ndev); 32962306a36Sopenharmony_ci arc_emac_rx_miss_handle(ndev); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci work_done = arc_emac_rx(ndev, budget); 33262306a36Sopenharmony_ci if (work_done < budget) { 33362306a36Sopenharmony_ci napi_complete_done(napi, work_done); 33462306a36Sopenharmony_ci arc_reg_or(priv, R_ENABLE, RXINT_MASK | TXINT_MASK); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci arc_emac_rx_stall_check(ndev, budget, work_done); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return work_done; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci/** 34362306a36Sopenharmony_ci * arc_emac_intr - Global interrupt handler for EMAC. 34462306a36Sopenharmony_ci * @irq: irq number. 34562306a36Sopenharmony_ci * @dev_instance: device instance. 34662306a36Sopenharmony_ci * 34762306a36Sopenharmony_ci * returns: IRQ_HANDLED for all cases. 34862306a36Sopenharmony_ci * 34962306a36Sopenharmony_ci * ARC EMAC has only 1 interrupt line, and depending on bits raised in 35062306a36Sopenharmony_ci * STATUS register we may tell what is a reason for interrupt to fire. 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_cistatic irqreturn_t arc_emac_intr(int irq, void *dev_instance) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct net_device *ndev = dev_instance; 35562306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 35662306a36Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 35762306a36Sopenharmony_ci unsigned int status; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci status = arc_reg_get(priv, R_STATUS); 36062306a36Sopenharmony_ci status &= ~MDIO_MASK; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* Reset all flags except "MDIO complete" */ 36362306a36Sopenharmony_ci arc_reg_set(priv, R_STATUS, status); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (status & (RXINT_MASK | TXINT_MASK)) { 36662306a36Sopenharmony_ci if (likely(napi_schedule_prep(&priv->napi))) { 36762306a36Sopenharmony_ci arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK); 36862306a36Sopenharmony_ci __napi_schedule(&priv->napi); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (status & ERR_MASK) { 37362306a36Sopenharmony_ci /* MSER/RXCR/RXFR/RXFL interrupt fires on corresponding 37462306a36Sopenharmony_ci * 8-bit error counter overrun. 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (status & MSER_MASK) { 37862306a36Sopenharmony_ci stats->rx_missed_errors += 0x100; 37962306a36Sopenharmony_ci stats->rx_errors += 0x100; 38062306a36Sopenharmony_ci priv->rx_missed_errors += 0x100; 38162306a36Sopenharmony_ci napi_schedule(&priv->napi); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (status & RXCR_MASK) { 38562306a36Sopenharmony_ci stats->rx_crc_errors += 0x100; 38662306a36Sopenharmony_ci stats->rx_errors += 0x100; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (status & RXFR_MASK) { 39062306a36Sopenharmony_ci stats->rx_frame_errors += 0x100; 39162306a36Sopenharmony_ci stats->rx_errors += 0x100; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (status & RXFL_MASK) { 39562306a36Sopenharmony_ci stats->rx_over_errors += 0x100; 39662306a36Sopenharmony_ci stats->rx_errors += 0x100; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci return IRQ_HANDLED; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 40462306a36Sopenharmony_cistatic void arc_emac_poll_controller(struct net_device *dev) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci disable_irq(dev->irq); 40762306a36Sopenharmony_ci arc_emac_intr(dev->irq, dev); 40862306a36Sopenharmony_ci enable_irq(dev->irq); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci#endif 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci/** 41362306a36Sopenharmony_ci * arc_emac_open - Open the network device. 41462306a36Sopenharmony_ci * @ndev: Pointer to the network device. 41562306a36Sopenharmony_ci * 41662306a36Sopenharmony_ci * returns: 0, on success or non-zero error value on failure. 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci * This function sets the MAC address, requests and enables an IRQ 41962306a36Sopenharmony_ci * for the EMAC device and starts the Tx queue. 42062306a36Sopenharmony_ci * It also connects to the phy device. 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_cistatic int arc_emac_open(struct net_device *ndev) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 42562306a36Sopenharmony_ci struct phy_device *phy_dev = ndev->phydev; 42662306a36Sopenharmony_ci int i; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci phy_dev->autoneg = AUTONEG_ENABLE; 42962306a36Sopenharmony_ci phy_dev->speed = 0; 43062306a36Sopenharmony_ci phy_dev->duplex = 0; 43162306a36Sopenharmony_ci linkmode_and(phy_dev->advertising, phy_dev->advertising, 43262306a36Sopenharmony_ci phy_dev->supported); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci priv->last_rx_bd = 0; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* Allocate and set buffers for Rx BD's */ 43762306a36Sopenharmony_ci for (i = 0; i < RX_BD_NUM; i++) { 43862306a36Sopenharmony_ci dma_addr_t addr; 43962306a36Sopenharmony_ci unsigned int *last_rx_bd = &priv->last_rx_bd; 44062306a36Sopenharmony_ci struct arc_emac_bd *rxbd = &priv->rxbd[*last_rx_bd]; 44162306a36Sopenharmony_ci struct buffer_state *rx_buff = &priv->rx_buff[*last_rx_bd]; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci rx_buff->skb = netdev_alloc_skb_ip_align(ndev, 44462306a36Sopenharmony_ci EMAC_BUFFER_SIZE); 44562306a36Sopenharmony_ci if (unlikely(!rx_buff->skb)) 44662306a36Sopenharmony_ci return -ENOMEM; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci addr = dma_map_single(&ndev->dev, (void *)rx_buff->skb->data, 44962306a36Sopenharmony_ci EMAC_BUFFER_SIZE, DMA_FROM_DEVICE); 45062306a36Sopenharmony_ci if (dma_mapping_error(&ndev->dev, addr)) { 45162306a36Sopenharmony_ci netdev_err(ndev, "cannot dma map\n"); 45262306a36Sopenharmony_ci dev_kfree_skb(rx_buff->skb); 45362306a36Sopenharmony_ci return -ENOMEM; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci dma_unmap_addr_set(rx_buff, addr, addr); 45662306a36Sopenharmony_ci dma_unmap_len_set(rx_buff, len, EMAC_BUFFER_SIZE); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci rxbd->data = cpu_to_le32(addr); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* Make sure pointer to data buffer is set */ 46162306a36Sopenharmony_ci wmb(); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Return ownership to EMAC */ 46462306a36Sopenharmony_ci rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci *last_rx_bd = (*last_rx_bd + 1) % RX_BD_NUM; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci priv->txbd_curr = 0; 47062306a36Sopenharmony_ci priv->txbd_dirty = 0; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* Clean Tx BD's */ 47362306a36Sopenharmony_ci memset(priv->txbd, 0, TX_RING_SZ); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Initialize logical address filter */ 47662306a36Sopenharmony_ci arc_reg_set(priv, R_LAFL, 0); 47762306a36Sopenharmony_ci arc_reg_set(priv, R_LAFH, 0); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* Set BD ring pointers for device side */ 48062306a36Sopenharmony_ci arc_reg_set(priv, R_RX_RING, (unsigned int)priv->rxbd_dma); 48162306a36Sopenharmony_ci arc_reg_set(priv, R_TX_RING, (unsigned int)priv->txbd_dma); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* Enable interrupts */ 48462306a36Sopenharmony_ci arc_reg_set(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* Set CONTROL */ 48762306a36Sopenharmony_ci arc_reg_set(priv, R_CTRL, 48862306a36Sopenharmony_ci (RX_BD_NUM << 24) | /* RX BD table length */ 48962306a36Sopenharmony_ci (TX_BD_NUM << 16) | /* TX BD table length */ 49062306a36Sopenharmony_ci TXRN_MASK | RXRN_MASK); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci napi_enable(&priv->napi); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* Enable EMAC */ 49562306a36Sopenharmony_ci arc_reg_or(priv, R_CTRL, EN_MASK); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci phy_start(ndev->phydev); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci netif_start_queue(ndev); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return 0; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci/** 50562306a36Sopenharmony_ci * arc_emac_set_rx_mode - Change the receive filtering mode. 50662306a36Sopenharmony_ci * @ndev: Pointer to the network device. 50762306a36Sopenharmony_ci * 50862306a36Sopenharmony_ci * This function enables/disables promiscuous or all-multicast mode 50962306a36Sopenharmony_ci * and updates the multicast filtering list of the network device. 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_cistatic void arc_emac_set_rx_mode(struct net_device *ndev) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (ndev->flags & IFF_PROMISC) { 51662306a36Sopenharmony_ci arc_reg_or(priv, R_CTRL, PROM_MASK); 51762306a36Sopenharmony_ci } else { 51862306a36Sopenharmony_ci arc_reg_clr(priv, R_CTRL, PROM_MASK); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (ndev->flags & IFF_ALLMULTI) { 52162306a36Sopenharmony_ci arc_reg_set(priv, R_LAFL, ~0); 52262306a36Sopenharmony_ci arc_reg_set(priv, R_LAFH, ~0); 52362306a36Sopenharmony_ci } else if (ndev->flags & IFF_MULTICAST) { 52462306a36Sopenharmony_ci struct netdev_hw_addr *ha; 52562306a36Sopenharmony_ci unsigned int filter[2] = { 0, 0 }; 52662306a36Sopenharmony_ci int bit; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, ndev) { 52962306a36Sopenharmony_ci bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26; 53062306a36Sopenharmony_ci filter[bit >> 5] |= 1 << (bit & 31); 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci arc_reg_set(priv, R_LAFL, filter[0]); 53462306a36Sopenharmony_ci arc_reg_set(priv, R_LAFH, filter[1]); 53562306a36Sopenharmony_ci } else { 53662306a36Sopenharmony_ci arc_reg_set(priv, R_LAFL, 0); 53762306a36Sopenharmony_ci arc_reg_set(priv, R_LAFH, 0); 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/** 54362306a36Sopenharmony_ci * arc_free_tx_queue - free skb from tx queue 54462306a36Sopenharmony_ci * @ndev: Pointer to the network device. 54562306a36Sopenharmony_ci * 54662306a36Sopenharmony_ci * This function must be called while EMAC disable 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_cistatic void arc_free_tx_queue(struct net_device *ndev) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 55162306a36Sopenharmony_ci unsigned int i; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci for (i = 0; i < TX_BD_NUM; i++) { 55462306a36Sopenharmony_ci struct arc_emac_bd *txbd = &priv->txbd[i]; 55562306a36Sopenharmony_ci struct buffer_state *tx_buff = &priv->tx_buff[i]; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (tx_buff->skb) { 55862306a36Sopenharmony_ci dma_unmap_single(&ndev->dev, 55962306a36Sopenharmony_ci dma_unmap_addr(tx_buff, addr), 56062306a36Sopenharmony_ci dma_unmap_len(tx_buff, len), 56162306a36Sopenharmony_ci DMA_TO_DEVICE); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* return the sk_buff to system */ 56462306a36Sopenharmony_ci dev_kfree_skb_irq(tx_buff->skb); 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci txbd->info = 0; 56862306a36Sopenharmony_ci txbd->data = 0; 56962306a36Sopenharmony_ci tx_buff->skb = NULL; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci/** 57462306a36Sopenharmony_ci * arc_free_rx_queue - free skb from rx queue 57562306a36Sopenharmony_ci * @ndev: Pointer to the network device. 57662306a36Sopenharmony_ci * 57762306a36Sopenharmony_ci * This function must be called while EMAC disable 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_cistatic void arc_free_rx_queue(struct net_device *ndev) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 58262306a36Sopenharmony_ci unsigned int i; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci for (i = 0; i < RX_BD_NUM; i++) { 58562306a36Sopenharmony_ci struct arc_emac_bd *rxbd = &priv->rxbd[i]; 58662306a36Sopenharmony_ci struct buffer_state *rx_buff = &priv->rx_buff[i]; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (rx_buff->skb) { 58962306a36Sopenharmony_ci dma_unmap_single(&ndev->dev, 59062306a36Sopenharmony_ci dma_unmap_addr(rx_buff, addr), 59162306a36Sopenharmony_ci dma_unmap_len(rx_buff, len), 59262306a36Sopenharmony_ci DMA_FROM_DEVICE); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* return the sk_buff to system */ 59562306a36Sopenharmony_ci dev_kfree_skb_irq(rx_buff->skb); 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci rxbd->info = 0; 59962306a36Sopenharmony_ci rxbd->data = 0; 60062306a36Sopenharmony_ci rx_buff->skb = NULL; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci/** 60562306a36Sopenharmony_ci * arc_emac_stop - Close the network device. 60662306a36Sopenharmony_ci * @ndev: Pointer to the network device. 60762306a36Sopenharmony_ci * 60862306a36Sopenharmony_ci * This function stops the Tx queue, disables interrupts and frees the IRQ for 60962306a36Sopenharmony_ci * the EMAC device. 61062306a36Sopenharmony_ci * It also disconnects the PHY device associated with the EMAC device. 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_cistatic int arc_emac_stop(struct net_device *ndev) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci napi_disable(&priv->napi); 61762306a36Sopenharmony_ci netif_stop_queue(ndev); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci phy_stop(ndev->phydev); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci /* Disable interrupts */ 62262306a36Sopenharmony_ci arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* Disable EMAC */ 62562306a36Sopenharmony_ci arc_reg_clr(priv, R_CTRL, EN_MASK); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* Return the sk_buff to system */ 62862306a36Sopenharmony_ci arc_free_tx_queue(ndev); 62962306a36Sopenharmony_ci arc_free_rx_queue(ndev); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci return 0; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci/** 63562306a36Sopenharmony_ci * arc_emac_stats - Get system network statistics. 63662306a36Sopenharmony_ci * @ndev: Pointer to net_device structure. 63762306a36Sopenharmony_ci * 63862306a36Sopenharmony_ci * Returns the address of the device statistics structure. 63962306a36Sopenharmony_ci * Statistics are updated in interrupt handler. 64062306a36Sopenharmony_ci */ 64162306a36Sopenharmony_cistatic struct net_device_stats *arc_emac_stats(struct net_device *ndev) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 64462306a36Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 64562306a36Sopenharmony_ci unsigned long miss, rxerr; 64662306a36Sopenharmony_ci u8 rxcrc, rxfram, rxoflow; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci rxerr = arc_reg_get(priv, R_RXERR); 64962306a36Sopenharmony_ci miss = arc_reg_get(priv, R_MISS); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci rxcrc = rxerr; 65262306a36Sopenharmony_ci rxfram = rxerr >> 8; 65362306a36Sopenharmony_ci rxoflow = rxerr >> 16; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci stats->rx_errors += miss; 65662306a36Sopenharmony_ci stats->rx_errors += rxcrc + rxfram + rxoflow; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci stats->rx_over_errors += rxoflow; 65962306a36Sopenharmony_ci stats->rx_frame_errors += rxfram; 66062306a36Sopenharmony_ci stats->rx_crc_errors += rxcrc; 66162306a36Sopenharmony_ci stats->rx_missed_errors += miss; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci return stats; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci/** 66762306a36Sopenharmony_ci * arc_emac_tx - Starts the data transmission. 66862306a36Sopenharmony_ci * @skb: sk_buff pointer that contains data to be Transmitted. 66962306a36Sopenharmony_ci * @ndev: Pointer to net_device structure. 67062306a36Sopenharmony_ci * 67162306a36Sopenharmony_ci * returns: NETDEV_TX_OK, on success 67262306a36Sopenharmony_ci * NETDEV_TX_BUSY, if any of the descriptors are not free. 67362306a36Sopenharmony_ci * 67462306a36Sopenharmony_ci * This function is invoked from upper layers to initiate transmission. 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_cistatic netdev_tx_t arc_emac_tx(struct sk_buff *skb, struct net_device *ndev) 67762306a36Sopenharmony_ci{ 67862306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 67962306a36Sopenharmony_ci unsigned int len, *txbd_curr = &priv->txbd_curr; 68062306a36Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 68162306a36Sopenharmony_ci __le32 *info = &priv->txbd[*txbd_curr].info; 68262306a36Sopenharmony_ci dma_addr_t addr; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (skb_padto(skb, ETH_ZLEN)) 68562306a36Sopenharmony_ci return NETDEV_TX_OK; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci len = max_t(unsigned int, ETH_ZLEN, skb->len); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (unlikely(!arc_emac_tx_avail(priv))) { 69062306a36Sopenharmony_ci netif_stop_queue(ndev); 69162306a36Sopenharmony_ci netdev_err(ndev, "BUG! Tx Ring full when queue awake!\n"); 69262306a36Sopenharmony_ci return NETDEV_TX_BUSY; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci addr = dma_map_single(&ndev->dev, (void *)skb->data, len, 69662306a36Sopenharmony_ci DMA_TO_DEVICE); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci if (unlikely(dma_mapping_error(&ndev->dev, addr))) { 69962306a36Sopenharmony_ci stats->tx_dropped++; 70062306a36Sopenharmony_ci stats->tx_errors++; 70162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 70262306a36Sopenharmony_ci return NETDEV_TX_OK; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci dma_unmap_addr_set(&priv->tx_buff[*txbd_curr], addr, addr); 70562306a36Sopenharmony_ci dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci priv->txbd[*txbd_curr].data = cpu_to_le32(addr); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci /* Make sure pointer to data buffer is set */ 71062306a36Sopenharmony_ci wmb(); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci skb_tx_timestamp(skb); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci *info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* Make sure info word is set */ 71762306a36Sopenharmony_ci wmb(); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci priv->tx_buff[*txbd_curr].skb = skb; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* Increment index to point to the next BD */ 72262306a36Sopenharmony_ci *txbd_curr = (*txbd_curr + 1) % TX_BD_NUM; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* Ensure that tx_clean() sees the new txbd_curr before 72562306a36Sopenharmony_ci * checking the queue status. This prevents an unneeded wake 72662306a36Sopenharmony_ci * of the queue in tx_clean(). 72762306a36Sopenharmony_ci */ 72862306a36Sopenharmony_ci smp_mb(); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (!arc_emac_tx_avail(priv)) { 73162306a36Sopenharmony_ci netif_stop_queue(ndev); 73262306a36Sopenharmony_ci /* Refresh tx_dirty */ 73362306a36Sopenharmony_ci smp_mb(); 73462306a36Sopenharmony_ci if (arc_emac_tx_avail(priv)) 73562306a36Sopenharmony_ci netif_start_queue(ndev); 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci arc_reg_set(priv, R_STATUS, TXPL_MASK); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci return NETDEV_TX_OK; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic void arc_emac_set_address_internal(struct net_device *ndev) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 74662306a36Sopenharmony_ci unsigned int addr_low, addr_hi; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci addr_low = le32_to_cpu(*(__le32 *)&ndev->dev_addr[0]); 74962306a36Sopenharmony_ci addr_hi = le16_to_cpu(*(__le16 *)&ndev->dev_addr[4]); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci arc_reg_set(priv, R_ADDRL, addr_low); 75262306a36Sopenharmony_ci arc_reg_set(priv, R_ADDRH, addr_hi); 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci/** 75662306a36Sopenharmony_ci * arc_emac_set_address - Set the MAC address for this device. 75762306a36Sopenharmony_ci * @ndev: Pointer to net_device structure. 75862306a36Sopenharmony_ci * @p: 6 byte Address to be written as MAC address. 75962306a36Sopenharmony_ci * 76062306a36Sopenharmony_ci * This function copies the HW address from the sockaddr structure to the 76162306a36Sopenharmony_ci * net_device structure and updates the address in HW. 76262306a36Sopenharmony_ci * 76362306a36Sopenharmony_ci * returns: -EBUSY if the net device is busy or 0 if the address is set 76462306a36Sopenharmony_ci * successfully. 76562306a36Sopenharmony_ci */ 76662306a36Sopenharmony_cistatic int arc_emac_set_address(struct net_device *ndev, void *p) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci struct sockaddr *addr = p; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (netif_running(ndev)) 77162306a36Sopenharmony_ci return -EBUSY; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 77462306a36Sopenharmony_ci return -EADDRNOTAVAIL; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci eth_hw_addr_set(ndev, addr->sa_data); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci arc_emac_set_address_internal(ndev); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci return 0; 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci/** 78462306a36Sopenharmony_ci * arc_emac_restart - Restart EMAC 78562306a36Sopenharmony_ci * @ndev: Pointer to net_device structure. 78662306a36Sopenharmony_ci * 78762306a36Sopenharmony_ci * This function do hardware reset of EMAC in order to restore 78862306a36Sopenharmony_ci * network packets reception. 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_cistatic void arc_emac_restart(struct net_device *ndev) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 79362306a36Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 79462306a36Sopenharmony_ci int i; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (net_ratelimit()) 79762306a36Sopenharmony_ci netdev_warn(ndev, "restarting stalled EMAC\n"); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci netif_stop_queue(ndev); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci /* Disable interrupts */ 80262306a36Sopenharmony_ci arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* Disable EMAC */ 80562306a36Sopenharmony_ci arc_reg_clr(priv, R_CTRL, EN_MASK); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci /* Return the sk_buff to system */ 80862306a36Sopenharmony_ci arc_free_tx_queue(ndev); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* Clean Tx BD's */ 81162306a36Sopenharmony_ci priv->txbd_curr = 0; 81262306a36Sopenharmony_ci priv->txbd_dirty = 0; 81362306a36Sopenharmony_ci memset(priv->txbd, 0, TX_RING_SZ); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci for (i = 0; i < RX_BD_NUM; i++) { 81662306a36Sopenharmony_ci struct arc_emac_bd *rxbd = &priv->rxbd[i]; 81762306a36Sopenharmony_ci unsigned int info = le32_to_cpu(rxbd->info); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (!(info & FOR_EMAC)) { 82062306a36Sopenharmony_ci stats->rx_errors++; 82162306a36Sopenharmony_ci stats->rx_dropped++; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci /* Return ownership to EMAC */ 82462306a36Sopenharmony_ci rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE); 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci priv->last_rx_bd = 0; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* Make sure info is visible to EMAC before enable */ 82962306a36Sopenharmony_ci wmb(); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* Enable interrupts */ 83262306a36Sopenharmony_ci arc_reg_set(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /* Enable EMAC */ 83562306a36Sopenharmony_ci arc_reg_or(priv, R_CTRL, EN_MASK); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci netif_start_queue(ndev); 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic const struct net_device_ops arc_emac_netdev_ops = { 84162306a36Sopenharmony_ci .ndo_open = arc_emac_open, 84262306a36Sopenharmony_ci .ndo_stop = arc_emac_stop, 84362306a36Sopenharmony_ci .ndo_start_xmit = arc_emac_tx, 84462306a36Sopenharmony_ci .ndo_set_mac_address = arc_emac_set_address, 84562306a36Sopenharmony_ci .ndo_get_stats = arc_emac_stats, 84662306a36Sopenharmony_ci .ndo_set_rx_mode = arc_emac_set_rx_mode, 84762306a36Sopenharmony_ci .ndo_eth_ioctl = phy_do_ioctl_running, 84862306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 84962306a36Sopenharmony_ci .ndo_poll_controller = arc_emac_poll_controller, 85062306a36Sopenharmony_ci#endif 85162306a36Sopenharmony_ci}; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ciint arc_emac_probe(struct net_device *ndev, int interface) 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci struct device *dev = ndev->dev.parent; 85662306a36Sopenharmony_ci struct resource res_regs; 85762306a36Sopenharmony_ci struct device_node *phy_node; 85862306a36Sopenharmony_ci struct phy_device *phydev = NULL; 85962306a36Sopenharmony_ci struct arc_emac_priv *priv; 86062306a36Sopenharmony_ci unsigned int id, clock_frequency, irq; 86162306a36Sopenharmony_ci int err; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* Get PHY from device tree */ 86462306a36Sopenharmony_ci phy_node = of_parse_phandle(dev->of_node, "phy", 0); 86562306a36Sopenharmony_ci if (!phy_node) { 86662306a36Sopenharmony_ci dev_err(dev, "failed to retrieve phy description from device tree\n"); 86762306a36Sopenharmony_ci return -ENODEV; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* Get EMAC registers base address from device tree */ 87162306a36Sopenharmony_ci err = of_address_to_resource(dev->of_node, 0, &res_regs); 87262306a36Sopenharmony_ci if (err) { 87362306a36Sopenharmony_ci dev_err(dev, "failed to retrieve registers base from device tree\n"); 87462306a36Sopenharmony_ci err = -ENODEV; 87562306a36Sopenharmony_ci goto out_put_node; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* Get IRQ from device tree */ 87962306a36Sopenharmony_ci irq = irq_of_parse_and_map(dev->of_node, 0); 88062306a36Sopenharmony_ci if (!irq) { 88162306a36Sopenharmony_ci dev_err(dev, "failed to retrieve <irq> value from device tree\n"); 88262306a36Sopenharmony_ci err = -ENODEV; 88362306a36Sopenharmony_ci goto out_put_node; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci ndev->netdev_ops = &arc_emac_netdev_ops; 88762306a36Sopenharmony_ci ndev->ethtool_ops = &arc_emac_ethtool_ops; 88862306a36Sopenharmony_ci ndev->watchdog_timeo = TX_TIMEOUT; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci priv = netdev_priv(ndev); 89162306a36Sopenharmony_ci priv->dev = dev; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci priv->regs = devm_ioremap_resource(dev, &res_regs); 89462306a36Sopenharmony_ci if (IS_ERR(priv->regs)) { 89562306a36Sopenharmony_ci err = PTR_ERR(priv->regs); 89662306a36Sopenharmony_ci goto out_put_node; 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (priv->clk) { 90262306a36Sopenharmony_ci err = clk_prepare_enable(priv->clk); 90362306a36Sopenharmony_ci if (err) { 90462306a36Sopenharmony_ci dev_err(dev, "failed to enable clock\n"); 90562306a36Sopenharmony_ci goto out_put_node; 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci clock_frequency = clk_get_rate(priv->clk); 90962306a36Sopenharmony_ci } else { 91062306a36Sopenharmony_ci /* Get CPU clock frequency from device tree */ 91162306a36Sopenharmony_ci if (of_property_read_u32(dev->of_node, "clock-frequency", 91262306a36Sopenharmony_ci &clock_frequency)) { 91362306a36Sopenharmony_ci dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n"); 91462306a36Sopenharmony_ci err = -EINVAL; 91562306a36Sopenharmony_ci goto out_put_node; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci id = arc_reg_get(priv, R_ID); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* Check for EMAC revision 5 or 7, magic number */ 92262306a36Sopenharmony_ci if (!(id == 0x0005fd02 || id == 0x0007fd02)) { 92362306a36Sopenharmony_ci dev_err(dev, "ARC EMAC not detected, id=0x%x\n", id); 92462306a36Sopenharmony_ci err = -ENODEV; 92562306a36Sopenharmony_ci goto out_clken; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci dev_info(dev, "ARC EMAC detected with id: 0x%x\n", id); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* Set poll rate so that it polls every 1 ms */ 93062306a36Sopenharmony_ci arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci ndev->irq = irq; 93362306a36Sopenharmony_ci dev_info(dev, "IRQ is %d\n", ndev->irq); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* Register interrupt handler for device */ 93662306a36Sopenharmony_ci err = devm_request_irq(dev, ndev->irq, arc_emac_intr, 0, 93762306a36Sopenharmony_ci ndev->name, ndev); 93862306a36Sopenharmony_ci if (err) { 93962306a36Sopenharmony_ci dev_err(dev, "could not allocate IRQ\n"); 94062306a36Sopenharmony_ci goto out_clken; 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* Get MAC address from device tree */ 94462306a36Sopenharmony_ci err = of_get_ethdev_address(dev->of_node, ndev); 94562306a36Sopenharmony_ci if (err) 94662306a36Sopenharmony_ci eth_hw_addr_random(ndev); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci arc_emac_set_address_internal(ndev); 94962306a36Sopenharmony_ci dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci /* Do 1 allocation instead of 2 separate ones for Rx and Tx BD rings */ 95262306a36Sopenharmony_ci priv->rxbd = dmam_alloc_coherent(dev, RX_RING_SZ + TX_RING_SZ, 95362306a36Sopenharmony_ci &priv->rxbd_dma, GFP_KERNEL); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci if (!priv->rxbd) { 95662306a36Sopenharmony_ci dev_err(dev, "failed to allocate data buffers\n"); 95762306a36Sopenharmony_ci err = -ENOMEM; 95862306a36Sopenharmony_ci goto out_clken; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci priv->txbd = priv->rxbd + RX_BD_NUM; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci priv->txbd_dma = priv->rxbd_dma + RX_RING_SZ; 96462306a36Sopenharmony_ci dev_dbg(dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n", 96562306a36Sopenharmony_ci (unsigned int)priv->rxbd_dma, (unsigned int)priv->txbd_dma); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci err = arc_mdio_probe(priv); 96862306a36Sopenharmony_ci if (err) { 96962306a36Sopenharmony_ci dev_err(dev, "failed to probe MII bus\n"); 97062306a36Sopenharmony_ci goto out_clken; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci phydev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0, 97462306a36Sopenharmony_ci interface); 97562306a36Sopenharmony_ci if (!phydev) { 97662306a36Sopenharmony_ci dev_err(dev, "of_phy_connect() failed\n"); 97762306a36Sopenharmony_ci err = -ENODEV; 97862306a36Sopenharmony_ci goto out_mdio; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci dev_info(dev, "connected to %s phy with id 0x%x\n", 98262306a36Sopenharmony_ci phydev->drv->name, phydev->phy_id); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci netif_napi_add_weight(ndev, &priv->napi, arc_emac_poll, 98562306a36Sopenharmony_ci ARC_EMAC_NAPI_WEIGHT); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci err = register_netdev(ndev); 98862306a36Sopenharmony_ci if (err) { 98962306a36Sopenharmony_ci dev_err(dev, "failed to register network device\n"); 99062306a36Sopenharmony_ci goto out_netif_api; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci of_node_put(phy_node); 99462306a36Sopenharmony_ci return 0; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ciout_netif_api: 99762306a36Sopenharmony_ci netif_napi_del(&priv->napi); 99862306a36Sopenharmony_ci phy_disconnect(phydev); 99962306a36Sopenharmony_ciout_mdio: 100062306a36Sopenharmony_ci arc_mdio_remove(priv); 100162306a36Sopenharmony_ciout_clken: 100262306a36Sopenharmony_ci if (priv->clk) 100362306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 100462306a36Sopenharmony_ciout_put_node: 100562306a36Sopenharmony_ci of_node_put(phy_node); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci return err; 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(arc_emac_probe); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_civoid arc_emac_remove(struct net_device *ndev) 101262306a36Sopenharmony_ci{ 101362306a36Sopenharmony_ci struct arc_emac_priv *priv = netdev_priv(ndev); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci phy_disconnect(ndev->phydev); 101662306a36Sopenharmony_ci arc_mdio_remove(priv); 101762306a36Sopenharmony_ci unregister_netdev(ndev); 101862306a36Sopenharmony_ci netif_napi_del(&priv->napi); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci if (!IS_ERR(priv->clk)) 102162306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 102262306a36Sopenharmony_ci} 102362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(arc_emac_remove); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ciMODULE_AUTHOR("Alexey Brodkin <abrodkin@synopsys.com>"); 102662306a36Sopenharmony_ciMODULE_DESCRIPTION("ARC EMAC driver"); 102762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1028