162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Actions Semi Owl SoCs Ethernet MAC driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2012 Actions Semi Inc. 662306a36Sopenharmony_ci * Copyright (c) 2021 Cristian Ciocaltea <cristian.ciocaltea@gmail.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/circ_buf.h> 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1262306a36Sopenharmony_ci#include <linux/etherdevice.h> 1362306a36Sopenharmony_ci#include <linux/of_mdio.h> 1462306a36Sopenharmony_ci#include <linux/of_net.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/pm.h> 1762306a36Sopenharmony_ci#include <linux/reset.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "owl-emac.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define OWL_EMAC_DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | \ 2262306a36Sopenharmony_ci NETIF_MSG_PROBE | \ 2362306a36Sopenharmony_ci NETIF_MSG_LINK) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic u32 owl_emac_reg_read(struct owl_emac_priv *priv, u32 reg) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci return readl(priv->base + reg); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic void owl_emac_reg_write(struct owl_emac_priv *priv, u32 reg, u32 data) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci writel(data, priv->base + reg); 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic u32 owl_emac_reg_update(struct owl_emac_priv *priv, 3662306a36Sopenharmony_ci u32 reg, u32 mask, u32 val) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci u32 data, old_val; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci data = owl_emac_reg_read(priv, reg); 4162306a36Sopenharmony_ci old_val = data & mask; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci data &= ~mask; 4462306a36Sopenharmony_ci data |= val & mask; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci owl_emac_reg_write(priv, reg, data); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci return old_val; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic void owl_emac_reg_set(struct owl_emac_priv *priv, u32 reg, u32 bits) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci owl_emac_reg_update(priv, reg, bits, bits); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void owl_emac_reg_clear(struct owl_emac_priv *priv, u32 reg, u32 bits) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci owl_emac_reg_update(priv, reg, bits, 0); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic struct device *owl_emac_get_dev(struct owl_emac_priv *priv) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci return priv->netdev->dev.parent; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic void owl_emac_irq_enable(struct owl_emac_priv *priv) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci /* Enable all interrupts except TU. 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * Note the NIE and AIE bits shall also be set in order to actually 7162306a36Sopenharmony_ci * enable the selected interrupts. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR7, 7462306a36Sopenharmony_ci OWL_EMAC_BIT_MAC_CSR7_NIE | 7562306a36Sopenharmony_ci OWL_EMAC_BIT_MAC_CSR7_AIE | 7662306a36Sopenharmony_ci OWL_EMAC_BIT_MAC_CSR7_ALL_NOT_TUE); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void owl_emac_irq_disable(struct owl_emac_priv *priv) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci /* Disable all interrupts. 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * WARNING: Unset only the NIE and AIE bits in CSR7 to workaround an 8462306a36Sopenharmony_ci * unexpected side effect (MAC hardware bug?!) where some bits in the 8562306a36Sopenharmony_ci * status register (CSR5) are cleared automatically before being able 8662306a36Sopenharmony_ci * to read them via owl_emac_irq_clear(). 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR7, 8962306a36Sopenharmony_ci OWL_EMAC_BIT_MAC_CSR7_ALL_NOT_TUE); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic u32 owl_emac_irq_status(struct owl_emac_priv *priv) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci return owl_emac_reg_read(priv, OWL_EMAC_REG_MAC_CSR5); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic u32 owl_emac_irq_clear(struct owl_emac_priv *priv) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci u32 val = owl_emac_irq_status(priv); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR5, val); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return val; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic dma_addr_t owl_emac_dma_map_rx(struct owl_emac_priv *priv, 10762306a36Sopenharmony_ci struct sk_buff *skb) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct device *dev = owl_emac_get_dev(priv); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* Buffer pointer for the RX DMA descriptor must be word aligned. */ 11262306a36Sopenharmony_ci return dma_map_single(dev, skb_tail_pointer(skb), 11362306a36Sopenharmony_ci skb_tailroom(skb), DMA_FROM_DEVICE); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void owl_emac_dma_unmap_rx(struct owl_emac_priv *priv, 11762306a36Sopenharmony_ci struct sk_buff *skb, dma_addr_t dma_addr) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct device *dev = owl_emac_get_dev(priv); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci dma_unmap_single(dev, dma_addr, skb_tailroom(skb), DMA_FROM_DEVICE); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic dma_addr_t owl_emac_dma_map_tx(struct owl_emac_priv *priv, 12562306a36Sopenharmony_ci struct sk_buff *skb) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct device *dev = owl_emac_get_dev(priv); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic void owl_emac_dma_unmap_tx(struct owl_emac_priv *priv, 13362306a36Sopenharmony_ci struct sk_buff *skb, dma_addr_t dma_addr) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct device *dev = owl_emac_get_dev(priv); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci dma_unmap_single(dev, dma_addr, skb_headlen(skb), DMA_TO_DEVICE); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic unsigned int owl_emac_ring_num_unused(struct owl_emac_ring *ring) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci return CIRC_SPACE(ring->head, ring->tail, ring->size); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic unsigned int owl_emac_ring_get_next(struct owl_emac_ring *ring, 14662306a36Sopenharmony_ci unsigned int cur) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci return (cur + 1) & (ring->size - 1); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic void owl_emac_ring_push_head(struct owl_emac_ring *ring) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci ring->head = owl_emac_ring_get_next(ring, ring->head); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void owl_emac_ring_pop_tail(struct owl_emac_ring *ring) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci ring->tail = owl_emac_ring_get_next(ring, ring->tail); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic struct sk_buff *owl_emac_alloc_skb(struct net_device *netdev) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct sk_buff *skb; 16462306a36Sopenharmony_ci int offset; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci skb = netdev_alloc_skb(netdev, OWL_EMAC_RX_FRAME_MAX_LEN + 16762306a36Sopenharmony_ci OWL_EMAC_SKB_RESERVE); 16862306a36Sopenharmony_ci if (unlikely(!skb)) 16962306a36Sopenharmony_ci return NULL; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Ensure 4 bytes DMA alignment. */ 17262306a36Sopenharmony_ci offset = ((uintptr_t)skb->data) & (OWL_EMAC_SKB_ALIGN - 1); 17362306a36Sopenharmony_ci if (unlikely(offset)) 17462306a36Sopenharmony_ci skb_reserve(skb, OWL_EMAC_SKB_ALIGN - offset); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci return skb; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int owl_emac_ring_prepare_rx(struct owl_emac_priv *priv) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct owl_emac_ring *ring = &priv->rx_ring; 18262306a36Sopenharmony_ci struct device *dev = owl_emac_get_dev(priv); 18362306a36Sopenharmony_ci struct net_device *netdev = priv->netdev; 18462306a36Sopenharmony_ci struct owl_emac_ring_desc *desc; 18562306a36Sopenharmony_ci struct sk_buff *skb; 18662306a36Sopenharmony_ci dma_addr_t dma_addr; 18762306a36Sopenharmony_ci int i; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (i = 0; i < ring->size; i++) { 19062306a36Sopenharmony_ci skb = owl_emac_alloc_skb(netdev); 19162306a36Sopenharmony_ci if (!skb) 19262306a36Sopenharmony_ci return -ENOMEM; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci dma_addr = owl_emac_dma_map_rx(priv, skb); 19562306a36Sopenharmony_ci if (dma_mapping_error(dev, dma_addr)) { 19662306a36Sopenharmony_ci dev_kfree_skb(skb); 19762306a36Sopenharmony_ci return -ENOMEM; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci desc = &ring->descs[i]; 20162306a36Sopenharmony_ci desc->status = OWL_EMAC_BIT_RDES0_OWN; 20262306a36Sopenharmony_ci desc->control = skb_tailroom(skb) & OWL_EMAC_MSK_RDES1_RBS1; 20362306a36Sopenharmony_ci desc->buf_addr = dma_addr; 20462306a36Sopenharmony_ci desc->reserved = 0; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci ring->skbs[i] = skb; 20762306a36Sopenharmony_ci ring->skbs_dma[i] = dma_addr; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci desc->control |= OWL_EMAC_BIT_RDES1_RER; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci ring->head = 0; 21362306a36Sopenharmony_ci ring->tail = 0; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic void owl_emac_ring_prepare_tx(struct owl_emac_priv *priv) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci struct owl_emac_ring *ring = &priv->tx_ring; 22162306a36Sopenharmony_ci struct owl_emac_ring_desc *desc; 22262306a36Sopenharmony_ci int i; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci for (i = 0; i < ring->size; i++) { 22562306a36Sopenharmony_ci desc = &ring->descs[i]; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci desc->status = 0; 22862306a36Sopenharmony_ci desc->control = OWL_EMAC_BIT_TDES1_IC; 22962306a36Sopenharmony_ci desc->buf_addr = 0; 23062306a36Sopenharmony_ci desc->reserved = 0; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci desc->control |= OWL_EMAC_BIT_TDES1_TER; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci memset(ring->skbs_dma, 0, sizeof(dma_addr_t) * ring->size); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci ring->head = 0; 23862306a36Sopenharmony_ci ring->tail = 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic void owl_emac_ring_unprepare_rx(struct owl_emac_priv *priv) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct owl_emac_ring *ring = &priv->rx_ring; 24462306a36Sopenharmony_ci int i; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci for (i = 0; i < ring->size; i++) { 24762306a36Sopenharmony_ci ring->descs[i].status = 0; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (!ring->skbs_dma[i]) 25062306a36Sopenharmony_ci continue; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci owl_emac_dma_unmap_rx(priv, ring->skbs[i], ring->skbs_dma[i]); 25362306a36Sopenharmony_ci ring->skbs_dma[i] = 0; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci dev_kfree_skb(ring->skbs[i]); 25662306a36Sopenharmony_ci ring->skbs[i] = NULL; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic void owl_emac_ring_unprepare_tx(struct owl_emac_priv *priv) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci struct owl_emac_ring *ring = &priv->tx_ring; 26362306a36Sopenharmony_ci int i; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci for (i = 0; i < ring->size; i++) { 26662306a36Sopenharmony_ci ring->descs[i].status = 0; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!ring->skbs_dma[i]) 26962306a36Sopenharmony_ci continue; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci owl_emac_dma_unmap_tx(priv, ring->skbs[i], ring->skbs_dma[i]); 27262306a36Sopenharmony_ci ring->skbs_dma[i] = 0; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci dev_kfree_skb(ring->skbs[i]); 27562306a36Sopenharmony_ci ring->skbs[i] = NULL; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int owl_emac_ring_alloc(struct device *dev, struct owl_emac_ring *ring, 28062306a36Sopenharmony_ci unsigned int size) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci ring->descs = dmam_alloc_coherent(dev, 28362306a36Sopenharmony_ci sizeof(struct owl_emac_ring_desc) * size, 28462306a36Sopenharmony_ci &ring->descs_dma, GFP_KERNEL); 28562306a36Sopenharmony_ci if (!ring->descs) 28662306a36Sopenharmony_ci return -ENOMEM; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ring->skbs = devm_kcalloc(dev, size, sizeof(struct sk_buff *), 28962306a36Sopenharmony_ci GFP_KERNEL); 29062306a36Sopenharmony_ci if (!ring->skbs) 29162306a36Sopenharmony_ci return -ENOMEM; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci ring->skbs_dma = devm_kcalloc(dev, size, sizeof(dma_addr_t), 29462306a36Sopenharmony_ci GFP_KERNEL); 29562306a36Sopenharmony_ci if (!ring->skbs_dma) 29662306a36Sopenharmony_ci return -ENOMEM; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci ring->size = size; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return 0; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic void owl_emac_dma_cmd_resume_rx(struct owl_emac_priv *priv) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR2, 30662306a36Sopenharmony_ci OWL_EMAC_VAL_MAC_CSR2_RPD); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic void owl_emac_dma_cmd_resume_tx(struct owl_emac_priv *priv) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR1, 31262306a36Sopenharmony_ci OWL_EMAC_VAL_MAC_CSR1_TPD); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic u32 owl_emac_dma_cmd_set_tx(struct owl_emac_priv *priv, u32 status) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci return owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6, 31862306a36Sopenharmony_ci OWL_EMAC_BIT_MAC_CSR6_ST, status); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic u32 owl_emac_dma_cmd_start_tx(struct owl_emac_priv *priv) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci return owl_emac_dma_cmd_set_tx(priv, ~0); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic u32 owl_emac_dma_cmd_set(struct owl_emac_priv *priv, u32 status) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci return owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6, 32962306a36Sopenharmony_ci OWL_EMAC_MSK_MAC_CSR6_STSR, status); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic u32 owl_emac_dma_cmd_start(struct owl_emac_priv *priv) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci return owl_emac_dma_cmd_set(priv, ~0); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic u32 owl_emac_dma_cmd_stop(struct owl_emac_priv *priv) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci return owl_emac_dma_cmd_set(priv, 0); 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic void owl_emac_set_hw_mac_addr(struct net_device *netdev) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 34562306a36Sopenharmony_ci const u8 *mac_addr = netdev->dev_addr; 34662306a36Sopenharmony_ci u32 addr_high, addr_low; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci addr_high = mac_addr[0] << 8 | mac_addr[1]; 34962306a36Sopenharmony_ci addr_low = mac_addr[2] << 24 | mac_addr[3] << 16 | 35062306a36Sopenharmony_ci mac_addr[4] << 8 | mac_addr[5]; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR17, addr_high); 35362306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR16, addr_low); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void owl_emac_update_link_state(struct owl_emac_priv *priv) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci u32 val, status; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (priv->pause) { 36162306a36Sopenharmony_ci val = OWL_EMAC_BIT_MAC_CSR20_FCE | OWL_EMAC_BIT_MAC_CSR20_TUE; 36262306a36Sopenharmony_ci val |= OWL_EMAC_BIT_MAC_CSR20_TPE | OWL_EMAC_BIT_MAC_CSR20_RPE; 36362306a36Sopenharmony_ci val |= OWL_EMAC_BIT_MAC_CSR20_BPE; 36462306a36Sopenharmony_ci } else { 36562306a36Sopenharmony_ci val = 0; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* Update flow control. */ 36962306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR20, val); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci val = (priv->speed == SPEED_100) ? OWL_EMAC_VAL_MAC_CSR6_SPEED_100M : 37262306a36Sopenharmony_ci OWL_EMAC_VAL_MAC_CSR6_SPEED_10M; 37362306a36Sopenharmony_ci val <<= OWL_EMAC_OFF_MAC_CSR6_SPEED; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (priv->duplex == DUPLEX_FULL) 37662306a36Sopenharmony_ci val |= OWL_EMAC_BIT_MAC_CSR6_FD; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci spin_lock_bh(&priv->lock); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* Temporarily stop DMA TX & RX. */ 38162306a36Sopenharmony_ci status = owl_emac_dma_cmd_stop(priv); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Update operation modes. */ 38462306a36Sopenharmony_ci owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6, 38562306a36Sopenharmony_ci OWL_EMAC_MSK_MAC_CSR6_SPEED | 38662306a36Sopenharmony_ci OWL_EMAC_BIT_MAC_CSR6_FD, val); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* Restore DMA TX & RX status. */ 38962306a36Sopenharmony_ci owl_emac_dma_cmd_set(priv, status); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci spin_unlock_bh(&priv->lock); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic void owl_emac_adjust_link(struct net_device *netdev) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 39762306a36Sopenharmony_ci struct phy_device *phydev = netdev->phydev; 39862306a36Sopenharmony_ci bool state_changed = false; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (phydev->link) { 40162306a36Sopenharmony_ci if (!priv->link) { 40262306a36Sopenharmony_ci priv->link = phydev->link; 40362306a36Sopenharmony_ci state_changed = true; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (priv->speed != phydev->speed) { 40762306a36Sopenharmony_ci priv->speed = phydev->speed; 40862306a36Sopenharmony_ci state_changed = true; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (priv->duplex != phydev->duplex) { 41262306a36Sopenharmony_ci priv->duplex = phydev->duplex; 41362306a36Sopenharmony_ci state_changed = true; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (priv->pause != phydev->pause) { 41762306a36Sopenharmony_ci priv->pause = phydev->pause; 41862306a36Sopenharmony_ci state_changed = true; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci } else { 42162306a36Sopenharmony_ci if (priv->link) { 42262306a36Sopenharmony_ci priv->link = phydev->link; 42362306a36Sopenharmony_ci state_changed = true; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (state_changed) { 42862306a36Sopenharmony_ci if (phydev->link) 42962306a36Sopenharmony_ci owl_emac_update_link_state(priv); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (netif_msg_link(priv)) 43262306a36Sopenharmony_ci phy_print_status(phydev); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic irqreturn_t owl_emac_handle_irq(int irq, void *data) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct net_device *netdev = data; 43962306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (netif_running(netdev)) { 44262306a36Sopenharmony_ci owl_emac_irq_disable(priv); 44362306a36Sopenharmony_ci napi_schedule(&priv->napi); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci return IRQ_HANDLED; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic void owl_emac_ether_addr_push(u8 **dst, const u8 *src) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci u32 *a = (u32 *)(*dst); 45262306a36Sopenharmony_ci const u16 *b = (const u16 *)src; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci a[0] = b[0]; 45562306a36Sopenharmony_ci a[1] = b[1]; 45662306a36Sopenharmony_ci a[2] = b[2]; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci *dst += 12; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void 46262306a36Sopenharmony_ciowl_emac_setup_frame_prepare(struct owl_emac_priv *priv, struct sk_buff *skb) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci const u8 bcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 46562306a36Sopenharmony_ci const u8 *mac_addr = priv->netdev->dev_addr; 46662306a36Sopenharmony_ci u8 *frame; 46762306a36Sopenharmony_ci int i; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci skb_put(skb, OWL_EMAC_SETUP_FRAME_LEN); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci frame = skb->data; 47262306a36Sopenharmony_ci memset(frame, 0, skb->len); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci owl_emac_ether_addr_push(&frame, mac_addr); 47562306a36Sopenharmony_ci owl_emac_ether_addr_push(&frame, bcast_addr); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* Fill multicast addresses. */ 47862306a36Sopenharmony_ci WARN_ON(priv->mcaddr_list.count >= OWL_EMAC_MAX_MULTICAST_ADDRS); 47962306a36Sopenharmony_ci for (i = 0; i < priv->mcaddr_list.count; i++) { 48062306a36Sopenharmony_ci mac_addr = priv->mcaddr_list.addrs[i]; 48162306a36Sopenharmony_ci owl_emac_ether_addr_push(&frame, mac_addr); 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci/* The setup frame is a special descriptor which is used to provide physical 48662306a36Sopenharmony_ci * addresses (i.e. mac, broadcast and multicast) to the MAC hardware for 48762306a36Sopenharmony_ci * filtering purposes. To be recognized as a setup frame, the TDES1_SET bit 48862306a36Sopenharmony_ci * must be set in the TX descriptor control field. 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_cistatic int owl_emac_setup_frame_xmit(struct owl_emac_priv *priv) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct owl_emac_ring *ring = &priv->tx_ring; 49362306a36Sopenharmony_ci struct net_device *netdev = priv->netdev; 49462306a36Sopenharmony_ci struct owl_emac_ring_desc *desc; 49562306a36Sopenharmony_ci struct sk_buff *skb; 49662306a36Sopenharmony_ci unsigned int tx_head; 49762306a36Sopenharmony_ci u32 status, control; 49862306a36Sopenharmony_ci dma_addr_t dma_addr; 49962306a36Sopenharmony_ci int ret; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci skb = owl_emac_alloc_skb(netdev); 50262306a36Sopenharmony_ci if (!skb) 50362306a36Sopenharmony_ci return -ENOMEM; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci owl_emac_setup_frame_prepare(priv, skb); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci dma_addr = owl_emac_dma_map_tx(priv, skb); 50862306a36Sopenharmony_ci if (dma_mapping_error(owl_emac_get_dev(priv), dma_addr)) { 50962306a36Sopenharmony_ci ret = -ENOMEM; 51062306a36Sopenharmony_ci goto err_free_skb; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci spin_lock_bh(&priv->lock); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci tx_head = ring->head; 51662306a36Sopenharmony_ci desc = &ring->descs[tx_head]; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci status = READ_ONCE(desc->status); 51962306a36Sopenharmony_ci control = READ_ONCE(desc->control); 52062306a36Sopenharmony_ci dma_rmb(); /* Ensure data has been read before used. */ 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (unlikely(status & OWL_EMAC_BIT_TDES0_OWN) || 52362306a36Sopenharmony_ci !owl_emac_ring_num_unused(ring)) { 52462306a36Sopenharmony_ci spin_unlock_bh(&priv->lock); 52562306a36Sopenharmony_ci owl_emac_dma_unmap_tx(priv, skb, dma_addr); 52662306a36Sopenharmony_ci ret = -EBUSY; 52762306a36Sopenharmony_ci goto err_free_skb; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci ring->skbs[tx_head] = skb; 53162306a36Sopenharmony_ci ring->skbs_dma[tx_head] = dma_addr; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci control &= OWL_EMAC_BIT_TDES1_IC | OWL_EMAC_BIT_TDES1_TER; /* Maintain bits */ 53462306a36Sopenharmony_ci control |= OWL_EMAC_BIT_TDES1_SET; 53562306a36Sopenharmony_ci control |= OWL_EMAC_MSK_TDES1_TBS1 & skb->len; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci WRITE_ONCE(desc->control, control); 53862306a36Sopenharmony_ci WRITE_ONCE(desc->buf_addr, dma_addr); 53962306a36Sopenharmony_ci dma_wmb(); /* Flush descriptor before changing ownership. */ 54062306a36Sopenharmony_ci WRITE_ONCE(desc->status, OWL_EMAC_BIT_TDES0_OWN); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci owl_emac_ring_push_head(ring); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* Temporarily enable DMA TX. */ 54562306a36Sopenharmony_ci status = owl_emac_dma_cmd_start_tx(priv); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Trigger setup frame processing. */ 54862306a36Sopenharmony_ci owl_emac_dma_cmd_resume_tx(priv); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* Restore DMA TX status. */ 55162306a36Sopenharmony_ci owl_emac_dma_cmd_set_tx(priv, status); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* Stop regular TX until setup frame is processed. */ 55462306a36Sopenharmony_ci netif_stop_queue(netdev); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci spin_unlock_bh(&priv->lock); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci return 0; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cierr_free_skb: 56162306a36Sopenharmony_ci dev_kfree_skb(skb); 56262306a36Sopenharmony_ci return ret; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic netdev_tx_t owl_emac_ndo_start_xmit(struct sk_buff *skb, 56662306a36Sopenharmony_ci struct net_device *netdev) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 56962306a36Sopenharmony_ci struct device *dev = owl_emac_get_dev(priv); 57062306a36Sopenharmony_ci struct owl_emac_ring *ring = &priv->tx_ring; 57162306a36Sopenharmony_ci struct owl_emac_ring_desc *desc; 57262306a36Sopenharmony_ci unsigned int tx_head; 57362306a36Sopenharmony_ci u32 status, control; 57462306a36Sopenharmony_ci dma_addr_t dma_addr; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci dma_addr = owl_emac_dma_map_tx(priv, skb); 57762306a36Sopenharmony_ci if (dma_mapping_error(dev, dma_addr)) { 57862306a36Sopenharmony_ci dev_err_ratelimited(&netdev->dev, "TX DMA mapping failed\n"); 57962306a36Sopenharmony_ci dev_kfree_skb(skb); 58062306a36Sopenharmony_ci netdev->stats.tx_dropped++; 58162306a36Sopenharmony_ci return NETDEV_TX_OK; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci spin_lock_bh(&priv->lock); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci tx_head = ring->head; 58762306a36Sopenharmony_ci desc = &ring->descs[tx_head]; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci status = READ_ONCE(desc->status); 59062306a36Sopenharmony_ci control = READ_ONCE(desc->control); 59162306a36Sopenharmony_ci dma_rmb(); /* Ensure data has been read before used. */ 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (!owl_emac_ring_num_unused(ring) || 59462306a36Sopenharmony_ci unlikely(status & OWL_EMAC_BIT_TDES0_OWN)) { 59562306a36Sopenharmony_ci netif_stop_queue(netdev); 59662306a36Sopenharmony_ci spin_unlock_bh(&priv->lock); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci dev_dbg_ratelimited(&netdev->dev, "TX buffer full, status=0x%08x\n", 59962306a36Sopenharmony_ci owl_emac_irq_status(priv)); 60062306a36Sopenharmony_ci owl_emac_dma_unmap_tx(priv, skb, dma_addr); 60162306a36Sopenharmony_ci netdev->stats.tx_dropped++; 60262306a36Sopenharmony_ci return NETDEV_TX_BUSY; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci ring->skbs[tx_head] = skb; 60662306a36Sopenharmony_ci ring->skbs_dma[tx_head] = dma_addr; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci control &= OWL_EMAC_BIT_TDES1_IC | OWL_EMAC_BIT_TDES1_TER; /* Maintain bits */ 60962306a36Sopenharmony_ci control |= OWL_EMAC_BIT_TDES1_FS | OWL_EMAC_BIT_TDES1_LS; 61062306a36Sopenharmony_ci control |= OWL_EMAC_MSK_TDES1_TBS1 & skb->len; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci WRITE_ONCE(desc->control, control); 61362306a36Sopenharmony_ci WRITE_ONCE(desc->buf_addr, dma_addr); 61462306a36Sopenharmony_ci dma_wmb(); /* Flush descriptor before changing ownership. */ 61562306a36Sopenharmony_ci WRITE_ONCE(desc->status, OWL_EMAC_BIT_TDES0_OWN); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci owl_emac_dma_cmd_resume_tx(priv); 61862306a36Sopenharmony_ci owl_emac_ring_push_head(ring); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* FIXME: The transmission is currently restricted to a single frame 62162306a36Sopenharmony_ci * at a time as a workaround for a MAC hardware bug that causes random 62262306a36Sopenharmony_ci * freeze of the TX queue processor. 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_ci netif_stop_queue(netdev); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci spin_unlock_bh(&priv->lock); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci return NETDEV_TX_OK; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic bool owl_emac_tx_complete_tail(struct owl_emac_priv *priv) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci struct owl_emac_ring *ring = &priv->tx_ring; 63462306a36Sopenharmony_ci struct net_device *netdev = priv->netdev; 63562306a36Sopenharmony_ci struct owl_emac_ring_desc *desc; 63662306a36Sopenharmony_ci struct sk_buff *skb; 63762306a36Sopenharmony_ci unsigned int tx_tail; 63862306a36Sopenharmony_ci u32 status; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci tx_tail = ring->tail; 64162306a36Sopenharmony_ci desc = &ring->descs[tx_tail]; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci status = READ_ONCE(desc->status); 64462306a36Sopenharmony_ci dma_rmb(); /* Ensure data has been read before used. */ 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_TDES0_OWN) 64762306a36Sopenharmony_ci return false; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* Check for errors. */ 65062306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_TDES0_ES) { 65162306a36Sopenharmony_ci dev_dbg_ratelimited(&netdev->dev, 65262306a36Sopenharmony_ci "TX complete error status: 0x%08x\n", 65362306a36Sopenharmony_ci status); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci netdev->stats.tx_errors++; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_TDES0_UF) 65862306a36Sopenharmony_ci netdev->stats.tx_fifo_errors++; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_TDES0_EC) 66162306a36Sopenharmony_ci netdev->stats.tx_aborted_errors++; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_TDES0_LC) 66462306a36Sopenharmony_ci netdev->stats.tx_window_errors++; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_TDES0_NC) 66762306a36Sopenharmony_ci netdev->stats.tx_heartbeat_errors++; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_TDES0_LO) 67062306a36Sopenharmony_ci netdev->stats.tx_carrier_errors++; 67162306a36Sopenharmony_ci } else { 67262306a36Sopenharmony_ci netdev->stats.tx_packets++; 67362306a36Sopenharmony_ci netdev->stats.tx_bytes += ring->skbs[tx_tail]->len; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* Some collisions occurred, but pkt has been transmitted. */ 67762306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_TDES0_DE) 67862306a36Sopenharmony_ci netdev->stats.collisions++; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci skb = ring->skbs[tx_tail]; 68162306a36Sopenharmony_ci owl_emac_dma_unmap_tx(priv, skb, ring->skbs_dma[tx_tail]); 68262306a36Sopenharmony_ci dev_kfree_skb(skb); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci ring->skbs[tx_tail] = NULL; 68562306a36Sopenharmony_ci ring->skbs_dma[tx_tail] = 0; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci owl_emac_ring_pop_tail(ring); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (unlikely(netif_queue_stopped(netdev))) 69062306a36Sopenharmony_ci netif_wake_queue(netdev); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci return true; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic void owl_emac_tx_complete(struct owl_emac_priv *priv) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct owl_emac_ring *ring = &priv->tx_ring; 69862306a36Sopenharmony_ci struct net_device *netdev = priv->netdev; 69962306a36Sopenharmony_ci unsigned int tx_next; 70062306a36Sopenharmony_ci u32 status; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci spin_lock(&priv->lock); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci while (ring->tail != ring->head) { 70562306a36Sopenharmony_ci if (!owl_emac_tx_complete_tail(priv)) 70662306a36Sopenharmony_ci break; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci /* FIXME: This is a workaround for a MAC hardware bug not clearing 71062306a36Sopenharmony_ci * (sometimes) the OWN bit for a transmitted frame descriptor. 71162306a36Sopenharmony_ci * 71262306a36Sopenharmony_ci * At this point, when TX queue is full, the tail descriptor has the 71362306a36Sopenharmony_ci * OWN bit set, which normally means the frame has not been processed 71462306a36Sopenharmony_ci * or transmitted yet. But if there is at least one descriptor in the 71562306a36Sopenharmony_ci * queue having the OWN bit cleared, we can safely assume the tail 71662306a36Sopenharmony_ci * frame has been also processed by the MAC hardware. 71762306a36Sopenharmony_ci * 71862306a36Sopenharmony_ci * If that's the case, let's force the frame completion by manually 71962306a36Sopenharmony_ci * clearing the OWN bit. 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci if (unlikely(!owl_emac_ring_num_unused(ring))) { 72262306a36Sopenharmony_ci tx_next = ring->tail; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci while ((tx_next = owl_emac_ring_get_next(ring, tx_next)) != ring->head) { 72562306a36Sopenharmony_ci status = READ_ONCE(ring->descs[tx_next].status); 72662306a36Sopenharmony_ci dma_rmb(); /* Ensure data has been read before used. */ 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_TDES0_OWN) 72962306a36Sopenharmony_ci continue; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci netdev_dbg(netdev, "Found uncleared TX desc OWN bit\n"); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci status = READ_ONCE(ring->descs[ring->tail].status); 73462306a36Sopenharmony_ci dma_rmb(); /* Ensure data has been read before used. */ 73562306a36Sopenharmony_ci status &= ~OWL_EMAC_BIT_TDES0_OWN; 73662306a36Sopenharmony_ci WRITE_ONCE(ring->descs[ring->tail].status, status); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci owl_emac_tx_complete_tail(priv); 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci spin_unlock(&priv->lock); 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic int owl_emac_rx_process(struct owl_emac_priv *priv, int budget) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci struct owl_emac_ring *ring = &priv->rx_ring; 74962306a36Sopenharmony_ci struct device *dev = owl_emac_get_dev(priv); 75062306a36Sopenharmony_ci struct net_device *netdev = priv->netdev; 75162306a36Sopenharmony_ci struct owl_emac_ring_desc *desc; 75262306a36Sopenharmony_ci struct sk_buff *curr_skb, *new_skb; 75362306a36Sopenharmony_ci dma_addr_t curr_dma, new_dma; 75462306a36Sopenharmony_ci unsigned int rx_tail, len; 75562306a36Sopenharmony_ci u32 status; 75662306a36Sopenharmony_ci int recv = 0; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci while (recv < budget) { 75962306a36Sopenharmony_ci spin_lock(&priv->lock); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci rx_tail = ring->tail; 76262306a36Sopenharmony_ci desc = &ring->descs[rx_tail]; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci status = READ_ONCE(desc->status); 76562306a36Sopenharmony_ci dma_rmb(); /* Ensure data has been read before used. */ 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_RDES0_OWN) { 76862306a36Sopenharmony_ci spin_unlock(&priv->lock); 76962306a36Sopenharmony_ci break; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci curr_skb = ring->skbs[rx_tail]; 77362306a36Sopenharmony_ci curr_dma = ring->skbs_dma[rx_tail]; 77462306a36Sopenharmony_ci owl_emac_ring_pop_tail(ring); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci spin_unlock(&priv->lock); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (status & (OWL_EMAC_BIT_RDES0_DE | OWL_EMAC_BIT_RDES0_RF | 77962306a36Sopenharmony_ci OWL_EMAC_BIT_RDES0_TL | OWL_EMAC_BIT_RDES0_CS | 78062306a36Sopenharmony_ci OWL_EMAC_BIT_RDES0_DB | OWL_EMAC_BIT_RDES0_CE | 78162306a36Sopenharmony_ci OWL_EMAC_BIT_RDES0_ZERO)) { 78262306a36Sopenharmony_ci dev_dbg_ratelimited(&netdev->dev, 78362306a36Sopenharmony_ci "RX desc error status: 0x%08x\n", 78462306a36Sopenharmony_ci status); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_RDES0_DE) 78762306a36Sopenharmony_ci netdev->stats.rx_over_errors++; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (status & (OWL_EMAC_BIT_RDES0_RF | OWL_EMAC_BIT_RDES0_DB)) 79062306a36Sopenharmony_ci netdev->stats.rx_frame_errors++; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_RDES0_TL) 79362306a36Sopenharmony_ci netdev->stats.rx_length_errors++; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_RDES0_CS) 79662306a36Sopenharmony_ci netdev->stats.collisions++; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_RDES0_CE) 79962306a36Sopenharmony_ci netdev->stats.rx_crc_errors++; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_RDES0_ZERO) 80262306a36Sopenharmony_ci netdev->stats.rx_fifo_errors++; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci goto drop_skb; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci len = (status & OWL_EMAC_MSK_RDES0_FL) >> OWL_EMAC_OFF_RDES0_FL; 80862306a36Sopenharmony_ci if (unlikely(len > OWL_EMAC_RX_FRAME_MAX_LEN)) { 80962306a36Sopenharmony_ci netdev->stats.rx_length_errors++; 81062306a36Sopenharmony_ci netdev_err(netdev, "invalid RX frame len: %u\n", len); 81162306a36Sopenharmony_ci goto drop_skb; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* Prepare new skb before receiving the current one. */ 81562306a36Sopenharmony_ci new_skb = owl_emac_alloc_skb(netdev); 81662306a36Sopenharmony_ci if (unlikely(!new_skb)) 81762306a36Sopenharmony_ci goto drop_skb; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci new_dma = owl_emac_dma_map_rx(priv, new_skb); 82062306a36Sopenharmony_ci if (dma_mapping_error(dev, new_dma)) { 82162306a36Sopenharmony_ci dev_kfree_skb(new_skb); 82262306a36Sopenharmony_ci netdev_err(netdev, "RX DMA mapping failed\n"); 82362306a36Sopenharmony_ci goto drop_skb; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci owl_emac_dma_unmap_rx(priv, curr_skb, curr_dma); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci skb_put(curr_skb, len - ETH_FCS_LEN); 82962306a36Sopenharmony_ci curr_skb->ip_summed = CHECKSUM_NONE; 83062306a36Sopenharmony_ci curr_skb->protocol = eth_type_trans(curr_skb, netdev); 83162306a36Sopenharmony_ci curr_skb->dev = netdev; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci netif_receive_skb(curr_skb); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci netdev->stats.rx_packets++; 83662306a36Sopenharmony_ci netdev->stats.rx_bytes += len; 83762306a36Sopenharmony_ci recv++; 83862306a36Sopenharmony_ci goto push_skb; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cidrop_skb: 84162306a36Sopenharmony_ci netdev->stats.rx_dropped++; 84262306a36Sopenharmony_ci netdev->stats.rx_errors++; 84362306a36Sopenharmony_ci /* Reuse the current skb. */ 84462306a36Sopenharmony_ci new_skb = curr_skb; 84562306a36Sopenharmony_ci new_dma = curr_dma; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cipush_skb: 84862306a36Sopenharmony_ci spin_lock(&priv->lock); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci ring->skbs[ring->head] = new_skb; 85162306a36Sopenharmony_ci ring->skbs_dma[ring->head] = new_dma; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci WRITE_ONCE(desc->buf_addr, new_dma); 85462306a36Sopenharmony_ci dma_wmb(); /* Flush descriptor before changing ownership. */ 85562306a36Sopenharmony_ci WRITE_ONCE(desc->status, OWL_EMAC_BIT_RDES0_OWN); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci owl_emac_ring_push_head(ring); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci spin_unlock(&priv->lock); 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return recv; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic int owl_emac_poll(struct napi_struct *napi, int budget) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci int work_done = 0, ru_cnt = 0, recv; 86862306a36Sopenharmony_ci static int tx_err_cnt, rx_err_cnt; 86962306a36Sopenharmony_ci struct owl_emac_priv *priv; 87062306a36Sopenharmony_ci u32 status, proc_status; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci priv = container_of(napi, struct owl_emac_priv, napi); 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci while ((status = owl_emac_irq_clear(priv)) & 87562306a36Sopenharmony_ci (OWL_EMAC_BIT_MAC_CSR5_NIS | OWL_EMAC_BIT_MAC_CSR5_AIS)) { 87662306a36Sopenharmony_ci recv = 0; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci /* TX setup frame raises ETI instead of TI. */ 87962306a36Sopenharmony_ci if (status & (OWL_EMAC_BIT_MAC_CSR5_TI | OWL_EMAC_BIT_MAC_CSR5_ETI)) { 88062306a36Sopenharmony_ci owl_emac_tx_complete(priv); 88162306a36Sopenharmony_ci tx_err_cnt = 0; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* Count MAC internal RX errors. */ 88462306a36Sopenharmony_ci proc_status = status & OWL_EMAC_MSK_MAC_CSR5_RS; 88562306a36Sopenharmony_ci proc_status >>= OWL_EMAC_OFF_MAC_CSR5_RS; 88662306a36Sopenharmony_ci if (proc_status == OWL_EMAC_VAL_MAC_CSR5_RS_DATA || 88762306a36Sopenharmony_ci proc_status == OWL_EMAC_VAL_MAC_CSR5_RS_CDES || 88862306a36Sopenharmony_ci proc_status == OWL_EMAC_VAL_MAC_CSR5_RS_FDES) 88962306a36Sopenharmony_ci rx_err_cnt++; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (status & OWL_EMAC_BIT_MAC_CSR5_RI) { 89362306a36Sopenharmony_ci recv = owl_emac_rx_process(priv, budget - work_done); 89462306a36Sopenharmony_ci rx_err_cnt = 0; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* Count MAC internal TX errors. */ 89762306a36Sopenharmony_ci proc_status = status & OWL_EMAC_MSK_MAC_CSR5_TS; 89862306a36Sopenharmony_ci proc_status >>= OWL_EMAC_OFF_MAC_CSR5_TS; 89962306a36Sopenharmony_ci if (proc_status == OWL_EMAC_VAL_MAC_CSR5_TS_DATA || 90062306a36Sopenharmony_ci proc_status == OWL_EMAC_VAL_MAC_CSR5_TS_CDES) 90162306a36Sopenharmony_ci tx_err_cnt++; 90262306a36Sopenharmony_ci } else if (status & OWL_EMAC_BIT_MAC_CSR5_RU) { 90362306a36Sopenharmony_ci /* MAC AHB is in suspended state, will return to RX 90462306a36Sopenharmony_ci * descriptor processing when the host changes ownership 90562306a36Sopenharmony_ci * of the descriptor and either an RX poll demand CMD is 90662306a36Sopenharmony_ci * issued or a new frame is recognized by the MAC AHB. 90762306a36Sopenharmony_ci */ 90862306a36Sopenharmony_ci if (++ru_cnt == 2) 90962306a36Sopenharmony_ci owl_emac_dma_cmd_resume_rx(priv); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci recv = owl_emac_rx_process(priv, budget - work_done); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /* Guard against too many RU interrupts. */ 91462306a36Sopenharmony_ci if (ru_cnt > 3) 91562306a36Sopenharmony_ci break; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci work_done += recv; 91962306a36Sopenharmony_ci if (work_done >= budget) 92062306a36Sopenharmony_ci break; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (work_done < budget) { 92462306a36Sopenharmony_ci napi_complete_done(napi, work_done); 92562306a36Sopenharmony_ci owl_emac_irq_enable(priv); 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* Reset MAC when getting too many internal TX or RX errors. */ 92962306a36Sopenharmony_ci if (tx_err_cnt > 10 || rx_err_cnt > 10) { 93062306a36Sopenharmony_ci netdev_dbg(priv->netdev, "%s error status: 0x%08x\n", 93162306a36Sopenharmony_ci tx_err_cnt > 10 ? "TX" : "RX", status); 93262306a36Sopenharmony_ci rx_err_cnt = 0; 93362306a36Sopenharmony_ci tx_err_cnt = 0; 93462306a36Sopenharmony_ci schedule_work(&priv->mac_reset_task); 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci return work_done; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic void owl_emac_mdio_clock_enable(struct owl_emac_priv *priv) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci u32 val; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* Enable MDC clock generation by adjusting CLKDIV according to 94562306a36Sopenharmony_ci * the vendor implementation of the original driver. 94662306a36Sopenharmony_ci */ 94762306a36Sopenharmony_ci val = owl_emac_reg_read(priv, OWL_EMAC_REG_MAC_CSR10); 94862306a36Sopenharmony_ci val &= OWL_EMAC_MSK_MAC_CSR10_CLKDIV; 94962306a36Sopenharmony_ci val |= OWL_EMAC_VAL_MAC_CSR10_CLKDIV_128 << OWL_EMAC_OFF_MAC_CSR10_CLKDIV; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci val |= OWL_EMAC_BIT_MAC_CSR10_SB; 95262306a36Sopenharmony_ci val |= OWL_EMAC_VAL_MAC_CSR10_OPCODE_CDS << OWL_EMAC_OFF_MAC_CSR10_OPCODE; 95362306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR10, val); 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic void owl_emac_core_hw_reset(struct owl_emac_priv *priv) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci /* Trigger hardware reset. */ 95962306a36Sopenharmony_ci reset_control_assert(priv->reset); 96062306a36Sopenharmony_ci usleep_range(10, 20); 96162306a36Sopenharmony_ci reset_control_deassert(priv->reset); 96262306a36Sopenharmony_ci usleep_range(100, 200); 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic int owl_emac_core_sw_reset(struct owl_emac_priv *priv) 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci u32 val; 96862306a36Sopenharmony_ci int ret; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* Trigger software reset. */ 97162306a36Sopenharmony_ci owl_emac_reg_set(priv, OWL_EMAC_REG_MAC_CSR0, OWL_EMAC_BIT_MAC_CSR0_SWR); 97262306a36Sopenharmony_ci ret = readl_poll_timeout(priv->base + OWL_EMAC_REG_MAC_CSR0, 97362306a36Sopenharmony_ci val, !(val & OWL_EMAC_BIT_MAC_CSR0_SWR), 97462306a36Sopenharmony_ci OWL_EMAC_POLL_DELAY_USEC, 97562306a36Sopenharmony_ci OWL_EMAC_RESET_POLL_TIMEOUT_USEC); 97662306a36Sopenharmony_ci if (ret) 97762306a36Sopenharmony_ci return ret; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if (priv->phy_mode == PHY_INTERFACE_MODE_RMII) { 98062306a36Sopenharmony_ci /* Enable RMII and use the 50MHz rmii clk as output to PHY. */ 98162306a36Sopenharmony_ci val = 0; 98262306a36Sopenharmony_ci } else { 98362306a36Sopenharmony_ci /* Enable SMII and use the 125MHz rmii clk as output to PHY. 98462306a36Sopenharmony_ci * Additionally set SMII SYNC delay to 4 half cycle. 98562306a36Sopenharmony_ci */ 98662306a36Sopenharmony_ci val = 0x04 << OWL_EMAC_OFF_MAC_CTRL_SSDC; 98762306a36Sopenharmony_ci val |= OWL_EMAC_BIT_MAC_CTRL_RSIS; 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CTRL, val); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci /* MDC is disabled after reset. */ 99262306a36Sopenharmony_ci owl_emac_mdio_clock_enable(priv); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* Set FIFO pause & restart threshold levels. */ 99562306a36Sopenharmony_ci val = 0x40 << OWL_EMAC_OFF_MAC_CSR19_FPTL; 99662306a36Sopenharmony_ci val |= 0x10 << OWL_EMAC_OFF_MAC_CSR19_FRTL; 99762306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR19, val); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* Set flow control pause quanta time to ~100 ms. */ 100062306a36Sopenharmony_ci val = 0x4FFF << OWL_EMAC_OFF_MAC_CSR18_PQT; 100162306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR18, val); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* Setup interrupt mitigation. */ 100462306a36Sopenharmony_ci val = 7 << OWL_EMAC_OFF_MAC_CSR11_NRP; 100562306a36Sopenharmony_ci val |= 4 << OWL_EMAC_OFF_MAC_CSR11_RT; 100662306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR11, val); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci /* Set RX/TX rings base addresses. */ 100962306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR3, 101062306a36Sopenharmony_ci (u32)(priv->rx_ring.descs_dma)); 101162306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR4, 101262306a36Sopenharmony_ci (u32)(priv->tx_ring.descs_dma)); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci /* Setup initial operation mode. */ 101562306a36Sopenharmony_ci val = OWL_EMAC_VAL_MAC_CSR6_SPEED_100M << OWL_EMAC_OFF_MAC_CSR6_SPEED; 101662306a36Sopenharmony_ci val |= OWL_EMAC_BIT_MAC_CSR6_FD; 101762306a36Sopenharmony_ci owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6, 101862306a36Sopenharmony_ci OWL_EMAC_MSK_MAC_CSR6_SPEED | 101962306a36Sopenharmony_ci OWL_EMAC_BIT_MAC_CSR6_FD, val); 102062306a36Sopenharmony_ci owl_emac_reg_clear(priv, OWL_EMAC_REG_MAC_CSR6, 102162306a36Sopenharmony_ci OWL_EMAC_BIT_MAC_CSR6_PR | OWL_EMAC_BIT_MAC_CSR6_PM); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci priv->link = 0; 102462306a36Sopenharmony_ci priv->speed = SPEED_UNKNOWN; 102562306a36Sopenharmony_ci priv->duplex = DUPLEX_UNKNOWN; 102662306a36Sopenharmony_ci priv->pause = 0; 102762306a36Sopenharmony_ci priv->mcaddr_list.count = 0; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci return 0; 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic int owl_emac_enable(struct net_device *netdev, bool start_phy) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 103562306a36Sopenharmony_ci int ret; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci owl_emac_dma_cmd_stop(priv); 103862306a36Sopenharmony_ci owl_emac_irq_disable(priv); 103962306a36Sopenharmony_ci owl_emac_irq_clear(priv); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci owl_emac_ring_prepare_tx(priv); 104262306a36Sopenharmony_ci ret = owl_emac_ring_prepare_rx(priv); 104362306a36Sopenharmony_ci if (ret) 104462306a36Sopenharmony_ci goto err_unprep; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci ret = owl_emac_core_sw_reset(priv); 104762306a36Sopenharmony_ci if (ret) { 104862306a36Sopenharmony_ci netdev_err(netdev, "failed to soft reset MAC core: %d\n", ret); 104962306a36Sopenharmony_ci goto err_unprep; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci owl_emac_set_hw_mac_addr(netdev); 105362306a36Sopenharmony_ci owl_emac_setup_frame_xmit(priv); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci netdev_reset_queue(netdev); 105662306a36Sopenharmony_ci napi_enable(&priv->napi); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci owl_emac_irq_enable(priv); 105962306a36Sopenharmony_ci owl_emac_dma_cmd_start(priv); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (start_phy) 106262306a36Sopenharmony_ci phy_start(netdev->phydev); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci netif_start_queue(netdev); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci return 0; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cierr_unprep: 106962306a36Sopenharmony_ci owl_emac_ring_unprepare_rx(priv); 107062306a36Sopenharmony_ci owl_emac_ring_unprepare_tx(priv); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci return ret; 107362306a36Sopenharmony_ci} 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_cistatic void owl_emac_disable(struct net_device *netdev, bool stop_phy) 107662306a36Sopenharmony_ci{ 107762306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci owl_emac_dma_cmd_stop(priv); 108062306a36Sopenharmony_ci owl_emac_irq_disable(priv); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci netif_stop_queue(netdev); 108362306a36Sopenharmony_ci napi_disable(&priv->napi); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (stop_phy) 108662306a36Sopenharmony_ci phy_stop(netdev->phydev); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci owl_emac_ring_unprepare_rx(priv); 108962306a36Sopenharmony_ci owl_emac_ring_unprepare_tx(priv); 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic int owl_emac_ndo_open(struct net_device *netdev) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci return owl_emac_enable(netdev, true); 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic int owl_emac_ndo_stop(struct net_device *netdev) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci owl_emac_disable(netdev, true); 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci return 0; 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistatic void owl_emac_set_multicast(struct net_device *netdev, int count) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 110762306a36Sopenharmony_ci struct netdev_hw_addr *ha; 110862306a36Sopenharmony_ci int index = 0; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (count <= 0) { 111162306a36Sopenharmony_ci priv->mcaddr_list.count = 0; 111262306a36Sopenharmony_ci return; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) { 111662306a36Sopenharmony_ci if (!is_multicast_ether_addr(ha->addr)) 111762306a36Sopenharmony_ci continue; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci WARN_ON(index >= OWL_EMAC_MAX_MULTICAST_ADDRS); 112062306a36Sopenharmony_ci ether_addr_copy(priv->mcaddr_list.addrs[index++], ha->addr); 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci priv->mcaddr_list.count = index; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci owl_emac_setup_frame_xmit(priv); 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cistatic void owl_emac_ndo_set_rx_mode(struct net_device *netdev) 112962306a36Sopenharmony_ci{ 113062306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 113162306a36Sopenharmony_ci u32 status, val = 0; 113262306a36Sopenharmony_ci int mcast_count = 0; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (netdev->flags & IFF_PROMISC) { 113562306a36Sopenharmony_ci val = OWL_EMAC_BIT_MAC_CSR6_PR; 113662306a36Sopenharmony_ci } else if (netdev->flags & IFF_ALLMULTI) { 113762306a36Sopenharmony_ci val = OWL_EMAC_BIT_MAC_CSR6_PM; 113862306a36Sopenharmony_ci } else if (netdev->flags & IFF_MULTICAST) { 113962306a36Sopenharmony_ci mcast_count = netdev_mc_count(netdev); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci if (mcast_count > OWL_EMAC_MAX_MULTICAST_ADDRS) { 114262306a36Sopenharmony_ci val = OWL_EMAC_BIT_MAC_CSR6_PM; 114362306a36Sopenharmony_ci mcast_count = 0; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci spin_lock_bh(&priv->lock); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci /* Temporarily stop DMA TX & RX. */ 115062306a36Sopenharmony_ci status = owl_emac_dma_cmd_stop(priv); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci /* Update operation modes. */ 115362306a36Sopenharmony_ci owl_emac_reg_update(priv, OWL_EMAC_REG_MAC_CSR6, 115462306a36Sopenharmony_ci OWL_EMAC_BIT_MAC_CSR6_PR | OWL_EMAC_BIT_MAC_CSR6_PM, 115562306a36Sopenharmony_ci val); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci /* Restore DMA TX & RX status. */ 115862306a36Sopenharmony_ci owl_emac_dma_cmd_set(priv, status); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci spin_unlock_bh(&priv->lock); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci /* Set/reset multicast addr list. */ 116362306a36Sopenharmony_ci owl_emac_set_multicast(netdev, mcast_count); 116462306a36Sopenharmony_ci} 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cistatic int owl_emac_ndo_set_mac_addr(struct net_device *netdev, void *addr) 116762306a36Sopenharmony_ci{ 116862306a36Sopenharmony_ci struct sockaddr *skaddr = addr; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci if (!is_valid_ether_addr(skaddr->sa_data)) 117162306a36Sopenharmony_ci return -EADDRNOTAVAIL; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (netif_running(netdev)) 117462306a36Sopenharmony_ci return -EBUSY; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci eth_hw_addr_set(netdev, skaddr->sa_data); 117762306a36Sopenharmony_ci owl_emac_set_hw_mac_addr(netdev); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci return owl_emac_setup_frame_xmit(netdev_priv(netdev)); 118062306a36Sopenharmony_ci} 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_cistatic int owl_emac_ndo_eth_ioctl(struct net_device *netdev, 118362306a36Sopenharmony_ci struct ifreq *req, int cmd) 118462306a36Sopenharmony_ci{ 118562306a36Sopenharmony_ci if (!netif_running(netdev)) 118662306a36Sopenharmony_ci return -EINVAL; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci return phy_mii_ioctl(netdev->phydev, req, cmd); 118962306a36Sopenharmony_ci} 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_cistatic void owl_emac_ndo_tx_timeout(struct net_device *netdev, 119262306a36Sopenharmony_ci unsigned int txqueue) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci schedule_work(&priv->mac_reset_task); 119762306a36Sopenharmony_ci} 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic void owl_emac_reset_task(struct work_struct *work) 120062306a36Sopenharmony_ci{ 120162306a36Sopenharmony_ci struct owl_emac_priv *priv; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci priv = container_of(work, struct owl_emac_priv, mac_reset_task); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci netdev_dbg(priv->netdev, "resetting MAC\n"); 120662306a36Sopenharmony_ci owl_emac_disable(priv->netdev, false); 120762306a36Sopenharmony_ci owl_emac_enable(priv->netdev, false); 120862306a36Sopenharmony_ci} 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_cistatic struct net_device_stats * 121162306a36Sopenharmony_ciowl_emac_ndo_get_stats(struct net_device *netdev) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci /* FIXME: If possible, try to get stats from MAC hardware registers 121462306a36Sopenharmony_ci * instead of tracking them manually in the driver. 121562306a36Sopenharmony_ci */ 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci return &netdev->stats; 121862306a36Sopenharmony_ci} 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_cistatic const struct net_device_ops owl_emac_netdev_ops = { 122162306a36Sopenharmony_ci .ndo_open = owl_emac_ndo_open, 122262306a36Sopenharmony_ci .ndo_stop = owl_emac_ndo_stop, 122362306a36Sopenharmony_ci .ndo_start_xmit = owl_emac_ndo_start_xmit, 122462306a36Sopenharmony_ci .ndo_set_rx_mode = owl_emac_ndo_set_rx_mode, 122562306a36Sopenharmony_ci .ndo_set_mac_address = owl_emac_ndo_set_mac_addr, 122662306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 122762306a36Sopenharmony_ci .ndo_eth_ioctl = owl_emac_ndo_eth_ioctl, 122862306a36Sopenharmony_ci .ndo_tx_timeout = owl_emac_ndo_tx_timeout, 122962306a36Sopenharmony_ci .ndo_get_stats = owl_emac_ndo_get_stats, 123062306a36Sopenharmony_ci}; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_cistatic void owl_emac_ethtool_get_drvinfo(struct net_device *dev, 123362306a36Sopenharmony_ci struct ethtool_drvinfo *info) 123462306a36Sopenharmony_ci{ 123562306a36Sopenharmony_ci strscpy(info->driver, OWL_EMAC_DRVNAME, sizeof(info->driver)); 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_cistatic u32 owl_emac_ethtool_get_msglevel(struct net_device *netdev) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci return priv->msg_enable; 124362306a36Sopenharmony_ci} 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_cistatic void owl_emac_ethtool_set_msglevel(struct net_device *ndev, u32 val) 124662306a36Sopenharmony_ci{ 124762306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(ndev); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci priv->msg_enable = val; 125062306a36Sopenharmony_ci} 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_cistatic const struct ethtool_ops owl_emac_ethtool_ops = { 125362306a36Sopenharmony_ci .get_drvinfo = owl_emac_ethtool_get_drvinfo, 125462306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 125562306a36Sopenharmony_ci .get_link_ksettings = phy_ethtool_get_link_ksettings, 125662306a36Sopenharmony_ci .set_link_ksettings = phy_ethtool_set_link_ksettings, 125762306a36Sopenharmony_ci .get_msglevel = owl_emac_ethtool_get_msglevel, 125862306a36Sopenharmony_ci .set_msglevel = owl_emac_ethtool_set_msglevel, 125962306a36Sopenharmony_ci}; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_cistatic int owl_emac_mdio_wait(struct owl_emac_priv *priv) 126262306a36Sopenharmony_ci{ 126362306a36Sopenharmony_ci u32 val; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci /* Wait while data transfer is in progress. */ 126662306a36Sopenharmony_ci return readl_poll_timeout(priv->base + OWL_EMAC_REG_MAC_CSR10, 126762306a36Sopenharmony_ci val, !(val & OWL_EMAC_BIT_MAC_CSR10_SB), 126862306a36Sopenharmony_ci OWL_EMAC_POLL_DELAY_USEC, 126962306a36Sopenharmony_ci OWL_EMAC_MDIO_POLL_TIMEOUT_USEC); 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_cistatic int owl_emac_mdio_read(struct mii_bus *bus, int addr, int regnum) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci struct owl_emac_priv *priv = bus->priv; 127562306a36Sopenharmony_ci u32 data, tmp; 127662306a36Sopenharmony_ci int ret; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci data = OWL_EMAC_BIT_MAC_CSR10_SB; 127962306a36Sopenharmony_ci data |= OWL_EMAC_VAL_MAC_CSR10_OPCODE_RD << OWL_EMAC_OFF_MAC_CSR10_OPCODE; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci tmp = addr << OWL_EMAC_OFF_MAC_CSR10_PHYADD; 128262306a36Sopenharmony_ci data |= tmp & OWL_EMAC_MSK_MAC_CSR10_PHYADD; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci tmp = regnum << OWL_EMAC_OFF_MAC_CSR10_REGADD; 128562306a36Sopenharmony_ci data |= tmp & OWL_EMAC_MSK_MAC_CSR10_REGADD; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR10, data); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci ret = owl_emac_mdio_wait(priv); 129062306a36Sopenharmony_ci if (ret) 129162306a36Sopenharmony_ci return ret; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci data = owl_emac_reg_read(priv, OWL_EMAC_REG_MAC_CSR10); 129462306a36Sopenharmony_ci data &= OWL_EMAC_MSK_MAC_CSR10_DATA; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci return data; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic int 130062306a36Sopenharmony_ciowl_emac_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci struct owl_emac_priv *priv = bus->priv; 130362306a36Sopenharmony_ci u32 data, tmp; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci data = OWL_EMAC_BIT_MAC_CSR10_SB; 130662306a36Sopenharmony_ci data |= OWL_EMAC_VAL_MAC_CSR10_OPCODE_WR << OWL_EMAC_OFF_MAC_CSR10_OPCODE; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci tmp = addr << OWL_EMAC_OFF_MAC_CSR10_PHYADD; 130962306a36Sopenharmony_ci data |= tmp & OWL_EMAC_MSK_MAC_CSR10_PHYADD; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci tmp = regnum << OWL_EMAC_OFF_MAC_CSR10_REGADD; 131262306a36Sopenharmony_ci data |= tmp & OWL_EMAC_MSK_MAC_CSR10_REGADD; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci data |= val & OWL_EMAC_MSK_MAC_CSR10_DATA; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci owl_emac_reg_write(priv, OWL_EMAC_REG_MAC_CSR10, data); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci return owl_emac_mdio_wait(priv); 131962306a36Sopenharmony_ci} 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_cistatic int owl_emac_mdio_init(struct net_device *netdev) 132262306a36Sopenharmony_ci{ 132362306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 132462306a36Sopenharmony_ci struct device *dev = owl_emac_get_dev(priv); 132562306a36Sopenharmony_ci struct device_node *mdio_node; 132662306a36Sopenharmony_ci int ret; 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci mdio_node = of_get_child_by_name(dev->of_node, "mdio"); 132962306a36Sopenharmony_ci if (!mdio_node) 133062306a36Sopenharmony_ci return -ENODEV; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci if (!of_device_is_available(mdio_node)) { 133362306a36Sopenharmony_ci ret = -ENODEV; 133462306a36Sopenharmony_ci goto err_put_node; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci priv->mii = devm_mdiobus_alloc(dev); 133862306a36Sopenharmony_ci if (!priv->mii) { 133962306a36Sopenharmony_ci ret = -ENOMEM; 134062306a36Sopenharmony_ci goto err_put_node; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci snprintf(priv->mii->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); 134462306a36Sopenharmony_ci priv->mii->name = "owl-emac-mdio"; 134562306a36Sopenharmony_ci priv->mii->parent = dev; 134662306a36Sopenharmony_ci priv->mii->read = owl_emac_mdio_read; 134762306a36Sopenharmony_ci priv->mii->write = owl_emac_mdio_write; 134862306a36Sopenharmony_ci priv->mii->phy_mask = ~0; /* Mask out all PHYs from auto probing. */ 134962306a36Sopenharmony_ci priv->mii->priv = priv; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci ret = devm_of_mdiobus_register(dev, priv->mii, mdio_node); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cierr_put_node: 135462306a36Sopenharmony_ci of_node_put(mdio_node); 135562306a36Sopenharmony_ci return ret; 135662306a36Sopenharmony_ci} 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_cistatic int owl_emac_phy_init(struct net_device *netdev) 135962306a36Sopenharmony_ci{ 136062306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 136162306a36Sopenharmony_ci struct device *dev = owl_emac_get_dev(priv); 136262306a36Sopenharmony_ci struct phy_device *phy; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci phy = of_phy_get_and_connect(netdev, dev->of_node, 136562306a36Sopenharmony_ci owl_emac_adjust_link); 136662306a36Sopenharmony_ci if (!phy) 136762306a36Sopenharmony_ci return -ENODEV; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci phy_set_sym_pause(phy, true, true, true); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci if (netif_msg_link(priv)) 137262306a36Sopenharmony_ci phy_attached_info(phy); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci return 0; 137562306a36Sopenharmony_ci} 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_cistatic void owl_emac_get_mac_addr(struct net_device *netdev) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci struct device *dev = netdev->dev.parent; 138062306a36Sopenharmony_ci int ret; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci ret = platform_get_ethdev_address(dev, netdev); 138362306a36Sopenharmony_ci if (!ret && is_valid_ether_addr(netdev->dev_addr)) 138462306a36Sopenharmony_ci return; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci eth_hw_addr_random(netdev); 138762306a36Sopenharmony_ci dev_warn(dev, "using random MAC address %pM\n", netdev->dev_addr); 138862306a36Sopenharmony_ci} 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_cistatic __maybe_unused int owl_emac_suspend(struct device *dev) 139162306a36Sopenharmony_ci{ 139262306a36Sopenharmony_ci struct net_device *netdev = dev_get_drvdata(dev); 139362306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci disable_irq(netdev->irq); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (netif_running(netdev)) { 139862306a36Sopenharmony_ci owl_emac_disable(netdev, true); 139962306a36Sopenharmony_ci netif_device_detach(netdev); 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci clk_bulk_disable_unprepare(OWL_EMAC_NCLKS, priv->clks); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci return 0; 140562306a36Sopenharmony_ci} 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_cistatic __maybe_unused int owl_emac_resume(struct device *dev) 140862306a36Sopenharmony_ci{ 140962306a36Sopenharmony_ci struct net_device *netdev = dev_get_drvdata(dev); 141062306a36Sopenharmony_ci struct owl_emac_priv *priv = netdev_priv(netdev); 141162306a36Sopenharmony_ci int ret; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci ret = clk_bulk_prepare_enable(OWL_EMAC_NCLKS, priv->clks); 141462306a36Sopenharmony_ci if (ret) 141562306a36Sopenharmony_ci return ret; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci if (netif_running(netdev)) { 141862306a36Sopenharmony_ci owl_emac_core_hw_reset(priv); 141962306a36Sopenharmony_ci owl_emac_core_sw_reset(priv); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci ret = owl_emac_enable(netdev, true); 142262306a36Sopenharmony_ci if (ret) { 142362306a36Sopenharmony_ci clk_bulk_disable_unprepare(OWL_EMAC_NCLKS, priv->clks); 142462306a36Sopenharmony_ci return ret; 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci netif_device_attach(netdev); 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci enable_irq(netdev->irq); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci return 0; 143362306a36Sopenharmony_ci} 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_cistatic void owl_emac_clk_disable_unprepare(void *data) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci struct owl_emac_priv *priv = data; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci clk_bulk_disable_unprepare(OWL_EMAC_NCLKS, priv->clks); 144062306a36Sopenharmony_ci} 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_cistatic int owl_emac_clk_set_rate(struct owl_emac_priv *priv) 144362306a36Sopenharmony_ci{ 144462306a36Sopenharmony_ci struct device *dev = owl_emac_get_dev(priv); 144562306a36Sopenharmony_ci unsigned long rate; 144662306a36Sopenharmony_ci int ret; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci switch (priv->phy_mode) { 144962306a36Sopenharmony_ci case PHY_INTERFACE_MODE_RMII: 145062306a36Sopenharmony_ci rate = 50000000; 145162306a36Sopenharmony_ci break; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci case PHY_INTERFACE_MODE_SMII: 145462306a36Sopenharmony_ci rate = 125000000; 145562306a36Sopenharmony_ci break; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci default: 145862306a36Sopenharmony_ci dev_err(dev, "unsupported phy interface mode %d\n", 145962306a36Sopenharmony_ci priv->phy_mode); 146062306a36Sopenharmony_ci return -EOPNOTSUPP; 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci ret = clk_set_rate(priv->clks[OWL_EMAC_CLK_RMII].clk, rate); 146462306a36Sopenharmony_ci if (ret) 146562306a36Sopenharmony_ci dev_err(dev, "failed to set RMII clock rate: %d\n", ret); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci return ret; 146862306a36Sopenharmony_ci} 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_cistatic int owl_emac_probe(struct platform_device *pdev) 147162306a36Sopenharmony_ci{ 147262306a36Sopenharmony_ci struct device *dev = &pdev->dev; 147362306a36Sopenharmony_ci struct net_device *netdev; 147462306a36Sopenharmony_ci struct owl_emac_priv *priv; 147562306a36Sopenharmony_ci int ret, i; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci netdev = devm_alloc_etherdev(dev, sizeof(*priv)); 147862306a36Sopenharmony_ci if (!netdev) 147962306a36Sopenharmony_ci return -ENOMEM; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci platform_set_drvdata(pdev, netdev); 148262306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, dev); 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci priv = netdev_priv(netdev); 148562306a36Sopenharmony_ci priv->netdev = netdev; 148662306a36Sopenharmony_ci priv->msg_enable = netif_msg_init(-1, OWL_EMAC_DEFAULT_MSG_ENABLE); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci ret = of_get_phy_mode(dev->of_node, &priv->phy_mode); 148962306a36Sopenharmony_ci if (ret) { 149062306a36Sopenharmony_ci dev_err(dev, "failed to get phy mode: %d\n", ret); 149162306a36Sopenharmony_ci return ret; 149262306a36Sopenharmony_ci } 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci spin_lock_init(&priv->lock); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 149762306a36Sopenharmony_ci if (ret) { 149862306a36Sopenharmony_ci dev_err(dev, "unsupported DMA mask\n"); 149962306a36Sopenharmony_ci return ret; 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci ret = owl_emac_ring_alloc(dev, &priv->rx_ring, OWL_EMAC_RX_RING_SIZE); 150362306a36Sopenharmony_ci if (ret) 150462306a36Sopenharmony_ci return ret; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci ret = owl_emac_ring_alloc(dev, &priv->tx_ring, OWL_EMAC_TX_RING_SIZE); 150762306a36Sopenharmony_ci if (ret) 150862306a36Sopenharmony_ci return ret; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci priv->base = devm_platform_ioremap_resource(pdev, 0); 151162306a36Sopenharmony_ci if (IS_ERR(priv->base)) 151262306a36Sopenharmony_ci return PTR_ERR(priv->base); 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci netdev->irq = platform_get_irq(pdev, 0); 151562306a36Sopenharmony_ci if (netdev->irq < 0) 151662306a36Sopenharmony_ci return netdev->irq; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci ret = devm_request_irq(dev, netdev->irq, owl_emac_handle_irq, 151962306a36Sopenharmony_ci IRQF_SHARED, netdev->name, netdev); 152062306a36Sopenharmony_ci if (ret) { 152162306a36Sopenharmony_ci dev_err(dev, "failed to request irq: %d\n", netdev->irq); 152262306a36Sopenharmony_ci return ret; 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci for (i = 0; i < OWL_EMAC_NCLKS; i++) 152662306a36Sopenharmony_ci priv->clks[i].id = owl_emac_clk_names[i]; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci ret = devm_clk_bulk_get(dev, OWL_EMAC_NCLKS, priv->clks); 152962306a36Sopenharmony_ci if (ret) 153062306a36Sopenharmony_ci return ret; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci ret = clk_bulk_prepare_enable(OWL_EMAC_NCLKS, priv->clks); 153362306a36Sopenharmony_ci if (ret) 153462306a36Sopenharmony_ci return ret; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, owl_emac_clk_disable_unprepare, priv); 153762306a36Sopenharmony_ci if (ret) 153862306a36Sopenharmony_ci return ret; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci ret = owl_emac_clk_set_rate(priv); 154162306a36Sopenharmony_ci if (ret) 154262306a36Sopenharmony_ci return ret; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci priv->reset = devm_reset_control_get_exclusive(dev, NULL); 154562306a36Sopenharmony_ci if (IS_ERR(priv->reset)) 154662306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(priv->reset), 154762306a36Sopenharmony_ci "failed to get reset control"); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci owl_emac_get_mac_addr(netdev); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci owl_emac_core_hw_reset(priv); 155262306a36Sopenharmony_ci owl_emac_mdio_clock_enable(priv); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci ret = owl_emac_mdio_init(netdev); 155562306a36Sopenharmony_ci if (ret) { 155662306a36Sopenharmony_ci dev_err(dev, "failed to initialize MDIO bus\n"); 155762306a36Sopenharmony_ci return ret; 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci ret = owl_emac_phy_init(netdev); 156162306a36Sopenharmony_ci if (ret) { 156262306a36Sopenharmony_ci dev_err(dev, "failed to initialize PHY\n"); 156362306a36Sopenharmony_ci return ret; 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci INIT_WORK(&priv->mac_reset_task, owl_emac_reset_task); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci netdev->min_mtu = OWL_EMAC_MTU_MIN; 156962306a36Sopenharmony_ci netdev->max_mtu = OWL_EMAC_MTU_MAX; 157062306a36Sopenharmony_ci netdev->watchdog_timeo = OWL_EMAC_TX_TIMEOUT; 157162306a36Sopenharmony_ci netdev->netdev_ops = &owl_emac_netdev_ops; 157262306a36Sopenharmony_ci netdev->ethtool_ops = &owl_emac_ethtool_ops; 157362306a36Sopenharmony_ci netif_napi_add(netdev, &priv->napi, owl_emac_poll); 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci ret = devm_register_netdev(dev, netdev); 157662306a36Sopenharmony_ci if (ret) { 157762306a36Sopenharmony_ci netif_napi_del(&priv->napi); 157862306a36Sopenharmony_ci phy_disconnect(netdev->phydev); 157962306a36Sopenharmony_ci return ret; 158062306a36Sopenharmony_ci } 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci return 0; 158362306a36Sopenharmony_ci} 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_cistatic int owl_emac_remove(struct platform_device *pdev) 158662306a36Sopenharmony_ci{ 158762306a36Sopenharmony_ci struct owl_emac_priv *priv = platform_get_drvdata(pdev); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci netif_napi_del(&priv->napi); 159062306a36Sopenharmony_ci phy_disconnect(priv->netdev->phydev); 159162306a36Sopenharmony_ci cancel_work_sync(&priv->mac_reset_task); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci return 0; 159462306a36Sopenharmony_ci} 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_cistatic const struct of_device_id owl_emac_of_match[] = { 159762306a36Sopenharmony_ci { .compatible = "actions,owl-emac", }, 159862306a36Sopenharmony_ci { } 159962306a36Sopenharmony_ci}; 160062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, owl_emac_of_match); 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(owl_emac_pm_ops, 160362306a36Sopenharmony_ci owl_emac_suspend, owl_emac_resume); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cistatic struct platform_driver owl_emac_driver = { 160662306a36Sopenharmony_ci .driver = { 160762306a36Sopenharmony_ci .name = OWL_EMAC_DRVNAME, 160862306a36Sopenharmony_ci .of_match_table = owl_emac_of_match, 160962306a36Sopenharmony_ci .pm = &owl_emac_pm_ops, 161062306a36Sopenharmony_ci }, 161162306a36Sopenharmony_ci .probe = owl_emac_probe, 161262306a36Sopenharmony_ci .remove = owl_emac_remove, 161362306a36Sopenharmony_ci}; 161462306a36Sopenharmony_cimodule_platform_driver(owl_emac_driver); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ciMODULE_DESCRIPTION("Actions Semi Owl SoCs Ethernet MAC Driver"); 161762306a36Sopenharmony_ciMODULE_AUTHOR("Actions Semi Inc."); 161862306a36Sopenharmony_ciMODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>"); 161962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1620