162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Applied Micro X-Gene SoC Ethernet v2 Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2017, Applied Micro Circuits Corporation 662306a36Sopenharmony_ci * Author(s): Iyappan Subramanian <isubramanian@apm.com> 762306a36Sopenharmony_ci * Keyur Chudgar <kchudgar@apm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "main.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic const struct acpi_device_id xge_acpi_match[]; 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic int xge_get_resources(struct xge_pdata *pdata) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci struct platform_device *pdev; 1762306a36Sopenharmony_ci struct net_device *ndev; 1862306a36Sopenharmony_ci int phy_mode, ret = 0; 1962306a36Sopenharmony_ci struct resource *res; 2062306a36Sopenharmony_ci struct device *dev; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci pdev = pdata->pdev; 2362306a36Sopenharmony_ci dev = &pdev->dev; 2462306a36Sopenharmony_ci ndev = pdata->ndev; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2762306a36Sopenharmony_ci if (!res) { 2862306a36Sopenharmony_ci dev_err(dev, "Resource enet_csr not defined\n"); 2962306a36Sopenharmony_ci return -ENODEV; 3062306a36Sopenharmony_ci } 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci pdata->resources.base_addr = devm_ioremap(dev, res->start, 3362306a36Sopenharmony_ci resource_size(res)); 3462306a36Sopenharmony_ci if (!pdata->resources.base_addr) { 3562306a36Sopenharmony_ci dev_err(dev, "Unable to retrieve ENET Port CSR region\n"); 3662306a36Sopenharmony_ci return -ENOMEM; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (device_get_ethdev_address(dev, ndev)) 4062306a36Sopenharmony_ci eth_hw_addr_random(ndev); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci phy_mode = device_get_phy_mode(dev); 4562306a36Sopenharmony_ci if (phy_mode < 0) { 4662306a36Sopenharmony_ci dev_err(dev, "Unable to get phy-connection-type\n"); 4762306a36Sopenharmony_ci return phy_mode; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci pdata->resources.phy_mode = phy_mode; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (pdata->resources.phy_mode != PHY_INTERFACE_MODE_RGMII) { 5262306a36Sopenharmony_ci dev_err(dev, "Incorrect phy-connection-type specified\n"); 5362306a36Sopenharmony_ci return -ENODEV; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci ret = platform_get_irq(pdev, 0); 5762306a36Sopenharmony_ci if (ret < 0) 5862306a36Sopenharmony_ci return ret; 5962306a36Sopenharmony_ci pdata->resources.irq = ret; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int xge_refill_buffers(struct net_device *ndev, u32 nbuf) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 6762306a36Sopenharmony_ci struct xge_desc_ring *ring = pdata->rx_ring; 6862306a36Sopenharmony_ci const u8 slots = XGENE_ENET_NUM_DESC - 1; 6962306a36Sopenharmony_ci struct device *dev = &pdata->pdev->dev; 7062306a36Sopenharmony_ci struct xge_raw_desc *raw_desc; 7162306a36Sopenharmony_ci u64 addr_lo, addr_hi; 7262306a36Sopenharmony_ci u8 tail = ring->tail; 7362306a36Sopenharmony_ci struct sk_buff *skb; 7462306a36Sopenharmony_ci dma_addr_t dma_addr; 7562306a36Sopenharmony_ci u16 len; 7662306a36Sopenharmony_ci int i; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci for (i = 0; i < nbuf; i++) { 7962306a36Sopenharmony_ci raw_desc = &ring->raw_desc[tail]; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci len = XGENE_ENET_STD_MTU; 8262306a36Sopenharmony_ci skb = netdev_alloc_skb(ndev, len); 8362306a36Sopenharmony_ci if (unlikely(!skb)) 8462306a36Sopenharmony_ci return -ENOMEM; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci dma_addr = dma_map_single(dev, skb->data, len, DMA_FROM_DEVICE); 8762306a36Sopenharmony_ci if (dma_mapping_error(dev, dma_addr)) { 8862306a36Sopenharmony_ci netdev_err(ndev, "DMA mapping error\n"); 8962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 9062306a36Sopenharmony_ci return -EINVAL; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci ring->pkt_info[tail].skb = skb; 9462306a36Sopenharmony_ci ring->pkt_info[tail].dma_addr = dma_addr; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci addr_hi = GET_BITS(NEXT_DESC_ADDRH, le64_to_cpu(raw_desc->m1)); 9762306a36Sopenharmony_ci addr_lo = GET_BITS(NEXT_DESC_ADDRL, le64_to_cpu(raw_desc->m1)); 9862306a36Sopenharmony_ci raw_desc->m1 = cpu_to_le64(SET_BITS(NEXT_DESC_ADDRL, addr_lo) | 9962306a36Sopenharmony_ci SET_BITS(NEXT_DESC_ADDRH, addr_hi) | 10062306a36Sopenharmony_ci SET_BITS(PKT_ADDRH, 10162306a36Sopenharmony_ci upper_32_bits(dma_addr))); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci dma_wmb(); 10462306a36Sopenharmony_ci raw_desc->m0 = cpu_to_le64(SET_BITS(PKT_ADDRL, dma_addr) | 10562306a36Sopenharmony_ci SET_BITS(E, 1)); 10662306a36Sopenharmony_ci tail = (tail + 1) & slots; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci ring->tail = tail; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int xge_init_hw(struct net_device *ndev) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 11762306a36Sopenharmony_ci int ret; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci ret = xge_port_reset(ndev); 12062306a36Sopenharmony_ci if (ret) 12162306a36Sopenharmony_ci return ret; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci xge_port_init(ndev); 12462306a36Sopenharmony_ci pdata->nbufs = NUM_BUFS; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return 0; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic irqreturn_t xge_irq(const int irq, void *data) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct xge_pdata *pdata = data; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (napi_schedule_prep(&pdata->napi)) { 13462306a36Sopenharmony_ci xge_intr_disable(pdata); 13562306a36Sopenharmony_ci __napi_schedule(&pdata->napi); 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return IRQ_HANDLED; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int xge_request_irq(struct net_device *ndev) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 14462306a36Sopenharmony_ci int ret; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci snprintf(pdata->irq_name, IRQ_ID_SIZE, "%s", ndev->name); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci ret = request_irq(pdata->resources.irq, xge_irq, 0, pdata->irq_name, 14962306a36Sopenharmony_ci pdata); 15062306a36Sopenharmony_ci if (ret) 15162306a36Sopenharmony_ci netdev_err(ndev, "Failed to request irq %s\n", pdata->irq_name); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return ret; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void xge_free_irq(struct net_device *ndev) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci free_irq(pdata->resources.irq, pdata); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic bool is_tx_slot_available(struct xge_raw_desc *raw_desc) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci if (GET_BITS(E, le64_to_cpu(raw_desc->m0)) && 16662306a36Sopenharmony_ci (GET_BITS(PKT_SIZE, le64_to_cpu(raw_desc->m0)) == SLOT_EMPTY)) 16762306a36Sopenharmony_ci return true; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return false; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic netdev_tx_t xge_start_xmit(struct sk_buff *skb, struct net_device *ndev) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 17562306a36Sopenharmony_ci struct device *dev = &pdata->pdev->dev; 17662306a36Sopenharmony_ci struct xge_desc_ring *tx_ring; 17762306a36Sopenharmony_ci struct xge_raw_desc *raw_desc; 17862306a36Sopenharmony_ci static dma_addr_t dma_addr; 17962306a36Sopenharmony_ci u64 addr_lo, addr_hi; 18062306a36Sopenharmony_ci void *pkt_buf; 18162306a36Sopenharmony_ci u8 tail; 18262306a36Sopenharmony_ci u16 len; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci tx_ring = pdata->tx_ring; 18562306a36Sopenharmony_ci tail = tx_ring->tail; 18662306a36Sopenharmony_ci len = skb_headlen(skb); 18762306a36Sopenharmony_ci raw_desc = &tx_ring->raw_desc[tail]; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (!is_tx_slot_available(raw_desc)) { 19062306a36Sopenharmony_ci netif_stop_queue(ndev); 19162306a36Sopenharmony_ci return NETDEV_TX_BUSY; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* Packet buffers should be 64B aligned */ 19562306a36Sopenharmony_ci pkt_buf = dma_alloc_coherent(dev, XGENE_ENET_STD_MTU, &dma_addr, 19662306a36Sopenharmony_ci GFP_ATOMIC); 19762306a36Sopenharmony_ci if (unlikely(!pkt_buf)) { 19862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 19962306a36Sopenharmony_ci return NETDEV_TX_OK; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci memcpy(pkt_buf, skb->data, len); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci addr_hi = GET_BITS(NEXT_DESC_ADDRH, le64_to_cpu(raw_desc->m1)); 20462306a36Sopenharmony_ci addr_lo = GET_BITS(NEXT_DESC_ADDRL, le64_to_cpu(raw_desc->m1)); 20562306a36Sopenharmony_ci raw_desc->m1 = cpu_to_le64(SET_BITS(NEXT_DESC_ADDRL, addr_lo) | 20662306a36Sopenharmony_ci SET_BITS(NEXT_DESC_ADDRH, addr_hi) | 20762306a36Sopenharmony_ci SET_BITS(PKT_ADDRH, 20862306a36Sopenharmony_ci upper_32_bits(dma_addr))); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci tx_ring->pkt_info[tail].skb = skb; 21162306a36Sopenharmony_ci tx_ring->pkt_info[tail].dma_addr = dma_addr; 21262306a36Sopenharmony_ci tx_ring->pkt_info[tail].pkt_buf = pkt_buf; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci dma_wmb(); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci raw_desc->m0 = cpu_to_le64(SET_BITS(PKT_ADDRL, dma_addr) | 21762306a36Sopenharmony_ci SET_BITS(PKT_SIZE, len) | 21862306a36Sopenharmony_ci SET_BITS(E, 0)); 21962306a36Sopenharmony_ci skb_tx_timestamp(skb); 22062306a36Sopenharmony_ci xge_wr_csr(pdata, DMATXCTRL, 1); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci tx_ring->tail = (tail + 1) & (XGENE_ENET_NUM_DESC - 1); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return NETDEV_TX_OK; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic bool is_tx_hw_done(struct xge_raw_desc *raw_desc) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci if (GET_BITS(E, le64_to_cpu(raw_desc->m0)) && 23062306a36Sopenharmony_ci !GET_BITS(PKT_SIZE, le64_to_cpu(raw_desc->m0))) 23162306a36Sopenharmony_ci return true; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return false; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void xge_txc_poll(struct net_device *ndev) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 23962306a36Sopenharmony_ci struct device *dev = &pdata->pdev->dev; 24062306a36Sopenharmony_ci struct xge_desc_ring *tx_ring; 24162306a36Sopenharmony_ci struct xge_raw_desc *raw_desc; 24262306a36Sopenharmony_ci dma_addr_t dma_addr; 24362306a36Sopenharmony_ci struct sk_buff *skb; 24462306a36Sopenharmony_ci void *pkt_buf; 24562306a36Sopenharmony_ci u32 data; 24662306a36Sopenharmony_ci u8 head; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci tx_ring = pdata->tx_ring; 24962306a36Sopenharmony_ci head = tx_ring->head; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci data = xge_rd_csr(pdata, DMATXSTATUS); 25262306a36Sopenharmony_ci if (!GET_BITS(TXPKTCOUNT, data)) 25362306a36Sopenharmony_ci return; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci while (1) { 25662306a36Sopenharmony_ci raw_desc = &tx_ring->raw_desc[head]; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!is_tx_hw_done(raw_desc)) 25962306a36Sopenharmony_ci break; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci dma_rmb(); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci skb = tx_ring->pkt_info[head].skb; 26462306a36Sopenharmony_ci dma_addr = tx_ring->pkt_info[head].dma_addr; 26562306a36Sopenharmony_ci pkt_buf = tx_ring->pkt_info[head].pkt_buf; 26662306a36Sopenharmony_ci pdata->stats.tx_packets++; 26762306a36Sopenharmony_ci pdata->stats.tx_bytes += skb->len; 26862306a36Sopenharmony_ci dma_free_coherent(dev, XGENE_ENET_STD_MTU, pkt_buf, dma_addr); 26962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* clear pktstart address and pktsize */ 27262306a36Sopenharmony_ci raw_desc->m0 = cpu_to_le64(SET_BITS(E, 1) | 27362306a36Sopenharmony_ci SET_BITS(PKT_SIZE, SLOT_EMPTY)); 27462306a36Sopenharmony_ci xge_wr_csr(pdata, DMATXSTATUS, 1); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci head = (head + 1) & (XGENE_ENET_NUM_DESC - 1); 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (netif_queue_stopped(ndev)) 28062306a36Sopenharmony_ci netif_wake_queue(ndev); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci tx_ring->head = head; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int xge_rx_poll(struct net_device *ndev, unsigned int budget) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 28862306a36Sopenharmony_ci struct device *dev = &pdata->pdev->dev; 28962306a36Sopenharmony_ci struct xge_desc_ring *rx_ring; 29062306a36Sopenharmony_ci struct xge_raw_desc *raw_desc; 29162306a36Sopenharmony_ci struct sk_buff *skb; 29262306a36Sopenharmony_ci dma_addr_t dma_addr; 29362306a36Sopenharmony_ci int processed = 0; 29462306a36Sopenharmony_ci u8 head, rx_error; 29562306a36Sopenharmony_ci int i, ret; 29662306a36Sopenharmony_ci u32 data; 29762306a36Sopenharmony_ci u16 len; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci rx_ring = pdata->rx_ring; 30062306a36Sopenharmony_ci head = rx_ring->head; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci data = xge_rd_csr(pdata, DMARXSTATUS); 30362306a36Sopenharmony_ci if (!GET_BITS(RXPKTCOUNT, data)) 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci for (i = 0; i < budget; i++) { 30762306a36Sopenharmony_ci raw_desc = &rx_ring->raw_desc[head]; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (GET_BITS(E, le64_to_cpu(raw_desc->m0))) 31062306a36Sopenharmony_ci break; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci dma_rmb(); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci skb = rx_ring->pkt_info[head].skb; 31562306a36Sopenharmony_ci rx_ring->pkt_info[head].skb = NULL; 31662306a36Sopenharmony_ci dma_addr = rx_ring->pkt_info[head].dma_addr; 31762306a36Sopenharmony_ci len = GET_BITS(PKT_SIZE, le64_to_cpu(raw_desc->m0)); 31862306a36Sopenharmony_ci dma_unmap_single(dev, dma_addr, XGENE_ENET_STD_MTU, 31962306a36Sopenharmony_ci DMA_FROM_DEVICE); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci rx_error = GET_BITS(D, le64_to_cpu(raw_desc->m2)); 32262306a36Sopenharmony_ci if (unlikely(rx_error)) { 32362306a36Sopenharmony_ci pdata->stats.rx_errors++; 32462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 32562306a36Sopenharmony_ci goto out; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci skb_put(skb, len); 32962306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, ndev); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci pdata->stats.rx_packets++; 33262306a36Sopenharmony_ci pdata->stats.rx_bytes += len; 33362306a36Sopenharmony_ci napi_gro_receive(&pdata->napi, skb); 33462306a36Sopenharmony_ciout: 33562306a36Sopenharmony_ci ret = xge_refill_buffers(ndev, 1); 33662306a36Sopenharmony_ci xge_wr_csr(pdata, DMARXSTATUS, 1); 33762306a36Sopenharmony_ci xge_wr_csr(pdata, DMARXCTRL, 1); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (ret) 34062306a36Sopenharmony_ci break; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci head = (head + 1) & (XGENE_ENET_NUM_DESC - 1); 34362306a36Sopenharmony_ci processed++; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci rx_ring->head = head; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return processed; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void xge_delete_desc_ring(struct net_device *ndev, 35262306a36Sopenharmony_ci struct xge_desc_ring *ring) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 35562306a36Sopenharmony_ci struct device *dev = &pdata->pdev->dev; 35662306a36Sopenharmony_ci u16 size; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (!ring) 35962306a36Sopenharmony_ci return; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci size = XGENE_ENET_DESC_SIZE * XGENE_ENET_NUM_DESC; 36262306a36Sopenharmony_ci if (ring->desc_addr) 36362306a36Sopenharmony_ci dma_free_coherent(dev, size, ring->desc_addr, ring->dma_addr); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci kfree(ring->pkt_info); 36662306a36Sopenharmony_ci kfree(ring); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic void xge_free_buffers(struct net_device *ndev) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 37262306a36Sopenharmony_ci struct xge_desc_ring *ring = pdata->rx_ring; 37362306a36Sopenharmony_ci struct device *dev = &pdata->pdev->dev; 37462306a36Sopenharmony_ci struct sk_buff *skb; 37562306a36Sopenharmony_ci dma_addr_t dma_addr; 37662306a36Sopenharmony_ci int i; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci for (i = 0; i < XGENE_ENET_NUM_DESC; i++) { 37962306a36Sopenharmony_ci skb = ring->pkt_info[i].skb; 38062306a36Sopenharmony_ci dma_addr = ring->pkt_info[i].dma_addr; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (!skb) 38362306a36Sopenharmony_ci continue; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci dma_unmap_single(dev, dma_addr, XGENE_ENET_STD_MTU, 38662306a36Sopenharmony_ci DMA_FROM_DEVICE); 38762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic void xge_delete_desc_rings(struct net_device *ndev) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci xge_txc_poll(ndev); 39662306a36Sopenharmony_ci xge_delete_desc_ring(ndev, pdata->tx_ring); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci xge_rx_poll(ndev, 64); 39962306a36Sopenharmony_ci xge_free_buffers(ndev); 40062306a36Sopenharmony_ci xge_delete_desc_ring(ndev, pdata->rx_ring); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic struct xge_desc_ring *xge_create_desc_ring(struct net_device *ndev) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 40662306a36Sopenharmony_ci struct device *dev = &pdata->pdev->dev; 40762306a36Sopenharmony_ci struct xge_desc_ring *ring; 40862306a36Sopenharmony_ci u16 size; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci ring = kzalloc(sizeof(*ring), GFP_KERNEL); 41162306a36Sopenharmony_ci if (!ring) 41262306a36Sopenharmony_ci return NULL; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci ring->ndev = ndev; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci size = XGENE_ENET_DESC_SIZE * XGENE_ENET_NUM_DESC; 41762306a36Sopenharmony_ci ring->desc_addr = dma_alloc_coherent(dev, size, &ring->dma_addr, 41862306a36Sopenharmony_ci GFP_KERNEL); 41962306a36Sopenharmony_ci if (!ring->desc_addr) 42062306a36Sopenharmony_ci goto err; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci ring->pkt_info = kcalloc(XGENE_ENET_NUM_DESC, sizeof(*ring->pkt_info), 42362306a36Sopenharmony_ci GFP_KERNEL); 42462306a36Sopenharmony_ci if (!ring->pkt_info) 42562306a36Sopenharmony_ci goto err; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci xge_setup_desc(ring); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci return ring; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cierr: 43262306a36Sopenharmony_ci xge_delete_desc_ring(ndev, ring); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return NULL; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int xge_create_desc_rings(struct net_device *ndev) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 44062306a36Sopenharmony_ci struct xge_desc_ring *ring; 44162306a36Sopenharmony_ci int ret; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* create tx ring */ 44462306a36Sopenharmony_ci ring = xge_create_desc_ring(ndev); 44562306a36Sopenharmony_ci if (!ring) 44662306a36Sopenharmony_ci goto err; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci pdata->tx_ring = ring; 44962306a36Sopenharmony_ci xge_update_tx_desc_addr(pdata); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* create rx ring */ 45262306a36Sopenharmony_ci ring = xge_create_desc_ring(ndev); 45362306a36Sopenharmony_ci if (!ring) 45462306a36Sopenharmony_ci goto err; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci pdata->rx_ring = ring; 45762306a36Sopenharmony_ci xge_update_rx_desc_addr(pdata); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci ret = xge_refill_buffers(ndev, XGENE_ENET_NUM_DESC); 46062306a36Sopenharmony_ci if (ret) 46162306a36Sopenharmony_ci goto err; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_cierr: 46562306a36Sopenharmony_ci xge_delete_desc_rings(ndev); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci return -ENOMEM; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int xge_open(struct net_device *ndev) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 47362306a36Sopenharmony_ci int ret; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci ret = xge_create_desc_rings(ndev); 47662306a36Sopenharmony_ci if (ret) 47762306a36Sopenharmony_ci return ret; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci napi_enable(&pdata->napi); 48062306a36Sopenharmony_ci ret = xge_request_irq(ndev); 48162306a36Sopenharmony_ci if (ret) 48262306a36Sopenharmony_ci return ret; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci xge_intr_enable(pdata); 48562306a36Sopenharmony_ci xge_wr_csr(pdata, DMARXCTRL, 1); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci phy_start(ndev->phydev); 48862306a36Sopenharmony_ci xge_mac_enable(pdata); 48962306a36Sopenharmony_ci netif_start_queue(ndev); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic int xge_close(struct net_device *ndev) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci netif_stop_queue(ndev); 49962306a36Sopenharmony_ci xge_mac_disable(pdata); 50062306a36Sopenharmony_ci phy_stop(ndev->phydev); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci xge_intr_disable(pdata); 50362306a36Sopenharmony_ci xge_free_irq(ndev); 50462306a36Sopenharmony_ci napi_disable(&pdata->napi); 50562306a36Sopenharmony_ci xge_delete_desc_rings(ndev); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return 0; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic int xge_napi(struct napi_struct *napi, const int budget) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct net_device *ndev = napi->dev; 51362306a36Sopenharmony_ci struct xge_pdata *pdata; 51462306a36Sopenharmony_ci int processed; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci pdata = netdev_priv(ndev); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci xge_txc_poll(ndev); 51962306a36Sopenharmony_ci processed = xge_rx_poll(ndev, budget); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (processed < budget) { 52262306a36Sopenharmony_ci napi_complete_done(napi, processed); 52362306a36Sopenharmony_ci xge_intr_enable(pdata); 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return processed; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int xge_set_mac_addr(struct net_device *ndev, void *addr) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 53262306a36Sopenharmony_ci int ret; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci ret = eth_mac_addr(ndev, addr); 53562306a36Sopenharmony_ci if (ret) 53662306a36Sopenharmony_ci return ret; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci xge_mac_set_station_addr(pdata); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return 0; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic bool is_tx_pending(struct xge_raw_desc *raw_desc) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci if (!GET_BITS(E, le64_to_cpu(raw_desc->m0))) 54662306a36Sopenharmony_ci return true; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return false; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic void xge_free_pending_skb(struct net_device *ndev) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 55462306a36Sopenharmony_ci struct device *dev = &pdata->pdev->dev; 55562306a36Sopenharmony_ci struct xge_desc_ring *tx_ring; 55662306a36Sopenharmony_ci struct xge_raw_desc *raw_desc; 55762306a36Sopenharmony_ci dma_addr_t dma_addr; 55862306a36Sopenharmony_ci struct sk_buff *skb; 55962306a36Sopenharmony_ci void *pkt_buf; 56062306a36Sopenharmony_ci int i; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci tx_ring = pdata->tx_ring; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci for (i = 0; i < XGENE_ENET_NUM_DESC; i++) { 56562306a36Sopenharmony_ci raw_desc = &tx_ring->raw_desc[i]; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (!is_tx_pending(raw_desc)) 56862306a36Sopenharmony_ci continue; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci skb = tx_ring->pkt_info[i].skb; 57162306a36Sopenharmony_ci dma_addr = tx_ring->pkt_info[i].dma_addr; 57262306a36Sopenharmony_ci pkt_buf = tx_ring->pkt_info[i].pkt_buf; 57362306a36Sopenharmony_ci dma_free_coherent(dev, XGENE_ENET_STD_MTU, pkt_buf, dma_addr); 57462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic void xge_timeout(struct net_device *ndev, unsigned int txqueue) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci rtnl_lock(); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (!netif_running(ndev)) 58562306a36Sopenharmony_ci goto out; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci netif_stop_queue(ndev); 58862306a36Sopenharmony_ci xge_intr_disable(pdata); 58962306a36Sopenharmony_ci napi_disable(&pdata->napi); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci xge_wr_csr(pdata, DMATXCTRL, 0); 59262306a36Sopenharmony_ci xge_txc_poll(ndev); 59362306a36Sopenharmony_ci xge_free_pending_skb(ndev); 59462306a36Sopenharmony_ci xge_wr_csr(pdata, DMATXSTATUS, ~0U); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci xge_setup_desc(pdata->tx_ring); 59762306a36Sopenharmony_ci xge_update_tx_desc_addr(pdata); 59862306a36Sopenharmony_ci xge_mac_init(pdata); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci napi_enable(&pdata->napi); 60162306a36Sopenharmony_ci xge_intr_enable(pdata); 60262306a36Sopenharmony_ci xge_mac_enable(pdata); 60362306a36Sopenharmony_ci netif_start_queue(ndev); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ciout: 60662306a36Sopenharmony_ci rtnl_unlock(); 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic void xge_get_stats64(struct net_device *ndev, 61062306a36Sopenharmony_ci struct rtnl_link_stats64 *storage) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct xge_pdata *pdata = netdev_priv(ndev); 61362306a36Sopenharmony_ci struct xge_stats *stats = &pdata->stats; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci storage->tx_packets += stats->tx_packets; 61662306a36Sopenharmony_ci storage->tx_bytes += stats->tx_bytes; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci storage->rx_packets += stats->rx_packets; 61962306a36Sopenharmony_ci storage->rx_bytes += stats->rx_bytes; 62062306a36Sopenharmony_ci storage->rx_errors += stats->rx_errors; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic const struct net_device_ops xgene_ndev_ops = { 62462306a36Sopenharmony_ci .ndo_open = xge_open, 62562306a36Sopenharmony_ci .ndo_stop = xge_close, 62662306a36Sopenharmony_ci .ndo_start_xmit = xge_start_xmit, 62762306a36Sopenharmony_ci .ndo_set_mac_address = xge_set_mac_addr, 62862306a36Sopenharmony_ci .ndo_tx_timeout = xge_timeout, 62962306a36Sopenharmony_ci .ndo_get_stats64 = xge_get_stats64, 63062306a36Sopenharmony_ci}; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic int xge_probe(struct platform_device *pdev) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 63562306a36Sopenharmony_ci struct net_device *ndev; 63662306a36Sopenharmony_ci struct xge_pdata *pdata; 63762306a36Sopenharmony_ci int ret; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci ndev = alloc_etherdev(sizeof(*pdata)); 64062306a36Sopenharmony_ci if (!ndev) 64162306a36Sopenharmony_ci return -ENOMEM; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci pdata = netdev_priv(ndev); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci pdata->pdev = pdev; 64662306a36Sopenharmony_ci pdata->ndev = ndev; 64762306a36Sopenharmony_ci SET_NETDEV_DEV(ndev, dev); 64862306a36Sopenharmony_ci platform_set_drvdata(pdev, pdata); 64962306a36Sopenharmony_ci ndev->netdev_ops = &xgene_ndev_ops; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci ndev->features |= NETIF_F_GSO | 65262306a36Sopenharmony_ci NETIF_F_GRO; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci ret = xge_get_resources(pdata); 65562306a36Sopenharmony_ci if (ret) 65662306a36Sopenharmony_ci goto err; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci ndev->hw_features = ndev->features; 65962306a36Sopenharmony_ci xge_set_ethtool_ops(ndev); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64)); 66262306a36Sopenharmony_ci if (ret) { 66362306a36Sopenharmony_ci netdev_err(ndev, "No usable DMA configuration\n"); 66462306a36Sopenharmony_ci goto err; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci ret = xge_init_hw(ndev); 66862306a36Sopenharmony_ci if (ret) 66962306a36Sopenharmony_ci goto err; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci ret = xge_mdio_config(ndev); 67262306a36Sopenharmony_ci if (ret) 67362306a36Sopenharmony_ci goto err; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci netif_napi_add(ndev, &pdata->napi, xge_napi); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci ret = register_netdev(ndev); 67862306a36Sopenharmony_ci if (ret) { 67962306a36Sopenharmony_ci netdev_err(ndev, "Failed to register netdev\n"); 68062306a36Sopenharmony_ci goto err_mdio_remove; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cierr_mdio_remove: 68662306a36Sopenharmony_ci xge_mdio_remove(ndev); 68762306a36Sopenharmony_cierr: 68862306a36Sopenharmony_ci free_netdev(ndev); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci return ret; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic int xge_remove(struct platform_device *pdev) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct xge_pdata *pdata; 69662306a36Sopenharmony_ci struct net_device *ndev; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci pdata = platform_get_drvdata(pdev); 69962306a36Sopenharmony_ci ndev = pdata->ndev; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci rtnl_lock(); 70262306a36Sopenharmony_ci if (netif_running(ndev)) 70362306a36Sopenharmony_ci dev_close(ndev); 70462306a36Sopenharmony_ci rtnl_unlock(); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci xge_mdio_remove(ndev); 70762306a36Sopenharmony_ci unregister_netdev(ndev); 70862306a36Sopenharmony_ci free_netdev(ndev); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci return 0; 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic void xge_shutdown(struct platform_device *pdev) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci struct xge_pdata *pdata; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci pdata = platform_get_drvdata(pdev); 71862306a36Sopenharmony_ci if (!pdata) 71962306a36Sopenharmony_ci return; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (!pdata->ndev) 72262306a36Sopenharmony_ci return; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci xge_remove(pdev); 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic const struct acpi_device_id xge_acpi_match[] = { 72862306a36Sopenharmony_ci { "APMC0D80" }, 72962306a36Sopenharmony_ci { } 73062306a36Sopenharmony_ci}; 73162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, xge_acpi_match); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic struct platform_driver xge_driver = { 73462306a36Sopenharmony_ci .driver = { 73562306a36Sopenharmony_ci .name = "xgene-enet-v2", 73662306a36Sopenharmony_ci .acpi_match_table = ACPI_PTR(xge_acpi_match), 73762306a36Sopenharmony_ci }, 73862306a36Sopenharmony_ci .probe = xge_probe, 73962306a36Sopenharmony_ci .remove = xge_remove, 74062306a36Sopenharmony_ci .shutdown = xge_shutdown, 74162306a36Sopenharmony_ci}; 74262306a36Sopenharmony_cimodule_platform_driver(xge_driver); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ciMODULE_DESCRIPTION("APM X-Gene SoC Ethernet v2 driver"); 74562306a36Sopenharmony_ciMODULE_AUTHOR("Iyappan Subramanian <isubramanian@apm.com>"); 74662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 747