162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Altera Triple-Speed Ethernet MAC driver 362306a36Sopenharmony_ci * Copyright (C) 2008-2014 Altera Corporation. All rights reserved 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Contributors: 662306a36Sopenharmony_ci * Dalon Westergreen 762306a36Sopenharmony_ci * Thomas Chou 862306a36Sopenharmony_ci * Ian Abbott 962306a36Sopenharmony_ci * Yuriy Kozlov 1062306a36Sopenharmony_ci * Tobias Klauser 1162306a36Sopenharmony_ci * Andriy Smolskyy 1262306a36Sopenharmony_ci * Roman Bulgakov 1362306a36Sopenharmony_ci * Dmytro Mytarchuk 1462306a36Sopenharmony_ci * Matthew Gerlach 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Original driver contributed by SLS. 1762306a36Sopenharmony_ci * Major updates contributed by GlobalLogic 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/atomic.h> 2162306a36Sopenharmony_ci#include <linux/delay.h> 2262306a36Sopenharmony_ci#include <linux/etherdevice.h> 2362306a36Sopenharmony_ci#include <linux/if_vlan.h> 2462306a36Sopenharmony_ci#include <linux/init.h> 2562306a36Sopenharmony_ci#include <linux/interrupt.h> 2662306a36Sopenharmony_ci#include <linux/io.h> 2762306a36Sopenharmony_ci#include <linux/kernel.h> 2862306a36Sopenharmony_ci#include <linux/module.h> 2962306a36Sopenharmony_ci#include <linux/mii.h> 3062306a36Sopenharmony_ci#include <linux/mdio/mdio-regmap.h> 3162306a36Sopenharmony_ci#include <linux/netdevice.h> 3262306a36Sopenharmony_ci#include <linux/of_device.h> 3362306a36Sopenharmony_ci#include <linux/of_mdio.h> 3462306a36Sopenharmony_ci#include <linux/of_net.h> 3562306a36Sopenharmony_ci#include <linux/of_platform.h> 3662306a36Sopenharmony_ci#include <linux/pcs-lynx.h> 3762306a36Sopenharmony_ci#include <linux/phy.h> 3862306a36Sopenharmony_ci#include <linux/platform_device.h> 3962306a36Sopenharmony_ci#include <linux/regmap.h> 4062306a36Sopenharmony_ci#include <linux/skbuff.h> 4162306a36Sopenharmony_ci#include <asm/cacheflush.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include "altera_utils.h" 4462306a36Sopenharmony_ci#include "altera_tse.h" 4562306a36Sopenharmony_ci#include "altera_sgdma.h" 4662306a36Sopenharmony_ci#include "altera_msgdma.h" 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic atomic_t instance_count = ATOMIC_INIT(~0); 4962306a36Sopenharmony_ci/* Module parameters */ 5062306a36Sopenharmony_cistatic int debug = -1; 5162306a36Sopenharmony_cimodule_param(debug, int, 0644); 5262306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)"); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE | 5562306a36Sopenharmony_ci NETIF_MSG_LINK | NETIF_MSG_IFUP | 5662306a36Sopenharmony_ci NETIF_MSG_IFDOWN); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define RX_DESCRIPTORS 64 5962306a36Sopenharmony_cistatic int dma_rx_num = RX_DESCRIPTORS; 6062306a36Sopenharmony_cimodule_param(dma_rx_num, int, 0644); 6162306a36Sopenharmony_ciMODULE_PARM_DESC(dma_rx_num, "Number of descriptors in the RX list"); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define TX_DESCRIPTORS 64 6462306a36Sopenharmony_cistatic int dma_tx_num = TX_DESCRIPTORS; 6562306a36Sopenharmony_cimodule_param(dma_tx_num, int, 0644); 6662306a36Sopenharmony_ciMODULE_PARM_DESC(dma_tx_num, "Number of descriptors in the TX list"); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define POLL_PHY (-1) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* Make sure DMA buffer size is larger than the max frame size 7262306a36Sopenharmony_ci * plus some alignment offset and a VLAN header. If the max frame size is 7362306a36Sopenharmony_ci * 1518, a VLAN header would be additional 4 bytes and additional 7462306a36Sopenharmony_ci * headroom for alignment is 2 bytes, 2048 is just fine. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci#define ALTERA_RXDMABUFFER_SIZE 2048 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* Allow network stack to resume queuing packets after we've 7962306a36Sopenharmony_ci * finished transmitting at least 1/4 of the packets in the queue. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci#define TSE_TX_THRESH(x) (x->tx_ring_size / 4) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define TXQUEUESTOP_THRESHHOLD 2 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic const struct of_device_id altera_tse_ids[]; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic inline u32 tse_tx_avail(struct altera_tse_private *priv) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci return priv->tx_cons + priv->tx_ring_size - priv->tx_prod - 1; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* MDIO specific functions 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_cistatic int altera_tse_mdio_read(struct mii_bus *bus, int mii_id, int regnum) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct net_device *ndev = bus->priv; 9762306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(ndev); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* set MDIO address */ 10062306a36Sopenharmony_ci csrwr32((mii_id & 0x1f), priv->mac_dev, 10162306a36Sopenharmony_ci tse_csroffs(mdio_phy1_addr)); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* get the data */ 10462306a36Sopenharmony_ci return csrrd32(priv->mac_dev, 10562306a36Sopenharmony_ci tse_csroffs(mdio_phy1) + regnum * 4) & 0xffff; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int altera_tse_mdio_write(struct mii_bus *bus, int mii_id, int regnum, 10962306a36Sopenharmony_ci u16 value) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct net_device *ndev = bus->priv; 11262306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(ndev); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* set MDIO address */ 11562306a36Sopenharmony_ci csrwr32((mii_id & 0x1f), priv->mac_dev, 11662306a36Sopenharmony_ci tse_csroffs(mdio_phy1_addr)); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* write the data */ 11962306a36Sopenharmony_ci csrwr32(value, priv->mac_dev, tse_csroffs(mdio_phy1) + regnum * 4); 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic int altera_tse_mdio_create(struct net_device *dev, unsigned int id) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(dev); 12662306a36Sopenharmony_ci struct device_node *mdio_node = NULL; 12762306a36Sopenharmony_ci struct device_node *child_node = NULL; 12862306a36Sopenharmony_ci struct mii_bus *mdio = NULL; 12962306a36Sopenharmony_ci int ret; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci for_each_child_of_node(priv->device->of_node, child_node) { 13262306a36Sopenharmony_ci if (of_device_is_compatible(child_node, "altr,tse-mdio")) { 13362306a36Sopenharmony_ci mdio_node = child_node; 13462306a36Sopenharmony_ci break; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (mdio_node) { 13962306a36Sopenharmony_ci netdev_dbg(dev, "FOUND MDIO subnode\n"); 14062306a36Sopenharmony_ci } else { 14162306a36Sopenharmony_ci netdev_dbg(dev, "NO MDIO subnode\n"); 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci mdio = mdiobus_alloc(); 14662306a36Sopenharmony_ci if (mdio == NULL) { 14762306a36Sopenharmony_ci netdev_err(dev, "Error allocating MDIO bus\n"); 14862306a36Sopenharmony_ci ret = -ENOMEM; 14962306a36Sopenharmony_ci goto put_node; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci mdio->name = ALTERA_TSE_RESOURCE_NAME; 15362306a36Sopenharmony_ci mdio->read = &altera_tse_mdio_read; 15462306a36Sopenharmony_ci mdio->write = &altera_tse_mdio_write; 15562306a36Sopenharmony_ci snprintf(mdio->id, MII_BUS_ID_SIZE, "%s-%u", mdio->name, id); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci mdio->priv = dev; 15862306a36Sopenharmony_ci mdio->parent = priv->device; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci ret = of_mdiobus_register(mdio, mdio_node); 16162306a36Sopenharmony_ci if (ret != 0) { 16262306a36Sopenharmony_ci netdev_err(dev, "Cannot register MDIO bus %s\n", 16362306a36Sopenharmony_ci mdio->id); 16462306a36Sopenharmony_ci goto out_free_mdio; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci of_node_put(mdio_node); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (netif_msg_drv(priv)) 16962306a36Sopenharmony_ci netdev_info(dev, "MDIO bus %s: created\n", mdio->id); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci priv->mdio = mdio; 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ciout_free_mdio: 17462306a36Sopenharmony_ci mdiobus_free(mdio); 17562306a36Sopenharmony_ci mdio = NULL; 17662306a36Sopenharmony_ciput_node: 17762306a36Sopenharmony_ci of_node_put(mdio_node); 17862306a36Sopenharmony_ci return ret; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void altera_tse_mdio_destroy(struct net_device *dev) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(dev); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (priv->mdio == NULL) 18662306a36Sopenharmony_ci return; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (netif_msg_drv(priv)) 18962306a36Sopenharmony_ci netdev_info(dev, "MDIO bus %s: removed\n", 19062306a36Sopenharmony_ci priv->mdio->id); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci mdiobus_unregister(priv->mdio); 19362306a36Sopenharmony_ci mdiobus_free(priv->mdio); 19462306a36Sopenharmony_ci priv->mdio = NULL; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int tse_init_rx_buffer(struct altera_tse_private *priv, 19862306a36Sopenharmony_ci struct tse_buffer *rxbuffer, int len) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci rxbuffer->skb = netdev_alloc_skb_ip_align(priv->dev, len); 20162306a36Sopenharmony_ci if (!rxbuffer->skb) 20262306a36Sopenharmony_ci return -ENOMEM; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci rxbuffer->dma_addr = dma_map_single(priv->device, rxbuffer->skb->data, 20562306a36Sopenharmony_ci len, 20662306a36Sopenharmony_ci DMA_FROM_DEVICE); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (dma_mapping_error(priv->device, rxbuffer->dma_addr)) { 20962306a36Sopenharmony_ci netdev_err(priv->dev, "%s: DMA mapping error\n", __func__); 21062306a36Sopenharmony_ci dev_kfree_skb_any(rxbuffer->skb); 21162306a36Sopenharmony_ci return -EINVAL; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci rxbuffer->dma_addr &= (dma_addr_t)~3; 21462306a36Sopenharmony_ci rxbuffer->len = len; 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void tse_free_rx_buffer(struct altera_tse_private *priv, 21962306a36Sopenharmony_ci struct tse_buffer *rxbuffer) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci dma_addr_t dma_addr = rxbuffer->dma_addr; 22262306a36Sopenharmony_ci struct sk_buff *skb = rxbuffer->skb; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (skb != NULL) { 22562306a36Sopenharmony_ci if (dma_addr) 22662306a36Sopenharmony_ci dma_unmap_single(priv->device, dma_addr, 22762306a36Sopenharmony_ci rxbuffer->len, 22862306a36Sopenharmony_ci DMA_FROM_DEVICE); 22962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 23062306a36Sopenharmony_ci rxbuffer->skb = NULL; 23162306a36Sopenharmony_ci rxbuffer->dma_addr = 0; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* Unmap and free Tx buffer resources 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_cistatic void tse_free_tx_buffer(struct altera_tse_private *priv, 23862306a36Sopenharmony_ci struct tse_buffer *buffer) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci if (buffer->dma_addr) { 24162306a36Sopenharmony_ci if (buffer->mapped_as_page) 24262306a36Sopenharmony_ci dma_unmap_page(priv->device, buffer->dma_addr, 24362306a36Sopenharmony_ci buffer->len, DMA_TO_DEVICE); 24462306a36Sopenharmony_ci else 24562306a36Sopenharmony_ci dma_unmap_single(priv->device, buffer->dma_addr, 24662306a36Sopenharmony_ci buffer->len, DMA_TO_DEVICE); 24762306a36Sopenharmony_ci buffer->dma_addr = 0; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci if (buffer->skb) { 25062306a36Sopenharmony_ci dev_kfree_skb_any(buffer->skb); 25162306a36Sopenharmony_ci buffer->skb = NULL; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic int alloc_init_skbufs(struct altera_tse_private *priv) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci unsigned int rx_descs = priv->rx_ring_size; 25862306a36Sopenharmony_ci unsigned int tx_descs = priv->tx_ring_size; 25962306a36Sopenharmony_ci int ret = -ENOMEM; 26062306a36Sopenharmony_ci int i; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* Create Rx ring buffer */ 26362306a36Sopenharmony_ci priv->rx_ring = kcalloc(rx_descs, sizeof(struct tse_buffer), 26462306a36Sopenharmony_ci GFP_KERNEL); 26562306a36Sopenharmony_ci if (!priv->rx_ring) 26662306a36Sopenharmony_ci goto err_rx_ring; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* Create Tx ring buffer */ 26962306a36Sopenharmony_ci priv->tx_ring = kcalloc(tx_descs, sizeof(struct tse_buffer), 27062306a36Sopenharmony_ci GFP_KERNEL); 27162306a36Sopenharmony_ci if (!priv->tx_ring) 27262306a36Sopenharmony_ci goto err_tx_ring; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci priv->tx_cons = 0; 27562306a36Sopenharmony_ci priv->tx_prod = 0; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* Init Rx ring */ 27862306a36Sopenharmony_ci for (i = 0; i < rx_descs; i++) { 27962306a36Sopenharmony_ci ret = tse_init_rx_buffer(priv, &priv->rx_ring[i], 28062306a36Sopenharmony_ci priv->rx_dma_buf_sz); 28162306a36Sopenharmony_ci if (ret) 28262306a36Sopenharmony_ci goto err_init_rx_buffers; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci priv->rx_cons = 0; 28662306a36Sopenharmony_ci priv->rx_prod = 0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_cierr_init_rx_buffers: 29062306a36Sopenharmony_ci while (--i >= 0) 29162306a36Sopenharmony_ci tse_free_rx_buffer(priv, &priv->rx_ring[i]); 29262306a36Sopenharmony_ci kfree(priv->tx_ring); 29362306a36Sopenharmony_cierr_tx_ring: 29462306a36Sopenharmony_ci kfree(priv->rx_ring); 29562306a36Sopenharmony_cierr_rx_ring: 29662306a36Sopenharmony_ci return ret; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic void free_skbufs(struct net_device *dev) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(dev); 30262306a36Sopenharmony_ci unsigned int rx_descs = priv->rx_ring_size; 30362306a36Sopenharmony_ci unsigned int tx_descs = priv->tx_ring_size; 30462306a36Sopenharmony_ci int i; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* Release the DMA TX/RX socket buffers */ 30762306a36Sopenharmony_ci for (i = 0; i < rx_descs; i++) 30862306a36Sopenharmony_ci tse_free_rx_buffer(priv, &priv->rx_ring[i]); 30962306a36Sopenharmony_ci for (i = 0; i < tx_descs; i++) 31062306a36Sopenharmony_ci tse_free_tx_buffer(priv, &priv->tx_ring[i]); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci kfree(priv->tx_ring); 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/* Reallocate the skb for the reception process 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_cistatic inline void tse_rx_refill(struct altera_tse_private *priv) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci unsigned int rxsize = priv->rx_ring_size; 32162306a36Sopenharmony_ci unsigned int entry; 32262306a36Sopenharmony_ci int ret; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci for (; priv->rx_cons - priv->rx_prod > 0; 32562306a36Sopenharmony_ci priv->rx_prod++) { 32662306a36Sopenharmony_ci entry = priv->rx_prod % rxsize; 32762306a36Sopenharmony_ci if (likely(priv->rx_ring[entry].skb == NULL)) { 32862306a36Sopenharmony_ci ret = tse_init_rx_buffer(priv, &priv->rx_ring[entry], 32962306a36Sopenharmony_ci priv->rx_dma_buf_sz); 33062306a36Sopenharmony_ci if (unlikely(ret != 0)) 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci priv->dmaops->add_rx_desc(priv, &priv->rx_ring[entry]); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci/* Pull out the VLAN tag and fix up the packet 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_cistatic inline void tse_rx_vlan(struct net_device *dev, struct sk_buff *skb) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct ethhdr *eth_hdr; 34262306a36Sopenharmony_ci u16 vid; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) && 34562306a36Sopenharmony_ci !__vlan_get_tag(skb, &vid)) { 34662306a36Sopenharmony_ci eth_hdr = (struct ethhdr *)skb->data; 34762306a36Sopenharmony_ci memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2); 34862306a36Sopenharmony_ci skb_pull(skb, VLAN_HLEN); 34962306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci/* Receive a packet: retrieve and pass over to upper levels 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_cistatic int tse_rx(struct altera_tse_private *priv, int limit) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci unsigned int entry = priv->rx_cons % priv->rx_ring_size; 35862306a36Sopenharmony_ci unsigned int next_entry; 35962306a36Sopenharmony_ci unsigned int count = 0; 36062306a36Sopenharmony_ci struct sk_buff *skb; 36162306a36Sopenharmony_ci u32 rxstatus; 36262306a36Sopenharmony_ci u16 pktlength; 36362306a36Sopenharmony_ci u16 pktstatus; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* Check for count < limit first as get_rx_status is changing 36662306a36Sopenharmony_ci * the response-fifo so we must process the next packet 36762306a36Sopenharmony_ci * after calling get_rx_status if a response is pending. 36862306a36Sopenharmony_ci * (reading the last byte of the response pops the value from the fifo.) 36962306a36Sopenharmony_ci */ 37062306a36Sopenharmony_ci while ((count < limit) && 37162306a36Sopenharmony_ci ((rxstatus = priv->dmaops->get_rx_status(priv)) != 0)) { 37262306a36Sopenharmony_ci pktstatus = rxstatus >> 16; 37362306a36Sopenharmony_ci pktlength = rxstatus & 0xffff; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if ((pktstatus & 0xFF) || (pktlength == 0)) 37662306a36Sopenharmony_ci netdev_err(priv->dev, 37762306a36Sopenharmony_ci "RCV pktstatus %08X pktlength %08X\n", 37862306a36Sopenharmony_ci pktstatus, pktlength); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* DMA transfer from TSE starts with 2 additional bytes for 38162306a36Sopenharmony_ci * IP payload alignment. Status returned by get_rx_status() 38262306a36Sopenharmony_ci * contains DMA transfer length. Packet is 2 bytes shorter. 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_ci pktlength -= 2; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci count++; 38762306a36Sopenharmony_ci next_entry = (++priv->rx_cons) % priv->rx_ring_size; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci skb = priv->rx_ring[entry].skb; 39062306a36Sopenharmony_ci if (unlikely(!skb)) { 39162306a36Sopenharmony_ci netdev_err(priv->dev, 39262306a36Sopenharmony_ci "%s: Inconsistent Rx descriptor chain\n", 39362306a36Sopenharmony_ci __func__); 39462306a36Sopenharmony_ci priv->dev->stats.rx_dropped++; 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci priv->rx_ring[entry].skb = NULL; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci skb_put(skb, pktlength); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci dma_unmap_single(priv->device, priv->rx_ring[entry].dma_addr, 40262306a36Sopenharmony_ci priv->rx_ring[entry].len, DMA_FROM_DEVICE); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (netif_msg_pktdata(priv)) { 40562306a36Sopenharmony_ci netdev_info(priv->dev, "frame received %d bytes\n", 40662306a36Sopenharmony_ci pktlength); 40762306a36Sopenharmony_ci print_hex_dump(KERN_ERR, "data: ", DUMP_PREFIX_OFFSET, 40862306a36Sopenharmony_ci 16, 1, skb->data, pktlength, true); 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci tse_rx_vlan(priv->dev, skb); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, priv->dev); 41462306a36Sopenharmony_ci skb_checksum_none_assert(skb); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci napi_gro_receive(&priv->napi, skb); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci priv->dev->stats.rx_packets++; 41962306a36Sopenharmony_ci priv->dev->stats.rx_bytes += pktlength; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci entry = next_entry; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci tse_rx_refill(priv); 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return count; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/* Reclaim resources after transmission completes 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_cistatic int tse_tx_complete(struct altera_tse_private *priv) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci unsigned int txsize = priv->tx_ring_size; 43462306a36Sopenharmony_ci struct tse_buffer *tx_buff; 43562306a36Sopenharmony_ci unsigned int entry; 43662306a36Sopenharmony_ci int txcomplete = 0; 43762306a36Sopenharmony_ci u32 ready; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci spin_lock(&priv->tx_lock); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci ready = priv->dmaops->tx_completions(priv); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* Free sent buffers */ 44462306a36Sopenharmony_ci while (ready && (priv->tx_cons != priv->tx_prod)) { 44562306a36Sopenharmony_ci entry = priv->tx_cons % txsize; 44662306a36Sopenharmony_ci tx_buff = &priv->tx_ring[entry]; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (netif_msg_tx_done(priv)) 44962306a36Sopenharmony_ci netdev_dbg(priv->dev, "%s: curr %d, dirty %d\n", 45062306a36Sopenharmony_ci __func__, priv->tx_prod, priv->tx_cons); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (likely(tx_buff->skb)) 45362306a36Sopenharmony_ci priv->dev->stats.tx_packets++; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci tse_free_tx_buffer(priv, tx_buff); 45662306a36Sopenharmony_ci priv->tx_cons++; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci txcomplete++; 45962306a36Sopenharmony_ci ready--; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (unlikely(netif_queue_stopped(priv->dev) && 46362306a36Sopenharmony_ci tse_tx_avail(priv) > TSE_TX_THRESH(priv))) { 46462306a36Sopenharmony_ci if (netif_queue_stopped(priv->dev) && 46562306a36Sopenharmony_ci tse_tx_avail(priv) > TSE_TX_THRESH(priv)) { 46662306a36Sopenharmony_ci if (netif_msg_tx_done(priv)) 46762306a36Sopenharmony_ci netdev_dbg(priv->dev, "%s: restart transmit\n", 46862306a36Sopenharmony_ci __func__); 46962306a36Sopenharmony_ci netif_wake_queue(priv->dev); 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci spin_unlock(&priv->tx_lock); 47462306a36Sopenharmony_ci return txcomplete; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/* NAPI polling function 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_cistatic int tse_poll(struct napi_struct *napi, int budget) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct altera_tse_private *priv = 48262306a36Sopenharmony_ci container_of(napi, struct altera_tse_private, napi); 48362306a36Sopenharmony_ci unsigned long int flags; 48462306a36Sopenharmony_ci int rxcomplete = 0; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci tse_tx_complete(priv); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci rxcomplete = tse_rx(priv, budget); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (rxcomplete < budget) { 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci napi_complete_done(napi, rxcomplete); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci netdev_dbg(priv->dev, 49562306a36Sopenharmony_ci "NAPI Complete, did %d packets with budget %d\n", 49662306a36Sopenharmony_ci rxcomplete, budget); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci spin_lock_irqsave(&priv->rxdma_irq_lock, flags); 49962306a36Sopenharmony_ci priv->dmaops->enable_rxirq(priv); 50062306a36Sopenharmony_ci priv->dmaops->enable_txirq(priv); 50162306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags); 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci return rxcomplete; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci/* DMA TX & RX FIFO interrupt routing 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_cistatic irqreturn_t altera_isr(int irq, void *dev_id) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct net_device *dev = dev_id; 51162306a36Sopenharmony_ci struct altera_tse_private *priv; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (unlikely(!dev)) { 51462306a36Sopenharmony_ci pr_err("%s: invalid dev pointer\n", __func__); 51562306a36Sopenharmony_ci return IRQ_NONE; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci priv = netdev_priv(dev); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci spin_lock(&priv->rxdma_irq_lock); 52062306a36Sopenharmony_ci /* reset IRQs */ 52162306a36Sopenharmony_ci priv->dmaops->clear_rxirq(priv); 52262306a36Sopenharmony_ci priv->dmaops->clear_txirq(priv); 52362306a36Sopenharmony_ci spin_unlock(&priv->rxdma_irq_lock); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (likely(napi_schedule_prep(&priv->napi))) { 52662306a36Sopenharmony_ci spin_lock(&priv->rxdma_irq_lock); 52762306a36Sopenharmony_ci priv->dmaops->disable_rxirq(priv); 52862306a36Sopenharmony_ci priv->dmaops->disable_txirq(priv); 52962306a36Sopenharmony_ci spin_unlock(&priv->rxdma_irq_lock); 53062306a36Sopenharmony_ci __napi_schedule(&priv->napi); 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return IRQ_HANDLED; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci/* Transmit a packet (called by the kernel). Dispatches 53862306a36Sopenharmony_ci * either the SGDMA method for transmitting or the 53962306a36Sopenharmony_ci * MSGDMA method, assumes no scatter/gather support, 54062306a36Sopenharmony_ci * implying an assumption that there's only one 54162306a36Sopenharmony_ci * physically contiguous fragment starting at 54262306a36Sopenharmony_ci * skb->data, for length of skb_headlen(skb). 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_cistatic netdev_tx_t tse_start_xmit(struct sk_buff *skb, struct net_device *dev) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(dev); 54762306a36Sopenharmony_ci unsigned int nopaged_len = skb_headlen(skb); 54862306a36Sopenharmony_ci unsigned int txsize = priv->tx_ring_size; 54962306a36Sopenharmony_ci int nfrags = skb_shinfo(skb)->nr_frags; 55062306a36Sopenharmony_ci struct tse_buffer *buffer = NULL; 55162306a36Sopenharmony_ci netdev_tx_t ret = NETDEV_TX_OK; 55262306a36Sopenharmony_ci dma_addr_t dma_addr; 55362306a36Sopenharmony_ci unsigned int entry; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci spin_lock_bh(&priv->tx_lock); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (unlikely(tse_tx_avail(priv) < nfrags + 1)) { 55862306a36Sopenharmony_ci if (!netif_queue_stopped(dev)) { 55962306a36Sopenharmony_ci netif_stop_queue(dev); 56062306a36Sopenharmony_ci /* This is a hard error, log it. */ 56162306a36Sopenharmony_ci netdev_err(priv->dev, 56262306a36Sopenharmony_ci "%s: Tx list full when queue awake\n", 56362306a36Sopenharmony_ci __func__); 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci ret = NETDEV_TX_BUSY; 56662306a36Sopenharmony_ci goto out; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* Map the first skb fragment */ 57062306a36Sopenharmony_ci entry = priv->tx_prod % txsize; 57162306a36Sopenharmony_ci buffer = &priv->tx_ring[entry]; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci dma_addr = dma_map_single(priv->device, skb->data, nopaged_len, 57462306a36Sopenharmony_ci DMA_TO_DEVICE); 57562306a36Sopenharmony_ci if (dma_mapping_error(priv->device, dma_addr)) { 57662306a36Sopenharmony_ci netdev_err(priv->dev, "%s: DMA mapping error\n", __func__); 57762306a36Sopenharmony_ci ret = NETDEV_TX_OK; 57862306a36Sopenharmony_ci goto out; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci buffer->skb = skb; 58262306a36Sopenharmony_ci buffer->dma_addr = dma_addr; 58362306a36Sopenharmony_ci buffer->len = nopaged_len; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci priv->dmaops->tx_buffer(priv, buffer); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci skb_tx_timestamp(skb); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci priv->tx_prod++; 59062306a36Sopenharmony_ci dev->stats.tx_bytes += skb->len; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (unlikely(tse_tx_avail(priv) <= TXQUEUESTOP_THRESHHOLD)) { 59362306a36Sopenharmony_ci if (netif_msg_hw(priv)) 59462306a36Sopenharmony_ci netdev_dbg(priv->dev, "%s: stop transmitted packets\n", 59562306a36Sopenharmony_ci __func__); 59662306a36Sopenharmony_ci netif_stop_queue(dev); 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ciout: 60062306a36Sopenharmony_ci spin_unlock_bh(&priv->tx_lock); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci return ret; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic int altera_tse_phy_get_addr_mdio_create(struct net_device *dev) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(dev); 60862306a36Sopenharmony_ci struct device_node *np = priv->device->of_node; 60962306a36Sopenharmony_ci int ret; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci ret = of_get_phy_mode(np, &priv->phy_iface); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* Avoid get phy addr and create mdio if no phy is present */ 61462306a36Sopenharmony_ci if (ret) 61562306a36Sopenharmony_ci return 0; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* try to get PHY address from device tree, use PHY autodetection if 61862306a36Sopenharmony_ci * no valid address is given 61962306a36Sopenharmony_ci */ 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (of_property_read_u32(priv->device->of_node, "phy-addr", 62262306a36Sopenharmony_ci &priv->phy_addr)) { 62362306a36Sopenharmony_ci priv->phy_addr = POLL_PHY; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (!((priv->phy_addr == POLL_PHY) || 62762306a36Sopenharmony_ci ((priv->phy_addr >= 0) && (priv->phy_addr < PHY_MAX_ADDR)))) { 62862306a36Sopenharmony_ci netdev_err(dev, "invalid phy-addr specified %d\n", 62962306a36Sopenharmony_ci priv->phy_addr); 63062306a36Sopenharmony_ci return -ENODEV; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* Create/attach to MDIO bus */ 63462306a36Sopenharmony_ci ret = altera_tse_mdio_create(dev, 63562306a36Sopenharmony_ci atomic_add_return(1, &instance_count)); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (ret) 63862306a36Sopenharmony_ci return -ENODEV; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci return 0; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic void tse_update_mac_addr(struct altera_tse_private *priv, const u8 *addr) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci u32 msb; 64662306a36Sopenharmony_ci u32 lsb; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci msb = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; 64962306a36Sopenharmony_ci lsb = ((addr[5] << 8) | addr[4]) & 0xffff; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Set primary MAC address */ 65262306a36Sopenharmony_ci csrwr32(msb, priv->mac_dev, tse_csroffs(mac_addr_0)); 65362306a36Sopenharmony_ci csrwr32(lsb, priv->mac_dev, tse_csroffs(mac_addr_1)); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci/* MAC software reset. 65762306a36Sopenharmony_ci * When reset is triggered, the MAC function completes the current 65862306a36Sopenharmony_ci * transmission or reception, and subsequently disables the transmit and 65962306a36Sopenharmony_ci * receive logic, flushes the receive FIFO buffer, and resets the statistics 66062306a36Sopenharmony_ci * counters. 66162306a36Sopenharmony_ci */ 66262306a36Sopenharmony_cistatic int reset_mac(struct altera_tse_private *priv) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci int counter; 66562306a36Sopenharmony_ci u32 dat; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci dat = csrrd32(priv->mac_dev, tse_csroffs(command_config)); 66862306a36Sopenharmony_ci dat &= ~(MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA); 66962306a36Sopenharmony_ci dat |= MAC_CMDCFG_SW_RESET | MAC_CMDCFG_CNT_RESET; 67062306a36Sopenharmony_ci csrwr32(dat, priv->mac_dev, tse_csroffs(command_config)); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci counter = 0; 67362306a36Sopenharmony_ci while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) { 67462306a36Sopenharmony_ci if (tse_bit_is_clear(priv->mac_dev, tse_csroffs(command_config), 67562306a36Sopenharmony_ci MAC_CMDCFG_SW_RESET)) 67662306a36Sopenharmony_ci break; 67762306a36Sopenharmony_ci udelay(1); 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) { 68162306a36Sopenharmony_ci dat = csrrd32(priv->mac_dev, tse_csroffs(command_config)); 68262306a36Sopenharmony_ci dat &= ~MAC_CMDCFG_SW_RESET; 68362306a36Sopenharmony_ci csrwr32(dat, priv->mac_dev, tse_csroffs(command_config)); 68462306a36Sopenharmony_ci return -1; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci return 0; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci/* Initialize MAC core registers 69062306a36Sopenharmony_ci*/ 69162306a36Sopenharmony_cistatic int init_mac(struct altera_tse_private *priv) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci unsigned int cmd = 0; 69462306a36Sopenharmony_ci u32 frm_length; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* Setup Rx FIFO */ 69762306a36Sopenharmony_ci csrwr32(priv->rx_fifo_depth - ALTERA_TSE_RX_SECTION_EMPTY, 69862306a36Sopenharmony_ci priv->mac_dev, tse_csroffs(rx_section_empty)); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci csrwr32(ALTERA_TSE_RX_SECTION_FULL, priv->mac_dev, 70162306a36Sopenharmony_ci tse_csroffs(rx_section_full)); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci csrwr32(ALTERA_TSE_RX_ALMOST_EMPTY, priv->mac_dev, 70462306a36Sopenharmony_ci tse_csroffs(rx_almost_empty)); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci csrwr32(ALTERA_TSE_RX_ALMOST_FULL, priv->mac_dev, 70762306a36Sopenharmony_ci tse_csroffs(rx_almost_full)); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci /* Setup Tx FIFO */ 71062306a36Sopenharmony_ci csrwr32(priv->tx_fifo_depth - ALTERA_TSE_TX_SECTION_EMPTY, 71162306a36Sopenharmony_ci priv->mac_dev, tse_csroffs(tx_section_empty)); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci csrwr32(ALTERA_TSE_TX_SECTION_FULL, priv->mac_dev, 71462306a36Sopenharmony_ci tse_csroffs(tx_section_full)); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci csrwr32(ALTERA_TSE_TX_ALMOST_EMPTY, priv->mac_dev, 71762306a36Sopenharmony_ci tse_csroffs(tx_almost_empty)); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci csrwr32(ALTERA_TSE_TX_ALMOST_FULL, priv->mac_dev, 72062306a36Sopenharmony_ci tse_csroffs(tx_almost_full)); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* MAC Address Configuration */ 72362306a36Sopenharmony_ci tse_update_mac_addr(priv, priv->dev->dev_addr); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* MAC Function Configuration */ 72662306a36Sopenharmony_ci frm_length = ETH_HLEN + priv->dev->mtu + ETH_FCS_LEN; 72762306a36Sopenharmony_ci csrwr32(frm_length, priv->mac_dev, tse_csroffs(frm_length)); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci csrwr32(ALTERA_TSE_TX_IPG_LENGTH, priv->mac_dev, 73062306a36Sopenharmony_ci tse_csroffs(tx_ipg_length)); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* Disable RX/TX shift 16 for alignment of all received frames on 16-bit 73362306a36Sopenharmony_ci * start address 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_ci tse_set_bit(priv->mac_dev, tse_csroffs(rx_cmd_stat), 73662306a36Sopenharmony_ci ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci tse_clear_bit(priv->mac_dev, tse_csroffs(tx_cmd_stat), 73962306a36Sopenharmony_ci ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 | 74062306a36Sopenharmony_ci ALTERA_TSE_TX_CMD_STAT_OMIT_CRC); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* Set the MAC options */ 74362306a36Sopenharmony_ci cmd = csrrd32(priv->mac_dev, tse_csroffs(command_config)); 74462306a36Sopenharmony_ci cmd &= ~MAC_CMDCFG_PAD_EN; /* No padding Removal on Receive */ 74562306a36Sopenharmony_ci cmd &= ~MAC_CMDCFG_CRC_FWD; /* CRC Removal */ 74662306a36Sopenharmony_ci cmd |= MAC_CMDCFG_RX_ERR_DISC; /* Automatically discard frames 74762306a36Sopenharmony_ci * with CRC errors 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_ci cmd |= MAC_CMDCFG_CNTL_FRM_ENA; 75062306a36Sopenharmony_ci cmd &= ~MAC_CMDCFG_TX_ENA; 75162306a36Sopenharmony_ci cmd &= ~MAC_CMDCFG_RX_ENA; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* Default speed and duplex setting, full/100 */ 75462306a36Sopenharmony_ci cmd &= ~MAC_CMDCFG_HD_ENA; 75562306a36Sopenharmony_ci cmd &= ~MAC_CMDCFG_ETH_SPEED; 75662306a36Sopenharmony_ci cmd &= ~MAC_CMDCFG_ENA_10; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci csrwr32(cmd, priv->mac_dev, tse_csroffs(command_config)); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci csrwr32(ALTERA_TSE_PAUSE_QUANTA, priv->mac_dev, 76162306a36Sopenharmony_ci tse_csroffs(pause_quanta)); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (netif_msg_hw(priv)) 76462306a36Sopenharmony_ci dev_dbg(priv->device, 76562306a36Sopenharmony_ci "MAC post-initialization: CMD_CONFIG = 0x%08x\n", cmd); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci return 0; 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci/* Start/stop MAC transmission logic 77162306a36Sopenharmony_ci */ 77262306a36Sopenharmony_cistatic void tse_set_mac(struct altera_tse_private *priv, bool enable) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci u32 value = csrrd32(priv->mac_dev, tse_csroffs(command_config)); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (enable) 77762306a36Sopenharmony_ci value |= MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA; 77862306a36Sopenharmony_ci else 77962306a36Sopenharmony_ci value &= ~(MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci csrwr32(value, priv->mac_dev, tse_csroffs(command_config)); 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci/* Change the MTU 78562306a36Sopenharmony_ci */ 78662306a36Sopenharmony_cistatic int tse_change_mtu(struct net_device *dev, int new_mtu) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci if (netif_running(dev)) { 78962306a36Sopenharmony_ci netdev_err(dev, "must be stopped to change its MTU\n"); 79062306a36Sopenharmony_ci return -EBUSY; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci dev->mtu = new_mtu; 79462306a36Sopenharmony_ci netdev_update_features(dev); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci return 0; 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic void altera_tse_set_mcfilter(struct net_device *dev) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(dev); 80262306a36Sopenharmony_ci struct netdev_hw_addr *ha; 80362306a36Sopenharmony_ci int i; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* clear the hash filter */ 80662306a36Sopenharmony_ci for (i = 0; i < 64; i++) 80762306a36Sopenharmony_ci csrwr32(0, priv->mac_dev, tse_csroffs(hash_table) + i * 4); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 81062306a36Sopenharmony_ci unsigned int hash = 0; 81162306a36Sopenharmony_ci int mac_octet; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci for (mac_octet = 5; mac_octet >= 0; mac_octet--) { 81462306a36Sopenharmony_ci unsigned char xor_bit = 0; 81562306a36Sopenharmony_ci unsigned char octet = ha->addr[mac_octet]; 81662306a36Sopenharmony_ci unsigned int bitshift; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci for (bitshift = 0; bitshift < 8; bitshift++) 81962306a36Sopenharmony_ci xor_bit ^= ((octet >> bitshift) & 0x01); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci hash = (hash << 1) | xor_bit; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci csrwr32(1, priv->mac_dev, tse_csroffs(hash_table) + hash * 4); 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic void altera_tse_set_mcfilterall(struct net_device *dev) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(dev); 83162306a36Sopenharmony_ci int i; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* set the hash filter */ 83462306a36Sopenharmony_ci for (i = 0; i < 64; i++) 83562306a36Sopenharmony_ci csrwr32(1, priv->mac_dev, tse_csroffs(hash_table) + i * 4); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci/* Set or clear the multicast filter for this adapter 83962306a36Sopenharmony_ci */ 84062306a36Sopenharmony_cistatic void tse_set_rx_mode_hashfilter(struct net_device *dev) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(dev); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci spin_lock(&priv->mac_cfg_lock); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) 84762306a36Sopenharmony_ci tse_set_bit(priv->mac_dev, tse_csroffs(command_config), 84862306a36Sopenharmony_ci MAC_CMDCFG_PROMIS_EN); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (dev->flags & IFF_ALLMULTI) 85162306a36Sopenharmony_ci altera_tse_set_mcfilterall(dev); 85262306a36Sopenharmony_ci else 85362306a36Sopenharmony_ci altera_tse_set_mcfilter(dev); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci spin_unlock(&priv->mac_cfg_lock); 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci/* Set or clear the multicast filter for this adapter 85962306a36Sopenharmony_ci */ 86062306a36Sopenharmony_cistatic void tse_set_rx_mode(struct net_device *dev) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(dev); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci spin_lock(&priv->mac_cfg_lock); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || 86762306a36Sopenharmony_ci !netdev_mc_empty(dev) || !netdev_uc_empty(dev)) 86862306a36Sopenharmony_ci tse_set_bit(priv->mac_dev, tse_csroffs(command_config), 86962306a36Sopenharmony_ci MAC_CMDCFG_PROMIS_EN); 87062306a36Sopenharmony_ci else 87162306a36Sopenharmony_ci tse_clear_bit(priv->mac_dev, tse_csroffs(command_config), 87262306a36Sopenharmony_ci MAC_CMDCFG_PROMIS_EN); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci spin_unlock(&priv->mac_cfg_lock); 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci/* Open and initialize the interface 87862306a36Sopenharmony_ci */ 87962306a36Sopenharmony_cistatic int tse_open(struct net_device *dev) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(dev); 88262306a36Sopenharmony_ci unsigned long flags; 88362306a36Sopenharmony_ci int ret = 0; 88462306a36Sopenharmony_ci int i; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* Reset and configure TSE MAC and probe associated PHY */ 88762306a36Sopenharmony_ci ret = priv->dmaops->init_dma(priv); 88862306a36Sopenharmony_ci if (ret != 0) { 88962306a36Sopenharmony_ci netdev_err(dev, "Cannot initialize DMA\n"); 89062306a36Sopenharmony_ci goto phy_error; 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (netif_msg_ifup(priv)) 89462306a36Sopenharmony_ci netdev_warn(dev, "device MAC address %pM\n", 89562306a36Sopenharmony_ci dev->dev_addr); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if ((priv->revision < 0xd00) || (priv->revision > 0xe00)) 89862306a36Sopenharmony_ci netdev_warn(dev, "TSE revision %x\n", priv->revision); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci spin_lock(&priv->mac_cfg_lock); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci ret = reset_mac(priv); 90362306a36Sopenharmony_ci /* Note that reset_mac will fail if the clocks are gated by the PHY 90462306a36Sopenharmony_ci * due to the PHY being put into isolation or power down mode. 90562306a36Sopenharmony_ci * This is not an error if reset fails due to no clock. 90662306a36Sopenharmony_ci */ 90762306a36Sopenharmony_ci if (ret) 90862306a36Sopenharmony_ci netdev_dbg(dev, "Cannot reset MAC core (error: %d)\n", ret); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci ret = init_mac(priv); 91162306a36Sopenharmony_ci spin_unlock(&priv->mac_cfg_lock); 91262306a36Sopenharmony_ci if (ret) { 91362306a36Sopenharmony_ci netdev_err(dev, "Cannot init MAC core (error: %d)\n", ret); 91462306a36Sopenharmony_ci goto alloc_skbuf_error; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci priv->dmaops->reset_dma(priv); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci /* Create and initialize the TX/RX descriptors chains. */ 92062306a36Sopenharmony_ci priv->rx_ring_size = dma_rx_num; 92162306a36Sopenharmony_ci priv->tx_ring_size = dma_tx_num; 92262306a36Sopenharmony_ci ret = alloc_init_skbufs(priv); 92362306a36Sopenharmony_ci if (ret) { 92462306a36Sopenharmony_ci netdev_err(dev, "DMA descriptors initialization failed\n"); 92562306a36Sopenharmony_ci goto alloc_skbuf_error; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* Register RX interrupt */ 93062306a36Sopenharmony_ci ret = request_irq(priv->rx_irq, altera_isr, IRQF_SHARED, 93162306a36Sopenharmony_ci dev->name, dev); 93262306a36Sopenharmony_ci if (ret) { 93362306a36Sopenharmony_ci netdev_err(dev, "Unable to register RX interrupt %d\n", 93462306a36Sopenharmony_ci priv->rx_irq); 93562306a36Sopenharmony_ci goto init_error; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* Register TX interrupt */ 93962306a36Sopenharmony_ci ret = request_irq(priv->tx_irq, altera_isr, IRQF_SHARED, 94062306a36Sopenharmony_ci dev->name, dev); 94162306a36Sopenharmony_ci if (ret) { 94262306a36Sopenharmony_ci netdev_err(dev, "Unable to register TX interrupt %d\n", 94362306a36Sopenharmony_ci priv->tx_irq); 94462306a36Sopenharmony_ci goto tx_request_irq_error; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* Enable DMA interrupts */ 94862306a36Sopenharmony_ci spin_lock_irqsave(&priv->rxdma_irq_lock, flags); 94962306a36Sopenharmony_ci priv->dmaops->enable_rxirq(priv); 95062306a36Sopenharmony_ci priv->dmaops->enable_txirq(priv); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci /* Setup RX descriptor chain */ 95362306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_size; i++) 95462306a36Sopenharmony_ci priv->dmaops->add_rx_desc(priv, &priv->rx_ring[i]); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci ret = phylink_of_phy_connect(priv->phylink, priv->device->of_node, 0); 95962306a36Sopenharmony_ci if (ret) { 96062306a36Sopenharmony_ci netdev_err(dev, "could not connect phylink (%d)\n", ret); 96162306a36Sopenharmony_ci goto tx_request_irq_error; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci phylink_start(priv->phylink); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci napi_enable(&priv->napi); 96662306a36Sopenharmony_ci netif_start_queue(dev); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci priv->dmaops->start_rxdma(priv); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* Start MAC Rx/Tx */ 97162306a36Sopenharmony_ci spin_lock(&priv->mac_cfg_lock); 97262306a36Sopenharmony_ci tse_set_mac(priv, true); 97362306a36Sopenharmony_ci spin_unlock(&priv->mac_cfg_lock); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci return 0; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_citx_request_irq_error: 97862306a36Sopenharmony_ci free_irq(priv->rx_irq, dev); 97962306a36Sopenharmony_ciinit_error: 98062306a36Sopenharmony_ci free_skbufs(dev); 98162306a36Sopenharmony_cialloc_skbuf_error: 98262306a36Sopenharmony_ciphy_error: 98362306a36Sopenharmony_ci return ret; 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci/* Stop TSE MAC interface and put the device in an inactive state 98762306a36Sopenharmony_ci */ 98862306a36Sopenharmony_cistatic int tse_shutdown(struct net_device *dev) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(dev); 99162306a36Sopenharmony_ci unsigned long int flags; 99262306a36Sopenharmony_ci int ret; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci phylink_stop(priv->phylink); 99562306a36Sopenharmony_ci phylink_disconnect_phy(priv->phylink); 99662306a36Sopenharmony_ci netif_stop_queue(dev); 99762306a36Sopenharmony_ci napi_disable(&priv->napi); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* Disable DMA interrupts */ 100062306a36Sopenharmony_ci spin_lock_irqsave(&priv->rxdma_irq_lock, flags); 100162306a36Sopenharmony_ci priv->dmaops->disable_rxirq(priv); 100262306a36Sopenharmony_ci priv->dmaops->disable_txirq(priv); 100362306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* Free the IRQ lines */ 100662306a36Sopenharmony_ci free_irq(priv->rx_irq, dev); 100762306a36Sopenharmony_ci free_irq(priv->tx_irq, dev); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* disable and reset the MAC, empties fifo */ 101062306a36Sopenharmony_ci spin_lock(&priv->mac_cfg_lock); 101162306a36Sopenharmony_ci spin_lock(&priv->tx_lock); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci ret = reset_mac(priv); 101462306a36Sopenharmony_ci /* Note that reset_mac will fail if the clocks are gated by the PHY 101562306a36Sopenharmony_ci * due to the PHY being put into isolation or power down mode. 101662306a36Sopenharmony_ci * This is not an error if reset fails due to no clock. 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_ci if (ret) 101962306a36Sopenharmony_ci netdev_dbg(dev, "Cannot reset MAC core (error: %d)\n", ret); 102062306a36Sopenharmony_ci priv->dmaops->reset_dma(priv); 102162306a36Sopenharmony_ci free_skbufs(dev); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci spin_unlock(&priv->tx_lock); 102462306a36Sopenharmony_ci spin_unlock(&priv->mac_cfg_lock); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci priv->dmaops->uninit_dma(priv); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci return 0; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic struct net_device_ops altera_tse_netdev_ops = { 103262306a36Sopenharmony_ci .ndo_open = tse_open, 103362306a36Sopenharmony_ci .ndo_stop = tse_shutdown, 103462306a36Sopenharmony_ci .ndo_start_xmit = tse_start_xmit, 103562306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 103662306a36Sopenharmony_ci .ndo_set_rx_mode = tse_set_rx_mode, 103762306a36Sopenharmony_ci .ndo_change_mtu = tse_change_mtu, 103862306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 103962306a36Sopenharmony_ci}; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cistatic void alt_tse_mac_config(struct phylink_config *config, unsigned int mode, 104262306a36Sopenharmony_ci const struct phylink_link_state *state) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci struct net_device *ndev = to_net_dev(config->dev); 104562306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(ndev); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci spin_lock(&priv->mac_cfg_lock); 104862306a36Sopenharmony_ci reset_mac(priv); 104962306a36Sopenharmony_ci tse_set_mac(priv, true); 105062306a36Sopenharmony_ci spin_unlock(&priv->mac_cfg_lock); 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_cistatic void alt_tse_mac_link_down(struct phylink_config *config, 105462306a36Sopenharmony_ci unsigned int mode, phy_interface_t interface) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_cistatic void alt_tse_mac_link_up(struct phylink_config *config, 105962306a36Sopenharmony_ci struct phy_device *phy, unsigned int mode, 106062306a36Sopenharmony_ci phy_interface_t interface, int speed, 106162306a36Sopenharmony_ci int duplex, bool tx_pause, bool rx_pause) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci struct net_device *ndev = to_net_dev(config->dev); 106462306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(ndev); 106562306a36Sopenharmony_ci u32 ctrl; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci ctrl = csrrd32(priv->mac_dev, tse_csroffs(command_config)); 106862306a36Sopenharmony_ci ctrl &= ~(MAC_CMDCFG_ENA_10 | MAC_CMDCFG_ETH_SPEED | MAC_CMDCFG_HD_ENA); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (duplex == DUPLEX_HALF) 107162306a36Sopenharmony_ci ctrl |= MAC_CMDCFG_HD_ENA; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (speed == SPEED_1000) 107462306a36Sopenharmony_ci ctrl |= MAC_CMDCFG_ETH_SPEED; 107562306a36Sopenharmony_ci else if (speed == SPEED_10) 107662306a36Sopenharmony_ci ctrl |= MAC_CMDCFG_ENA_10; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci spin_lock(&priv->mac_cfg_lock); 107962306a36Sopenharmony_ci csrwr32(ctrl, priv->mac_dev, tse_csroffs(command_config)); 108062306a36Sopenharmony_ci spin_unlock(&priv->mac_cfg_lock); 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_cistatic struct phylink_pcs *alt_tse_select_pcs(struct phylink_config *config, 108462306a36Sopenharmony_ci phy_interface_t interface) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci struct net_device *ndev = to_net_dev(config->dev); 108762306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(ndev); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (interface == PHY_INTERFACE_MODE_SGMII || 109062306a36Sopenharmony_ci interface == PHY_INTERFACE_MODE_1000BASEX) 109162306a36Sopenharmony_ci return priv->pcs; 109262306a36Sopenharmony_ci else 109362306a36Sopenharmony_ci return NULL; 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic const struct phylink_mac_ops alt_tse_phylink_ops = { 109762306a36Sopenharmony_ci .mac_config = alt_tse_mac_config, 109862306a36Sopenharmony_ci .mac_link_down = alt_tse_mac_link_down, 109962306a36Sopenharmony_ci .mac_link_up = alt_tse_mac_link_up, 110062306a36Sopenharmony_ci .mac_select_pcs = alt_tse_select_pcs, 110162306a36Sopenharmony_ci}; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_cistatic int request_and_map(struct platform_device *pdev, const char *name, 110462306a36Sopenharmony_ci struct resource **res, void __iomem **ptr) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci struct device *device = &pdev->dev; 110762306a36Sopenharmony_ci struct resource *region; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); 111062306a36Sopenharmony_ci if (*res == NULL) { 111162306a36Sopenharmony_ci dev_err(device, "resource %s not defined\n", name); 111262306a36Sopenharmony_ci return -ENODEV; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci region = devm_request_mem_region(device, (*res)->start, 111662306a36Sopenharmony_ci resource_size(*res), dev_name(device)); 111762306a36Sopenharmony_ci if (region == NULL) { 111862306a36Sopenharmony_ci dev_err(device, "unable to request %s\n", name); 111962306a36Sopenharmony_ci return -EBUSY; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci *ptr = devm_ioremap(device, region->start, 112362306a36Sopenharmony_ci resource_size(region)); 112462306a36Sopenharmony_ci if (*ptr == NULL) { 112562306a36Sopenharmony_ci dev_err(device, "ioremap of %s failed!", name); 112662306a36Sopenharmony_ci return -ENOMEM; 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci return 0; 113062306a36Sopenharmony_ci} 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci/* Probe Altera TSE MAC device 113362306a36Sopenharmony_ci */ 113462306a36Sopenharmony_cistatic int altera_tse_probe(struct platform_device *pdev) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci const struct of_device_id *of_id = NULL; 113762306a36Sopenharmony_ci struct regmap_config pcs_regmap_cfg; 113862306a36Sopenharmony_ci struct altera_tse_private *priv; 113962306a36Sopenharmony_ci struct mdio_regmap_config mrc; 114062306a36Sopenharmony_ci struct resource *control_port; 114162306a36Sopenharmony_ci struct regmap *pcs_regmap; 114262306a36Sopenharmony_ci struct resource *dma_res; 114362306a36Sopenharmony_ci struct resource *pcs_res; 114462306a36Sopenharmony_ci struct mii_bus *pcs_bus; 114562306a36Sopenharmony_ci struct net_device *ndev; 114662306a36Sopenharmony_ci void __iomem *descmap; 114762306a36Sopenharmony_ci int ret = -ENODEV; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci ndev = alloc_etherdev(sizeof(struct altera_tse_private)); 115062306a36Sopenharmony_ci if (!ndev) { 115162306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not allocate network device\n"); 115262306a36Sopenharmony_ci return -ENODEV; 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci SET_NETDEV_DEV(ndev, &pdev->dev); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci priv = netdev_priv(ndev); 115862306a36Sopenharmony_ci priv->device = &pdev->dev; 115962306a36Sopenharmony_ci priv->dev = ndev; 116062306a36Sopenharmony_ci priv->msg_enable = netif_msg_init(debug, default_msg_level); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci of_id = of_match_device(altera_tse_ids, &pdev->dev); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci if (of_id) 116562306a36Sopenharmony_ci priv->dmaops = (struct altera_dmaops *)of_id->data; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (priv->dmaops && 116962306a36Sopenharmony_ci priv->dmaops->altera_dtype == ALTERA_DTYPE_SGDMA) { 117062306a36Sopenharmony_ci /* Get the mapped address to the SGDMA descriptor memory */ 117162306a36Sopenharmony_ci ret = request_and_map(pdev, "s1", &dma_res, &descmap); 117262306a36Sopenharmony_ci if (ret) 117362306a36Sopenharmony_ci goto err_free_netdev; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* Start of that memory is for transmit descriptors */ 117662306a36Sopenharmony_ci priv->tx_dma_desc = descmap; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci /* First half is for tx descriptors, other half for tx */ 117962306a36Sopenharmony_ci priv->txdescmem = resource_size(dma_res)/2; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci priv->txdescmem_busaddr = (dma_addr_t)dma_res->start; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci priv->rx_dma_desc = (void __iomem *)((uintptr_t)(descmap + 118462306a36Sopenharmony_ci priv->txdescmem)); 118562306a36Sopenharmony_ci priv->rxdescmem = resource_size(dma_res)/2; 118662306a36Sopenharmony_ci priv->rxdescmem_busaddr = dma_res->start; 118762306a36Sopenharmony_ci priv->rxdescmem_busaddr += priv->txdescmem; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (upper_32_bits(priv->rxdescmem_busaddr)) { 119062306a36Sopenharmony_ci dev_dbg(priv->device, 119162306a36Sopenharmony_ci "SGDMA bus addresses greater than 32-bits\n"); 119262306a36Sopenharmony_ci ret = -EINVAL; 119362306a36Sopenharmony_ci goto err_free_netdev; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci if (upper_32_bits(priv->txdescmem_busaddr)) { 119662306a36Sopenharmony_ci dev_dbg(priv->device, 119762306a36Sopenharmony_ci "SGDMA bus addresses greater than 32-bits\n"); 119862306a36Sopenharmony_ci ret = -EINVAL; 119962306a36Sopenharmony_ci goto err_free_netdev; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci } else if (priv->dmaops && 120262306a36Sopenharmony_ci priv->dmaops->altera_dtype == ALTERA_DTYPE_MSGDMA) { 120362306a36Sopenharmony_ci ret = request_and_map(pdev, "rx_resp", &dma_res, 120462306a36Sopenharmony_ci &priv->rx_dma_resp); 120562306a36Sopenharmony_ci if (ret) 120662306a36Sopenharmony_ci goto err_free_netdev; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci ret = request_and_map(pdev, "tx_desc", &dma_res, 120962306a36Sopenharmony_ci &priv->tx_dma_desc); 121062306a36Sopenharmony_ci if (ret) 121162306a36Sopenharmony_ci goto err_free_netdev; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci priv->txdescmem = resource_size(dma_res); 121462306a36Sopenharmony_ci priv->txdescmem_busaddr = dma_res->start; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci ret = request_and_map(pdev, "rx_desc", &dma_res, 121762306a36Sopenharmony_ci &priv->rx_dma_desc); 121862306a36Sopenharmony_ci if (ret) 121962306a36Sopenharmony_ci goto err_free_netdev; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci priv->rxdescmem = resource_size(dma_res); 122262306a36Sopenharmony_ci priv->rxdescmem_busaddr = dma_res->start; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci } else { 122562306a36Sopenharmony_ci ret = -ENODEV; 122662306a36Sopenharmony_ci goto err_free_netdev; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask))) { 123062306a36Sopenharmony_ci dma_set_coherent_mask(priv->device, 123162306a36Sopenharmony_ci DMA_BIT_MASK(priv->dmaops->dmamask)); 123262306a36Sopenharmony_ci } else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32))) { 123362306a36Sopenharmony_ci dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32)); 123462306a36Sopenharmony_ci } else { 123562306a36Sopenharmony_ci ret = -EIO; 123662306a36Sopenharmony_ci goto err_free_netdev; 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci /* MAC address space */ 124062306a36Sopenharmony_ci ret = request_and_map(pdev, "control_port", &control_port, 124162306a36Sopenharmony_ci (void __iomem **)&priv->mac_dev); 124262306a36Sopenharmony_ci if (ret) 124362306a36Sopenharmony_ci goto err_free_netdev; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* xSGDMA Rx Dispatcher address space */ 124662306a36Sopenharmony_ci ret = request_and_map(pdev, "rx_csr", &dma_res, 124762306a36Sopenharmony_ci &priv->rx_dma_csr); 124862306a36Sopenharmony_ci if (ret) 124962306a36Sopenharmony_ci goto err_free_netdev; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* xSGDMA Tx Dispatcher address space */ 125362306a36Sopenharmony_ci ret = request_and_map(pdev, "tx_csr", &dma_res, 125462306a36Sopenharmony_ci &priv->tx_dma_csr); 125562306a36Sopenharmony_ci if (ret) 125662306a36Sopenharmony_ci goto err_free_netdev; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci memset(&pcs_regmap_cfg, 0, sizeof(pcs_regmap_cfg)); 125962306a36Sopenharmony_ci memset(&mrc, 0, sizeof(mrc)); 126062306a36Sopenharmony_ci /* SGMII PCS address space. The location can vary depending on how the 126162306a36Sopenharmony_ci * IP is integrated. We can have a resource dedicated to it at a specific 126262306a36Sopenharmony_ci * address space, but if it's not the case, we fallback to the mdiophy0 126362306a36Sopenharmony_ci * from the MAC's address space 126462306a36Sopenharmony_ci */ 126562306a36Sopenharmony_ci ret = request_and_map(pdev, "pcs", &pcs_res, &priv->pcs_base); 126662306a36Sopenharmony_ci if (ret) { 126762306a36Sopenharmony_ci /* If we can't find a dedicated resource for the PCS, fallback 126862306a36Sopenharmony_ci * to the internal PCS, that has a different address stride 126962306a36Sopenharmony_ci */ 127062306a36Sopenharmony_ci priv->pcs_base = priv->mac_dev + tse_csroffs(mdio_phy0); 127162306a36Sopenharmony_ci pcs_regmap_cfg.reg_bits = 32; 127262306a36Sopenharmony_ci /* Values are MDIO-like values, on 16 bits */ 127362306a36Sopenharmony_ci pcs_regmap_cfg.val_bits = 16; 127462306a36Sopenharmony_ci pcs_regmap_cfg.reg_shift = REGMAP_UPSHIFT(2); 127562306a36Sopenharmony_ci } else { 127662306a36Sopenharmony_ci pcs_regmap_cfg.reg_bits = 16; 127762306a36Sopenharmony_ci pcs_regmap_cfg.val_bits = 16; 127862306a36Sopenharmony_ci pcs_regmap_cfg.reg_shift = REGMAP_UPSHIFT(1); 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci /* Create a regmap for the PCS so that it can be used by the PCS driver */ 128262306a36Sopenharmony_ci pcs_regmap = devm_regmap_init_mmio(&pdev->dev, priv->pcs_base, 128362306a36Sopenharmony_ci &pcs_regmap_cfg); 128462306a36Sopenharmony_ci if (IS_ERR(pcs_regmap)) { 128562306a36Sopenharmony_ci ret = PTR_ERR(pcs_regmap); 128662306a36Sopenharmony_ci goto err_free_netdev; 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci mrc.regmap = pcs_regmap; 128962306a36Sopenharmony_ci mrc.parent = &pdev->dev; 129062306a36Sopenharmony_ci mrc.valid_addr = 0x0; 129162306a36Sopenharmony_ci mrc.autoscan = false; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci /* Rx IRQ */ 129462306a36Sopenharmony_ci priv->rx_irq = platform_get_irq_byname(pdev, "rx_irq"); 129562306a36Sopenharmony_ci if (priv->rx_irq == -ENXIO) { 129662306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot obtain Rx IRQ\n"); 129762306a36Sopenharmony_ci ret = -ENXIO; 129862306a36Sopenharmony_ci goto err_free_netdev; 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci /* Tx IRQ */ 130262306a36Sopenharmony_ci priv->tx_irq = platform_get_irq_byname(pdev, "tx_irq"); 130362306a36Sopenharmony_ci if (priv->tx_irq == -ENXIO) { 130462306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot obtain Tx IRQ\n"); 130562306a36Sopenharmony_ci ret = -ENXIO; 130662306a36Sopenharmony_ci goto err_free_netdev; 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci /* get FIFO depths from device tree */ 131062306a36Sopenharmony_ci if (of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth", 131162306a36Sopenharmony_ci &priv->rx_fifo_depth)) { 131262306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot obtain rx-fifo-depth\n"); 131362306a36Sopenharmony_ci ret = -ENXIO; 131462306a36Sopenharmony_ci goto err_free_netdev; 131562306a36Sopenharmony_ci } 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth", 131862306a36Sopenharmony_ci &priv->tx_fifo_depth)) { 131962306a36Sopenharmony_ci dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n"); 132062306a36Sopenharmony_ci ret = -ENXIO; 132162306a36Sopenharmony_ci goto err_free_netdev; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci /* get hash filter settings for this instance */ 132562306a36Sopenharmony_ci priv->hash_filter = 132662306a36Sopenharmony_ci of_property_read_bool(pdev->dev.of_node, 132762306a36Sopenharmony_ci "altr,has-hash-multicast-filter"); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci /* Set hash filter to not set for now until the 133062306a36Sopenharmony_ci * multicast filter receive issue is debugged 133162306a36Sopenharmony_ci */ 133262306a36Sopenharmony_ci priv->hash_filter = 0; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci /* get supplemental address settings for this instance */ 133562306a36Sopenharmony_ci priv->added_unicast = 133662306a36Sopenharmony_ci of_property_read_bool(pdev->dev.of_node, 133762306a36Sopenharmony_ci "altr,has-supplementary-unicast"); 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci priv->dev->min_mtu = ETH_ZLEN + ETH_FCS_LEN; 134062306a36Sopenharmony_ci /* Max MTU is 1500, ETH_DATA_LEN */ 134162306a36Sopenharmony_ci priv->dev->max_mtu = ETH_DATA_LEN; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci /* Get the max mtu from the device tree. Note that the 134462306a36Sopenharmony_ci * "max-frame-size" parameter is actually max mtu. Definition 134562306a36Sopenharmony_ci * in the ePAPR v1.1 spec and usage differ, so go with usage. 134662306a36Sopenharmony_ci */ 134762306a36Sopenharmony_ci of_property_read_u32(pdev->dev.of_node, "max-frame-size", 134862306a36Sopenharmony_ci &priv->dev->max_mtu); 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci /* The DMA buffer size already accounts for an alignment bias 135162306a36Sopenharmony_ci * to avoid unaligned access exceptions for the NIOS processor, 135262306a36Sopenharmony_ci */ 135362306a36Sopenharmony_ci priv->rx_dma_buf_sz = ALTERA_RXDMABUFFER_SIZE; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci /* get default MAC address from device tree */ 135662306a36Sopenharmony_ci ret = of_get_ethdev_address(pdev->dev.of_node, ndev); 135762306a36Sopenharmony_ci if (ret) 135862306a36Sopenharmony_ci eth_hw_addr_random(ndev); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci /* get phy addr and create mdio */ 136162306a36Sopenharmony_ci ret = altera_tse_phy_get_addr_mdio_create(ndev); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci if (ret) 136462306a36Sopenharmony_ci goto err_free_netdev; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci /* initialize netdev */ 136762306a36Sopenharmony_ci ndev->mem_start = control_port->start; 136862306a36Sopenharmony_ci ndev->mem_end = control_port->end; 136962306a36Sopenharmony_ci ndev->netdev_ops = &altera_tse_netdev_ops; 137062306a36Sopenharmony_ci altera_tse_set_ethtool_ops(ndev); 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci altera_tse_netdev_ops.ndo_set_rx_mode = tse_set_rx_mode; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci if (priv->hash_filter) 137562306a36Sopenharmony_ci altera_tse_netdev_ops.ndo_set_rx_mode = 137662306a36Sopenharmony_ci tse_set_rx_mode_hashfilter; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci /* Scatter/gather IO is not supported, 137962306a36Sopenharmony_ci * so it is turned off 138062306a36Sopenharmony_ci */ 138162306a36Sopenharmony_ci ndev->hw_features &= ~NETIF_F_SG; 138262306a36Sopenharmony_ci ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci /* VLAN offloading of tagging, stripping and filtering is not 138562306a36Sopenharmony_ci * supported by hardware, but driver will accommodate the 138662306a36Sopenharmony_ci * extra 4-byte VLAN tag for processing by upper layers 138762306a36Sopenharmony_ci */ 138862306a36Sopenharmony_ci ndev->features |= NETIF_F_HW_VLAN_CTAG_RX; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci /* setup NAPI interface */ 139162306a36Sopenharmony_ci netif_napi_add(ndev, &priv->napi, tse_poll); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci spin_lock_init(&priv->mac_cfg_lock); 139462306a36Sopenharmony_ci spin_lock_init(&priv->tx_lock); 139562306a36Sopenharmony_ci spin_lock_init(&priv->rxdma_irq_lock); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci netif_carrier_off(ndev); 139862306a36Sopenharmony_ci ret = register_netdev(ndev); 139962306a36Sopenharmony_ci if (ret) { 140062306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register TSE net device\n"); 140162306a36Sopenharmony_ci goto err_register_netdev; 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci platform_set_drvdata(pdev, ndev); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci priv->revision = ioread32(&priv->mac_dev->megacore_revision); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if (netif_msg_probe(priv)) 140962306a36Sopenharmony_ci dev_info(&pdev->dev, "Altera TSE MAC version %d.%d at 0x%08lx irq %d/%d\n", 141062306a36Sopenharmony_ci (priv->revision >> 8) & 0xff, 141162306a36Sopenharmony_ci priv->revision & 0xff, 141262306a36Sopenharmony_ci (unsigned long) control_port->start, priv->rx_irq, 141362306a36Sopenharmony_ci priv->tx_irq); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci snprintf(mrc.name, MII_BUS_ID_SIZE, "%s-pcs-mii", ndev->name); 141662306a36Sopenharmony_ci pcs_bus = devm_mdio_regmap_register(&pdev->dev, &mrc); 141762306a36Sopenharmony_ci if (IS_ERR(pcs_bus)) { 141862306a36Sopenharmony_ci ret = PTR_ERR(pcs_bus); 141962306a36Sopenharmony_ci goto err_init_pcs; 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci priv->pcs = lynx_pcs_create_mdiodev(pcs_bus, 0); 142362306a36Sopenharmony_ci if (IS_ERR(priv->pcs)) { 142462306a36Sopenharmony_ci ret = PTR_ERR(priv->pcs); 142562306a36Sopenharmony_ci goto err_init_pcs; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci priv->phylink_config.dev = &ndev->dev; 142962306a36Sopenharmony_ci priv->phylink_config.type = PHYLINK_NETDEV; 143062306a36Sopenharmony_ci priv->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 | 143162306a36Sopenharmony_ci MAC_100 | MAC_1000FD; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci phy_interface_set_rgmii(priv->phylink_config.supported_interfaces); 143462306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_MII, 143562306a36Sopenharmony_ci priv->phylink_config.supported_interfaces); 143662306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_GMII, 143762306a36Sopenharmony_ci priv->phylink_config.supported_interfaces); 143862306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_SGMII, 143962306a36Sopenharmony_ci priv->phylink_config.supported_interfaces); 144062306a36Sopenharmony_ci __set_bit(PHY_INTERFACE_MODE_1000BASEX, 144162306a36Sopenharmony_ci priv->phylink_config.supported_interfaces); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci priv->phylink = phylink_create(&priv->phylink_config, 144462306a36Sopenharmony_ci of_fwnode_handle(priv->device->of_node), 144562306a36Sopenharmony_ci priv->phy_iface, &alt_tse_phylink_ops); 144662306a36Sopenharmony_ci if (IS_ERR(priv->phylink)) { 144762306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to create phylink\n"); 144862306a36Sopenharmony_ci ret = PTR_ERR(priv->phylink); 144962306a36Sopenharmony_ci goto err_init_phylink; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci return 0; 145362306a36Sopenharmony_cierr_init_phylink: 145462306a36Sopenharmony_ci lynx_pcs_destroy(priv->pcs); 145562306a36Sopenharmony_cierr_init_pcs: 145662306a36Sopenharmony_ci unregister_netdev(ndev); 145762306a36Sopenharmony_cierr_register_netdev: 145862306a36Sopenharmony_ci netif_napi_del(&priv->napi); 145962306a36Sopenharmony_ci altera_tse_mdio_destroy(ndev); 146062306a36Sopenharmony_cierr_free_netdev: 146162306a36Sopenharmony_ci free_netdev(ndev); 146262306a36Sopenharmony_ci return ret; 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci/* Remove Altera TSE MAC device 146662306a36Sopenharmony_ci */ 146762306a36Sopenharmony_cistatic int altera_tse_remove(struct platform_device *pdev) 146862306a36Sopenharmony_ci{ 146962306a36Sopenharmony_ci struct net_device *ndev = platform_get_drvdata(pdev); 147062306a36Sopenharmony_ci struct altera_tse_private *priv = netdev_priv(ndev); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci platform_set_drvdata(pdev, NULL); 147362306a36Sopenharmony_ci altera_tse_mdio_destroy(ndev); 147462306a36Sopenharmony_ci unregister_netdev(ndev); 147562306a36Sopenharmony_ci phylink_destroy(priv->phylink); 147662306a36Sopenharmony_ci lynx_pcs_destroy(priv->pcs); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci free_netdev(ndev); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci return 0; 148162306a36Sopenharmony_ci} 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_cistatic const struct altera_dmaops altera_dtype_sgdma = { 148462306a36Sopenharmony_ci .altera_dtype = ALTERA_DTYPE_SGDMA, 148562306a36Sopenharmony_ci .dmamask = 32, 148662306a36Sopenharmony_ci .reset_dma = sgdma_reset, 148762306a36Sopenharmony_ci .enable_txirq = sgdma_enable_txirq, 148862306a36Sopenharmony_ci .enable_rxirq = sgdma_enable_rxirq, 148962306a36Sopenharmony_ci .disable_txirq = sgdma_disable_txirq, 149062306a36Sopenharmony_ci .disable_rxirq = sgdma_disable_rxirq, 149162306a36Sopenharmony_ci .clear_txirq = sgdma_clear_txirq, 149262306a36Sopenharmony_ci .clear_rxirq = sgdma_clear_rxirq, 149362306a36Sopenharmony_ci .tx_buffer = sgdma_tx_buffer, 149462306a36Sopenharmony_ci .tx_completions = sgdma_tx_completions, 149562306a36Sopenharmony_ci .add_rx_desc = sgdma_add_rx_desc, 149662306a36Sopenharmony_ci .get_rx_status = sgdma_rx_status, 149762306a36Sopenharmony_ci .init_dma = sgdma_initialize, 149862306a36Sopenharmony_ci .uninit_dma = sgdma_uninitialize, 149962306a36Sopenharmony_ci .start_rxdma = sgdma_start_rxdma, 150062306a36Sopenharmony_ci}; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_cistatic const struct altera_dmaops altera_dtype_msgdma = { 150362306a36Sopenharmony_ci .altera_dtype = ALTERA_DTYPE_MSGDMA, 150462306a36Sopenharmony_ci .dmamask = 64, 150562306a36Sopenharmony_ci .reset_dma = msgdma_reset, 150662306a36Sopenharmony_ci .enable_txirq = msgdma_enable_txirq, 150762306a36Sopenharmony_ci .enable_rxirq = msgdma_enable_rxirq, 150862306a36Sopenharmony_ci .disable_txirq = msgdma_disable_txirq, 150962306a36Sopenharmony_ci .disable_rxirq = msgdma_disable_rxirq, 151062306a36Sopenharmony_ci .clear_txirq = msgdma_clear_txirq, 151162306a36Sopenharmony_ci .clear_rxirq = msgdma_clear_rxirq, 151262306a36Sopenharmony_ci .tx_buffer = msgdma_tx_buffer, 151362306a36Sopenharmony_ci .tx_completions = msgdma_tx_completions, 151462306a36Sopenharmony_ci .add_rx_desc = msgdma_add_rx_desc, 151562306a36Sopenharmony_ci .get_rx_status = msgdma_rx_status, 151662306a36Sopenharmony_ci .init_dma = msgdma_initialize, 151762306a36Sopenharmony_ci .uninit_dma = msgdma_uninitialize, 151862306a36Sopenharmony_ci .start_rxdma = msgdma_start_rxdma, 151962306a36Sopenharmony_ci}; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_cistatic const struct of_device_id altera_tse_ids[] = { 152262306a36Sopenharmony_ci { .compatible = "altr,tse-msgdma-1.0", .data = &altera_dtype_msgdma, }, 152362306a36Sopenharmony_ci { .compatible = "altr,tse-1.0", .data = &altera_dtype_sgdma, }, 152462306a36Sopenharmony_ci { .compatible = "ALTR,tse-1.0", .data = &altera_dtype_sgdma, }, 152562306a36Sopenharmony_ci {}, 152662306a36Sopenharmony_ci}; 152762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, altera_tse_ids); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_cistatic struct platform_driver altera_tse_driver = { 153062306a36Sopenharmony_ci .probe = altera_tse_probe, 153162306a36Sopenharmony_ci .remove = altera_tse_remove, 153262306a36Sopenharmony_ci .suspend = NULL, 153362306a36Sopenharmony_ci .resume = NULL, 153462306a36Sopenharmony_ci .driver = { 153562306a36Sopenharmony_ci .name = ALTERA_TSE_RESOURCE_NAME, 153662306a36Sopenharmony_ci .of_match_table = altera_tse_ids, 153762306a36Sopenharmony_ci }, 153862306a36Sopenharmony_ci}; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_cimodule_platform_driver(altera_tse_driver); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ciMODULE_AUTHOR("Altera Corporation"); 154362306a36Sopenharmony_ciMODULE_DESCRIPTION("Altera Triple Speed Ethernet MAC driver"); 154462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1545