18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* Copyright 2017-2019 NXP */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "enetc.h" 58c2ecf20Sopenharmony_ci#include <linux/tcp.h> 68c2ecf20Sopenharmony_ci#include <linux/udp.h> 78c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 88c2ecf20Sopenharmony_ci#include <net/pkt_sched.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* ENETC overhead: optional extension BD + 1 BD gap */ 118c2ecf20Sopenharmony_ci#define ENETC_TXBDS_NEEDED(val) ((val) + 2) 128c2ecf20Sopenharmony_ci/* max # of chained Tx BDs is 15, including head and extension BD */ 138c2ecf20Sopenharmony_ci#define ENETC_MAX_SKB_FRAGS 13 148c2ecf20Sopenharmony_ci#define ENETC_TXBDS_MAX_NEEDED ENETC_TXBDS_NEEDED(ENETC_MAX_SKB_FRAGS + 1) 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb, 178c2ecf20Sopenharmony_ci int active_offloads); 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cinetdev_tx_t enetc_xmit(struct sk_buff *skb, struct net_device *ndev) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 228c2ecf20Sopenharmony_ci struct enetc_bdr *tx_ring; 238c2ecf20Sopenharmony_ci int count; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci tx_ring = priv->tx_ring[skb->queue_mapping]; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci if (unlikely(skb_shinfo(skb)->nr_frags > ENETC_MAX_SKB_FRAGS)) 288c2ecf20Sopenharmony_ci if (unlikely(skb_linearize(skb))) 298c2ecf20Sopenharmony_ci goto drop_packet_err; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci count = skb_shinfo(skb)->nr_frags + 1; /* fragments + head */ 328c2ecf20Sopenharmony_ci if (enetc_bd_unused(tx_ring) < ENETC_TXBDS_NEEDED(count)) { 338c2ecf20Sopenharmony_ci netif_stop_subqueue(ndev, tx_ring->index); 348c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci enetc_lock_mdio(); 388c2ecf20Sopenharmony_ci count = enetc_map_tx_buffs(tx_ring, skb, priv->active_offloads); 398c2ecf20Sopenharmony_ci enetc_unlock_mdio(); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (unlikely(!count)) 428c2ecf20Sopenharmony_ci goto drop_packet_err; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (enetc_bd_unused(tx_ring) < ENETC_TXBDS_MAX_NEEDED) 458c2ecf20Sopenharmony_ci netif_stop_subqueue(ndev, tx_ring->index); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cidrop_packet_err: 508c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 518c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic bool enetc_tx_csum(struct sk_buff *skb, union enetc_tx_bd *txbd) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci int l3_start, l3_hsize; 578c2ecf20Sopenharmony_ci u16 l3_flags, l4_flags; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (skb->ip_summed != CHECKSUM_PARTIAL) 608c2ecf20Sopenharmony_ci return false; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci switch (skb->csum_offset) { 638c2ecf20Sopenharmony_ci case offsetof(struct tcphdr, check): 648c2ecf20Sopenharmony_ci l4_flags = ENETC_TXBD_L4_TCP; 658c2ecf20Sopenharmony_ci break; 668c2ecf20Sopenharmony_ci case offsetof(struct udphdr, check): 678c2ecf20Sopenharmony_ci l4_flags = ENETC_TXBD_L4_UDP; 688c2ecf20Sopenharmony_ci break; 698c2ecf20Sopenharmony_ci default: 708c2ecf20Sopenharmony_ci skb_checksum_help(skb); 718c2ecf20Sopenharmony_ci return false; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci l3_start = skb_network_offset(skb); 758c2ecf20Sopenharmony_ci l3_hsize = skb_network_header_len(skb); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci l3_flags = 0; 788c2ecf20Sopenharmony_ci if (skb->protocol == htons(ETH_P_IPV6)) 798c2ecf20Sopenharmony_ci l3_flags = ENETC_TXBD_L3_IPV6; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* write BD fields */ 828c2ecf20Sopenharmony_ci txbd->l3_csoff = enetc_txbd_l3_csoff(l3_start, l3_hsize, l3_flags); 838c2ecf20Sopenharmony_ci txbd->l4_csoff = l4_flags; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return true; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void enetc_unmap_tx_buff(struct enetc_bdr *tx_ring, 898c2ecf20Sopenharmony_ci struct enetc_tx_swbd *tx_swbd) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci if (tx_swbd->is_dma_page) 928c2ecf20Sopenharmony_ci dma_unmap_page(tx_ring->dev, tx_swbd->dma, 938c2ecf20Sopenharmony_ci tx_swbd->len, DMA_TO_DEVICE); 948c2ecf20Sopenharmony_ci else 958c2ecf20Sopenharmony_ci dma_unmap_single(tx_ring->dev, tx_swbd->dma, 968c2ecf20Sopenharmony_ci tx_swbd->len, DMA_TO_DEVICE); 978c2ecf20Sopenharmony_ci tx_swbd->dma = 0; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void enetc_free_tx_skb(struct enetc_bdr *tx_ring, 1018c2ecf20Sopenharmony_ci struct enetc_tx_swbd *tx_swbd) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci if (tx_swbd->dma) 1048c2ecf20Sopenharmony_ci enetc_unmap_tx_buff(tx_ring, tx_swbd); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (tx_swbd->skb) { 1078c2ecf20Sopenharmony_ci dev_kfree_skb_any(tx_swbd->skb); 1088c2ecf20Sopenharmony_ci tx_swbd->skb = NULL; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb, 1138c2ecf20Sopenharmony_ci int active_offloads) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct enetc_tx_swbd *tx_swbd; 1168c2ecf20Sopenharmony_ci skb_frag_t *frag; 1178c2ecf20Sopenharmony_ci int len = skb_headlen(skb); 1188c2ecf20Sopenharmony_ci union enetc_tx_bd temp_bd; 1198c2ecf20Sopenharmony_ci union enetc_tx_bd *txbd; 1208c2ecf20Sopenharmony_ci bool do_vlan, do_tstamp; 1218c2ecf20Sopenharmony_ci int i, count = 0; 1228c2ecf20Sopenharmony_ci unsigned int f; 1238c2ecf20Sopenharmony_ci dma_addr_t dma; 1248c2ecf20Sopenharmony_ci u8 flags = 0; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci i = tx_ring->next_to_use; 1278c2ecf20Sopenharmony_ci txbd = ENETC_TXBD(*tx_ring, i); 1288c2ecf20Sopenharmony_ci prefetchw(txbd); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci dma = dma_map_single(tx_ring->dev, skb->data, len, DMA_TO_DEVICE); 1318c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(tx_ring->dev, dma))) 1328c2ecf20Sopenharmony_ci goto dma_err; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci temp_bd.addr = cpu_to_le64(dma); 1358c2ecf20Sopenharmony_ci temp_bd.buf_len = cpu_to_le16(len); 1368c2ecf20Sopenharmony_ci temp_bd.lstatus = 0; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci tx_swbd = &tx_ring->tx_swbd[i]; 1398c2ecf20Sopenharmony_ci tx_swbd->dma = dma; 1408c2ecf20Sopenharmony_ci tx_swbd->len = len; 1418c2ecf20Sopenharmony_ci tx_swbd->is_dma_page = 0; 1428c2ecf20Sopenharmony_ci count++; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci do_vlan = skb_vlan_tag_present(skb); 1458c2ecf20Sopenharmony_ci do_tstamp = (active_offloads & ENETC_F_TX_TSTAMP) && 1468c2ecf20Sopenharmony_ci (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP); 1478c2ecf20Sopenharmony_ci tx_swbd->do_tstamp = do_tstamp; 1488c2ecf20Sopenharmony_ci tx_swbd->check_wb = tx_swbd->do_tstamp; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (do_vlan || do_tstamp) 1518c2ecf20Sopenharmony_ci flags |= ENETC_TXBD_FLAGS_EX; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (enetc_tx_csum(skb, &temp_bd)) 1548c2ecf20Sopenharmony_ci flags |= ENETC_TXBD_FLAGS_CSUM | ENETC_TXBD_FLAGS_L4CS; 1558c2ecf20Sopenharmony_ci else if (tx_ring->tsd_enable) 1568c2ecf20Sopenharmony_ci flags |= ENETC_TXBD_FLAGS_TSE | ENETC_TXBD_FLAGS_TXSTART; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* first BD needs frm_len and offload flags set */ 1598c2ecf20Sopenharmony_ci temp_bd.frm_len = cpu_to_le16(skb->len); 1608c2ecf20Sopenharmony_ci temp_bd.flags = flags; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (flags & ENETC_TXBD_FLAGS_TSE) { 1638c2ecf20Sopenharmony_ci u32 temp; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci temp = (skb->skb_mstamp_ns >> 5 & ENETC_TXBD_TXSTART_MASK) 1668c2ecf20Sopenharmony_ci | (flags << ENETC_TXBD_FLAGS_OFFSET); 1678c2ecf20Sopenharmony_ci temp_bd.txstart = cpu_to_le32(temp); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (flags & ENETC_TXBD_FLAGS_EX) { 1718c2ecf20Sopenharmony_ci u8 e_flags = 0; 1728c2ecf20Sopenharmony_ci *txbd = temp_bd; 1738c2ecf20Sopenharmony_ci enetc_clear_tx_bd(&temp_bd); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* add extension BD for VLAN and/or timestamping */ 1768c2ecf20Sopenharmony_ci flags = 0; 1778c2ecf20Sopenharmony_ci tx_swbd++; 1788c2ecf20Sopenharmony_ci txbd++; 1798c2ecf20Sopenharmony_ci i++; 1808c2ecf20Sopenharmony_ci if (unlikely(i == tx_ring->bd_count)) { 1818c2ecf20Sopenharmony_ci i = 0; 1828c2ecf20Sopenharmony_ci tx_swbd = tx_ring->tx_swbd; 1838c2ecf20Sopenharmony_ci txbd = ENETC_TXBD(*tx_ring, 0); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci prefetchw(txbd); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (do_vlan) { 1888c2ecf20Sopenharmony_ci temp_bd.ext.vid = cpu_to_le16(skb_vlan_tag_get(skb)); 1898c2ecf20Sopenharmony_ci temp_bd.ext.tpid = 0; /* < C-TAG */ 1908c2ecf20Sopenharmony_ci e_flags |= ENETC_TXBD_E_FLAGS_VLAN_INS; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (do_tstamp) { 1948c2ecf20Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 1958c2ecf20Sopenharmony_ci e_flags |= ENETC_TXBD_E_FLAGS_TWO_STEP_PTP; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci temp_bd.ext.e_flags = e_flags; 1998c2ecf20Sopenharmony_ci count++; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci frag = &skb_shinfo(skb)->frags[0]; 2038c2ecf20Sopenharmony_ci for (f = 0; f < skb_shinfo(skb)->nr_frags; f++, frag++) { 2048c2ecf20Sopenharmony_ci len = skb_frag_size(frag); 2058c2ecf20Sopenharmony_ci dma = skb_frag_dma_map(tx_ring->dev, frag, 0, len, 2068c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 2078c2ecf20Sopenharmony_ci if (dma_mapping_error(tx_ring->dev, dma)) 2088c2ecf20Sopenharmony_ci goto dma_err; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci *txbd = temp_bd; 2118c2ecf20Sopenharmony_ci enetc_clear_tx_bd(&temp_bd); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci flags = 0; 2148c2ecf20Sopenharmony_ci tx_swbd++; 2158c2ecf20Sopenharmony_ci txbd++; 2168c2ecf20Sopenharmony_ci i++; 2178c2ecf20Sopenharmony_ci if (unlikely(i == tx_ring->bd_count)) { 2188c2ecf20Sopenharmony_ci i = 0; 2198c2ecf20Sopenharmony_ci tx_swbd = tx_ring->tx_swbd; 2208c2ecf20Sopenharmony_ci txbd = ENETC_TXBD(*tx_ring, 0); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci prefetchw(txbd); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci temp_bd.addr = cpu_to_le64(dma); 2258c2ecf20Sopenharmony_ci temp_bd.buf_len = cpu_to_le16(len); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci tx_swbd->dma = dma; 2288c2ecf20Sopenharmony_ci tx_swbd->len = len; 2298c2ecf20Sopenharmony_ci tx_swbd->is_dma_page = 1; 2308c2ecf20Sopenharmony_ci count++; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* last BD needs 'F' bit set */ 2348c2ecf20Sopenharmony_ci flags |= ENETC_TXBD_FLAGS_F; 2358c2ecf20Sopenharmony_ci temp_bd.flags = flags; 2368c2ecf20Sopenharmony_ci *txbd = temp_bd; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci tx_ring->tx_swbd[i].skb = skb; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci enetc_bdr_idx_inc(tx_ring, &i); 2418c2ecf20Sopenharmony_ci tx_ring->next_to_use = i; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci skb_tx_timestamp(skb); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* let H/W know BD ring has been updated */ 2468c2ecf20Sopenharmony_ci enetc_wr_reg_hot(tx_ring->tpir, i); /* includes wmb() */ 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return count; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cidma_err: 2518c2ecf20Sopenharmony_ci dev_err(tx_ring->dev, "DMA map error"); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci do { 2548c2ecf20Sopenharmony_ci tx_swbd = &tx_ring->tx_swbd[i]; 2558c2ecf20Sopenharmony_ci enetc_free_tx_skb(tx_ring, tx_swbd); 2568c2ecf20Sopenharmony_ci if (i == 0) 2578c2ecf20Sopenharmony_ci i = tx_ring->bd_count; 2588c2ecf20Sopenharmony_ci i--; 2598c2ecf20Sopenharmony_ci } while (count--); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic irqreturn_t enetc_msix(int irq, void *data) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct enetc_int_vector *v = data; 2678c2ecf20Sopenharmony_ci int i; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci enetc_lock_mdio(); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* disable interrupts */ 2728c2ecf20Sopenharmony_ci enetc_wr_reg_hot(v->rbier, 0); 2738c2ecf20Sopenharmony_ci enetc_wr_reg_hot(v->ricr1, v->rx_ictt); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci for_each_set_bit(i, &v->tx_rings_map, ENETC_MAX_NUM_TXQS) 2768c2ecf20Sopenharmony_ci enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i), 0); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci enetc_unlock_mdio(); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci napi_schedule(&v->napi); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget); 2868c2ecf20Sopenharmony_cistatic int enetc_clean_rx_ring(struct enetc_bdr *rx_ring, 2878c2ecf20Sopenharmony_ci struct napi_struct *napi, int work_limit); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void enetc_rx_dim_work(struct work_struct *w) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct dim *dim = container_of(w, struct dim, work); 2928c2ecf20Sopenharmony_ci struct dim_cq_moder moder = 2938c2ecf20Sopenharmony_ci net_dim_get_rx_moderation(dim->mode, dim->profile_ix); 2948c2ecf20Sopenharmony_ci struct enetc_int_vector *v = 2958c2ecf20Sopenharmony_ci container_of(dim, struct enetc_int_vector, rx_dim); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci v->rx_ictt = enetc_usecs_to_cycles(moder.usec); 2988c2ecf20Sopenharmony_ci dim->state = DIM_START_MEASURE; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void enetc_rx_net_dim(struct enetc_int_vector *v) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci struct dim_sample dim_sample = {}; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci v->comp_cnt++; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (!v->rx_napi_work) 3088c2ecf20Sopenharmony_ci return; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci dim_update_sample(v->comp_cnt, 3118c2ecf20Sopenharmony_ci v->rx_ring.stats.packets, 3128c2ecf20Sopenharmony_ci v->rx_ring.stats.bytes, 3138c2ecf20Sopenharmony_ci &dim_sample); 3148c2ecf20Sopenharmony_ci net_dim(&v->rx_dim, dim_sample); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int enetc_poll(struct napi_struct *napi, int budget) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct enetc_int_vector 3208c2ecf20Sopenharmony_ci *v = container_of(napi, struct enetc_int_vector, napi); 3218c2ecf20Sopenharmony_ci bool complete = true; 3228c2ecf20Sopenharmony_ci int work_done; 3238c2ecf20Sopenharmony_ci int i; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci enetc_lock_mdio(); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci for (i = 0; i < v->count_tx_rings; i++) 3288c2ecf20Sopenharmony_ci if (!enetc_clean_tx_ring(&v->tx_ring[i], budget)) 3298c2ecf20Sopenharmony_ci complete = false; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci work_done = enetc_clean_rx_ring(&v->rx_ring, napi, budget); 3328c2ecf20Sopenharmony_ci if (work_done == budget) 3338c2ecf20Sopenharmony_ci complete = false; 3348c2ecf20Sopenharmony_ci if (work_done) 3358c2ecf20Sopenharmony_ci v->rx_napi_work = true; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (!complete) { 3388c2ecf20Sopenharmony_ci enetc_unlock_mdio(); 3398c2ecf20Sopenharmony_ci return budget; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (likely(v->rx_dim_en)) 3458c2ecf20Sopenharmony_ci enetc_rx_net_dim(v); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci v->rx_napi_work = false; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* enable interrupts */ 3508c2ecf20Sopenharmony_ci enetc_wr_reg_hot(v->rbier, ENETC_RBIER_RXTIE); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci for_each_set_bit(i, &v->tx_rings_map, ENETC_MAX_NUM_TXQS) 3538c2ecf20Sopenharmony_ci enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i), 3548c2ecf20Sopenharmony_ci ENETC_TBIER_TXTIE); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci enetc_unlock_mdio(); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return work_done; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic int enetc_bd_ready_count(struct enetc_bdr *tx_ring, int ci) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci int pi = enetc_rd_reg_hot(tx_ring->tcir) & ENETC_TBCIR_IDX_MASK; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return pi >= ci ? pi - ci : tx_ring->bd_count - ci + pi; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void enetc_get_tx_tstamp(struct enetc_hw *hw, union enetc_tx_bd *txbd, 3698c2ecf20Sopenharmony_ci u64 *tstamp) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci u32 lo, hi, tstamp_lo; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci lo = enetc_rd_hot(hw, ENETC_SICTR0); 3748c2ecf20Sopenharmony_ci hi = enetc_rd_hot(hw, ENETC_SICTR1); 3758c2ecf20Sopenharmony_ci tstamp_lo = le32_to_cpu(txbd->wb.tstamp); 3768c2ecf20Sopenharmony_ci if (lo <= tstamp_lo) 3778c2ecf20Sopenharmony_ci hi -= 1; 3788c2ecf20Sopenharmony_ci *tstamp = (u64)hi << 32 | tstamp_lo; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic void enetc_tstamp_tx(struct sk_buff *skb, u64 tstamp) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct skb_shared_hwtstamps shhwtstamps; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) { 3868c2ecf20Sopenharmony_ci memset(&shhwtstamps, 0, sizeof(shhwtstamps)); 3878c2ecf20Sopenharmony_ci shhwtstamps.hwtstamp = ns_to_ktime(tstamp); 3888c2ecf20Sopenharmony_ci skb_txtime_consumed(skb); 3898c2ecf20Sopenharmony_ci skb_tstamp_tx(skb, &shhwtstamps); 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct net_device *ndev = tx_ring->ndev; 3968c2ecf20Sopenharmony_ci int tx_frm_cnt = 0, tx_byte_cnt = 0; 3978c2ecf20Sopenharmony_ci struct enetc_tx_swbd *tx_swbd; 3988c2ecf20Sopenharmony_ci int i, bds_to_clean; 3998c2ecf20Sopenharmony_ci bool do_tstamp; 4008c2ecf20Sopenharmony_ci u64 tstamp = 0; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci i = tx_ring->next_to_clean; 4038c2ecf20Sopenharmony_ci tx_swbd = &tx_ring->tx_swbd[i]; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci bds_to_clean = enetc_bd_ready_count(tx_ring, i); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci do_tstamp = false; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci while (bds_to_clean && tx_frm_cnt < ENETC_DEFAULT_TX_WORK) { 4108c2ecf20Sopenharmony_ci bool is_eof = !!tx_swbd->skb; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (unlikely(tx_swbd->check_wb)) { 4138c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 4148c2ecf20Sopenharmony_ci union enetc_tx_bd *txbd; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci txbd = ENETC_TXBD(*tx_ring, i); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci if (txbd->flags & ENETC_TXBD_FLAGS_W && 4198c2ecf20Sopenharmony_ci tx_swbd->do_tstamp) { 4208c2ecf20Sopenharmony_ci enetc_get_tx_tstamp(&priv->si->hw, txbd, 4218c2ecf20Sopenharmony_ci &tstamp); 4228c2ecf20Sopenharmony_ci do_tstamp = true; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (likely(tx_swbd->dma)) 4278c2ecf20Sopenharmony_ci enetc_unmap_tx_buff(tx_ring, tx_swbd); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (is_eof) { 4308c2ecf20Sopenharmony_ci if (unlikely(do_tstamp)) { 4318c2ecf20Sopenharmony_ci enetc_tstamp_tx(tx_swbd->skb, tstamp); 4328c2ecf20Sopenharmony_ci do_tstamp = false; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci napi_consume_skb(tx_swbd->skb, napi_budget); 4358c2ecf20Sopenharmony_ci tx_swbd->skb = NULL; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci tx_byte_cnt += tx_swbd->len; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci bds_to_clean--; 4418c2ecf20Sopenharmony_ci tx_swbd++; 4428c2ecf20Sopenharmony_ci i++; 4438c2ecf20Sopenharmony_ci if (unlikely(i == tx_ring->bd_count)) { 4448c2ecf20Sopenharmony_ci i = 0; 4458c2ecf20Sopenharmony_ci tx_swbd = tx_ring->tx_swbd; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* BD iteration loop end */ 4498c2ecf20Sopenharmony_ci if (is_eof) { 4508c2ecf20Sopenharmony_ci tx_frm_cnt++; 4518c2ecf20Sopenharmony_ci /* re-arm interrupt source */ 4528c2ecf20Sopenharmony_ci enetc_wr_reg_hot(tx_ring->idr, BIT(tx_ring->index) | 4538c2ecf20Sopenharmony_ci BIT(16 + tx_ring->index)); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (unlikely(!bds_to_clean)) 4578c2ecf20Sopenharmony_ci bds_to_clean = enetc_bd_ready_count(tx_ring, i); 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci tx_ring->next_to_clean = i; 4618c2ecf20Sopenharmony_ci tx_ring->stats.packets += tx_frm_cnt; 4628c2ecf20Sopenharmony_ci tx_ring->stats.bytes += tx_byte_cnt; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (unlikely(tx_frm_cnt && netif_carrier_ok(ndev) && 4658c2ecf20Sopenharmony_ci __netif_subqueue_stopped(ndev, tx_ring->index) && 4668c2ecf20Sopenharmony_ci (enetc_bd_unused(tx_ring) >= ENETC_TXBDS_MAX_NEEDED))) { 4678c2ecf20Sopenharmony_ci netif_wake_subqueue(ndev, tx_ring->index); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci return tx_frm_cnt != ENETC_DEFAULT_TX_WORK; 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic bool enetc_new_page(struct enetc_bdr *rx_ring, 4748c2ecf20Sopenharmony_ci struct enetc_rx_swbd *rx_swbd) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci struct page *page; 4778c2ecf20Sopenharmony_ci dma_addr_t addr; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci page = dev_alloc_page(); 4808c2ecf20Sopenharmony_ci if (unlikely(!page)) 4818c2ecf20Sopenharmony_ci return false; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci addr = dma_map_page(rx_ring->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); 4848c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(rx_ring->dev, addr))) { 4858c2ecf20Sopenharmony_ci __free_page(page); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return false; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci rx_swbd->dma = addr; 4918c2ecf20Sopenharmony_ci rx_swbd->page = page; 4928c2ecf20Sopenharmony_ci rx_swbd->page_offset = ENETC_RXB_PAD; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return true; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic int enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci struct enetc_rx_swbd *rx_swbd; 5008c2ecf20Sopenharmony_ci union enetc_rx_bd *rxbd; 5018c2ecf20Sopenharmony_ci int i, j; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci i = rx_ring->next_to_use; 5048c2ecf20Sopenharmony_ci rx_swbd = &rx_ring->rx_swbd[i]; 5058c2ecf20Sopenharmony_ci rxbd = enetc_rxbd(rx_ring, i); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci for (j = 0; j < buff_cnt; j++) { 5088c2ecf20Sopenharmony_ci /* try reuse page */ 5098c2ecf20Sopenharmony_ci if (unlikely(!rx_swbd->page)) { 5108c2ecf20Sopenharmony_ci if (unlikely(!enetc_new_page(rx_ring, rx_swbd))) { 5118c2ecf20Sopenharmony_ci rx_ring->stats.rx_alloc_errs++; 5128c2ecf20Sopenharmony_ci break; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* update RxBD */ 5178c2ecf20Sopenharmony_ci rxbd->w.addr = cpu_to_le64(rx_swbd->dma + 5188c2ecf20Sopenharmony_ci rx_swbd->page_offset); 5198c2ecf20Sopenharmony_ci /* clear 'R" as well */ 5208c2ecf20Sopenharmony_ci rxbd->r.lstatus = 0; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci rxbd = enetc_rxbd_next(rx_ring, rxbd, i); 5238c2ecf20Sopenharmony_ci rx_swbd++; 5248c2ecf20Sopenharmony_ci i++; 5258c2ecf20Sopenharmony_ci if (unlikely(i == rx_ring->bd_count)) { 5268c2ecf20Sopenharmony_ci i = 0; 5278c2ecf20Sopenharmony_ci rx_swbd = rx_ring->rx_swbd; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (likely(j)) { 5328c2ecf20Sopenharmony_ci rx_ring->next_to_alloc = i; /* keep track from page reuse */ 5338c2ecf20Sopenharmony_ci rx_ring->next_to_use = i; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return j; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_ENETC_PTP_CLOCK 5408c2ecf20Sopenharmony_cistatic void enetc_get_rx_tstamp(struct net_device *ndev, 5418c2ecf20Sopenharmony_ci union enetc_rx_bd *rxbd, 5428c2ecf20Sopenharmony_ci struct sk_buff *skb) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); 5458c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 5468c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 5478c2ecf20Sopenharmony_ci u32 lo, hi, tstamp_lo; 5488c2ecf20Sopenharmony_ci u64 tstamp; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_TSTMP) { 5518c2ecf20Sopenharmony_ci lo = enetc_rd_reg_hot(hw->reg + ENETC_SICTR0); 5528c2ecf20Sopenharmony_ci hi = enetc_rd_reg_hot(hw->reg + ENETC_SICTR1); 5538c2ecf20Sopenharmony_ci rxbd = enetc_rxbd_ext(rxbd); 5548c2ecf20Sopenharmony_ci tstamp_lo = le32_to_cpu(rxbd->ext.tstamp); 5558c2ecf20Sopenharmony_ci if (lo <= tstamp_lo) 5568c2ecf20Sopenharmony_ci hi -= 1; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci tstamp = (u64)hi << 32 | tstamp_lo; 5598c2ecf20Sopenharmony_ci memset(shhwtstamps, 0, sizeof(*shhwtstamps)); 5608c2ecf20Sopenharmony_ci shhwtstamps->hwtstamp = ns_to_ktime(tstamp); 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci#endif 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic void enetc_get_offloads(struct enetc_bdr *rx_ring, 5668c2ecf20Sopenharmony_ci union enetc_rx_bd *rxbd, struct sk_buff *skb) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(rx_ring->ndev); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* TODO: hashing */ 5718c2ecf20Sopenharmony_ci if (rx_ring->ndev->features & NETIF_F_RXCSUM) { 5728c2ecf20Sopenharmony_ci u16 inet_csum = le16_to_cpu(rxbd->r.inet_csum); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci skb->csum = csum_unfold((__force __sum16)~htons(inet_csum)); 5758c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_VLAN) { 5798c2ecf20Sopenharmony_ci __be16 tpid = 0; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci switch (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_TPID) { 5828c2ecf20Sopenharmony_ci case 0: 5838c2ecf20Sopenharmony_ci tpid = htons(ETH_P_8021Q); 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci case 1: 5868c2ecf20Sopenharmony_ci tpid = htons(ETH_P_8021AD); 5878c2ecf20Sopenharmony_ci break; 5888c2ecf20Sopenharmony_ci case 2: 5898c2ecf20Sopenharmony_ci tpid = htons(enetc_port_rd(&priv->si->hw, 5908c2ecf20Sopenharmony_ci ENETC_PCVLANR1)); 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci case 3: 5938c2ecf20Sopenharmony_ci tpid = htons(enetc_port_rd(&priv->si->hw, 5948c2ecf20Sopenharmony_ci ENETC_PCVLANR2)); 5958c2ecf20Sopenharmony_ci break; 5968c2ecf20Sopenharmony_ci default: 5978c2ecf20Sopenharmony_ci break; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, tpid, le16_to_cpu(rxbd->r.vlan_opt)); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_ENETC_PTP_CLOCK 6048c2ecf20Sopenharmony_ci if (priv->active_offloads & ENETC_F_RX_TSTAMP) 6058c2ecf20Sopenharmony_ci enetc_get_rx_tstamp(rx_ring->ndev, rxbd, skb); 6068c2ecf20Sopenharmony_ci#endif 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic void enetc_process_skb(struct enetc_bdr *rx_ring, 6108c2ecf20Sopenharmony_ci struct sk_buff *skb) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, rx_ring->index); 6138c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, rx_ring->ndev); 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic bool enetc_page_reusable(struct page *page) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci return (!page_is_pfmemalloc(page) && page_ref_count(page) == 1); 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic void enetc_reuse_page(struct enetc_bdr *rx_ring, 6228c2ecf20Sopenharmony_ci struct enetc_rx_swbd *old) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct enetc_rx_swbd *new; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci new = &rx_ring->rx_swbd[rx_ring->next_to_alloc]; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* next buf that may reuse a page */ 6298c2ecf20Sopenharmony_ci enetc_bdr_idx_inc(rx_ring, &rx_ring->next_to_alloc); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* copy page reference */ 6328c2ecf20Sopenharmony_ci *new = *old; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic struct enetc_rx_swbd *enetc_get_rx_buff(struct enetc_bdr *rx_ring, 6368c2ecf20Sopenharmony_ci int i, u16 size) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci struct enetc_rx_swbd *rx_swbd = &rx_ring->rx_swbd[i]; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci dma_sync_single_range_for_cpu(rx_ring->dev, rx_swbd->dma, 6418c2ecf20Sopenharmony_ci rx_swbd->page_offset, 6428c2ecf20Sopenharmony_ci size, DMA_FROM_DEVICE); 6438c2ecf20Sopenharmony_ci return rx_swbd; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic void enetc_put_rx_buff(struct enetc_bdr *rx_ring, 6478c2ecf20Sopenharmony_ci struct enetc_rx_swbd *rx_swbd) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci if (likely(enetc_page_reusable(rx_swbd->page))) { 6508c2ecf20Sopenharmony_ci rx_swbd->page_offset ^= ENETC_RXB_TRUESIZE; 6518c2ecf20Sopenharmony_ci page_ref_inc(rx_swbd->page); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci enetc_reuse_page(rx_ring, rx_swbd); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci /* sync for use by the device */ 6568c2ecf20Sopenharmony_ci dma_sync_single_range_for_device(rx_ring->dev, rx_swbd->dma, 6578c2ecf20Sopenharmony_ci rx_swbd->page_offset, 6588c2ecf20Sopenharmony_ci ENETC_RXB_DMA_SIZE, 6598c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 6608c2ecf20Sopenharmony_ci } else { 6618c2ecf20Sopenharmony_ci dma_unmap_page(rx_ring->dev, rx_swbd->dma, 6628c2ecf20Sopenharmony_ci PAGE_SIZE, DMA_FROM_DEVICE); 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci rx_swbd->page = NULL; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic struct sk_buff *enetc_map_rx_buff_to_skb(struct enetc_bdr *rx_ring, 6698c2ecf20Sopenharmony_ci int i, u16 size) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct enetc_rx_swbd *rx_swbd = enetc_get_rx_buff(rx_ring, i, size); 6728c2ecf20Sopenharmony_ci struct sk_buff *skb; 6738c2ecf20Sopenharmony_ci void *ba; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci ba = page_address(rx_swbd->page) + rx_swbd->page_offset; 6768c2ecf20Sopenharmony_ci skb = build_skb(ba - ENETC_RXB_PAD, ENETC_RXB_TRUESIZE); 6778c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 6788c2ecf20Sopenharmony_ci rx_ring->stats.rx_alloc_errs++; 6798c2ecf20Sopenharmony_ci return NULL; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci skb_reserve(skb, ENETC_RXB_PAD); 6838c2ecf20Sopenharmony_ci __skb_put(skb, size); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci enetc_put_rx_buff(rx_ring, rx_swbd); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return skb; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic void enetc_add_rx_buff_to_skb(struct enetc_bdr *rx_ring, int i, 6918c2ecf20Sopenharmony_ci u16 size, struct sk_buff *skb) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct enetc_rx_swbd *rx_swbd = enetc_get_rx_buff(rx_ring, i, size); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_swbd->page, 6968c2ecf20Sopenharmony_ci rx_swbd->page_offset, size, ENETC_RXB_TRUESIZE); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci enetc_put_rx_buff(rx_ring, rx_swbd); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci#define ENETC_RXBD_BUNDLE 16 /* # of BDs to update at once */ 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic int enetc_clean_rx_ring(struct enetc_bdr *rx_ring, 7048c2ecf20Sopenharmony_ci struct napi_struct *napi, int work_limit) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci int rx_frm_cnt = 0, rx_byte_cnt = 0; 7078c2ecf20Sopenharmony_ci int cleaned_cnt, i; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci cleaned_cnt = enetc_bd_unused(rx_ring); 7108c2ecf20Sopenharmony_ci /* next descriptor to process */ 7118c2ecf20Sopenharmony_ci i = rx_ring->next_to_clean; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci while (likely(rx_frm_cnt < work_limit)) { 7148c2ecf20Sopenharmony_ci union enetc_rx_bd *rxbd; 7158c2ecf20Sopenharmony_ci struct sk_buff *skb; 7168c2ecf20Sopenharmony_ci u32 bd_status; 7178c2ecf20Sopenharmony_ci u16 size; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (cleaned_cnt >= ENETC_RXBD_BUNDLE) { 7208c2ecf20Sopenharmony_ci int count = enetc_refill_rx_ring(rx_ring, cleaned_cnt); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* update ENETC's consumer index */ 7238c2ecf20Sopenharmony_ci enetc_wr_reg_hot(rx_ring->rcir, rx_ring->next_to_use); 7248c2ecf20Sopenharmony_ci cleaned_cnt -= count; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci rxbd = enetc_rxbd(rx_ring, i); 7288c2ecf20Sopenharmony_ci bd_status = le32_to_cpu(rxbd->r.lstatus); 7298c2ecf20Sopenharmony_ci if (!bd_status) 7308c2ecf20Sopenharmony_ci break; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci enetc_wr_reg_hot(rx_ring->idr, BIT(rx_ring->index)); 7338c2ecf20Sopenharmony_ci dma_rmb(); /* for reading other rxbd fields */ 7348c2ecf20Sopenharmony_ci size = le16_to_cpu(rxbd->r.buf_len); 7358c2ecf20Sopenharmony_ci skb = enetc_map_rx_buff_to_skb(rx_ring, i, size); 7368c2ecf20Sopenharmony_ci if (!skb) 7378c2ecf20Sopenharmony_ci break; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci enetc_get_offloads(rx_ring, rxbd, skb); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci cleaned_cnt++; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci rxbd = enetc_rxbd_next(rx_ring, rxbd, i); 7448c2ecf20Sopenharmony_ci if (unlikely(++i == rx_ring->bd_count)) 7458c2ecf20Sopenharmony_ci i = 0; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (unlikely(bd_status & 7488c2ecf20Sopenharmony_ci ENETC_RXBD_LSTATUS(ENETC_RXBD_ERR_MASK))) { 7498c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 7508c2ecf20Sopenharmony_ci while (!(bd_status & ENETC_RXBD_LSTATUS_F)) { 7518c2ecf20Sopenharmony_ci dma_rmb(); 7528c2ecf20Sopenharmony_ci bd_status = le32_to_cpu(rxbd->r.lstatus); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci rxbd = enetc_rxbd_next(rx_ring, rxbd, i); 7558c2ecf20Sopenharmony_ci if (unlikely(++i == rx_ring->bd_count)) 7568c2ecf20Sopenharmony_ci i = 0; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci rx_ring->ndev->stats.rx_dropped++; 7608c2ecf20Sopenharmony_ci rx_ring->ndev->stats.rx_errors++; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* not last BD in frame? */ 7668c2ecf20Sopenharmony_ci while (!(bd_status & ENETC_RXBD_LSTATUS_F)) { 7678c2ecf20Sopenharmony_ci bd_status = le32_to_cpu(rxbd->r.lstatus); 7688c2ecf20Sopenharmony_ci size = ENETC_RXB_DMA_SIZE; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (bd_status & ENETC_RXBD_LSTATUS_F) { 7718c2ecf20Sopenharmony_ci dma_rmb(); 7728c2ecf20Sopenharmony_ci size = le16_to_cpu(rxbd->r.buf_len); 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci enetc_add_rx_buff_to_skb(rx_ring, i, size, skb); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci cleaned_cnt++; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci rxbd = enetc_rxbd_next(rx_ring, rxbd, i); 7808c2ecf20Sopenharmony_ci if (unlikely(++i == rx_ring->bd_count)) 7818c2ecf20Sopenharmony_ci i = 0; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci rx_byte_cnt += skb->len; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci enetc_process_skb(rx_ring, skb); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci napi_gro_receive(napi, skb); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci rx_frm_cnt++; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci rx_ring->next_to_clean = i; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci rx_ring->stats.packets += rx_frm_cnt; 7968c2ecf20Sopenharmony_ci rx_ring->stats.bytes += rx_byte_cnt; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci return rx_frm_cnt; 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci/* Probing and Init */ 8028c2ecf20Sopenharmony_ci#define ENETC_MAX_RFS_SIZE 64 8038c2ecf20Sopenharmony_civoid enetc_get_si_caps(struct enetc_si *si) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci struct enetc_hw *hw = &si->hw; 8068c2ecf20Sopenharmony_ci u32 val; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* find out how many of various resources we have to work with */ 8098c2ecf20Sopenharmony_ci val = enetc_rd(hw, ENETC_SICAPR0); 8108c2ecf20Sopenharmony_ci si->num_rx_rings = (val >> 16) & 0xff; 8118c2ecf20Sopenharmony_ci si->num_tx_rings = val & 0xff; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci val = enetc_rd(hw, ENETC_SIRFSCAPR); 8148c2ecf20Sopenharmony_ci si->num_fs_entries = ENETC_SIRFSCAPR_GET_NUM_RFS(val); 8158c2ecf20Sopenharmony_ci si->num_fs_entries = min(si->num_fs_entries, ENETC_MAX_RFS_SIZE); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci si->num_rss = 0; 8188c2ecf20Sopenharmony_ci val = enetc_rd(hw, ENETC_SIPCAPR0); 8198c2ecf20Sopenharmony_ci if (val & ENETC_SIPCAPR0_RSS) { 8208c2ecf20Sopenharmony_ci u32 rss; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci rss = enetc_rd(hw, ENETC_SIRSSCAPR); 8238c2ecf20Sopenharmony_ci si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(rss); 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (val & ENETC_SIPCAPR0_QBV) 8278c2ecf20Sopenharmony_ci si->hw_features |= ENETC_SI_F_QBV; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (val & ENETC_SIPCAPR0_PSFP) 8308c2ecf20Sopenharmony_ci si->hw_features |= ENETC_SI_F_PSFP; 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_cistatic int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size) 8348c2ecf20Sopenharmony_ci{ 8358c2ecf20Sopenharmony_ci r->bd_base = dma_alloc_coherent(r->dev, r->bd_count * bd_size, 8368c2ecf20Sopenharmony_ci &r->bd_dma_base, GFP_KERNEL); 8378c2ecf20Sopenharmony_ci if (!r->bd_base) 8388c2ecf20Sopenharmony_ci return -ENOMEM; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci /* h/w requires 128B alignment */ 8418c2ecf20Sopenharmony_ci if (!IS_ALIGNED(r->bd_dma_base, 128)) { 8428c2ecf20Sopenharmony_ci dma_free_coherent(r->dev, r->bd_count * bd_size, r->bd_base, 8438c2ecf20Sopenharmony_ci r->bd_dma_base); 8448c2ecf20Sopenharmony_ci return -EINVAL; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci return 0; 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cistatic int enetc_alloc_txbdr(struct enetc_bdr *txr) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci int err; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci txr->tx_swbd = vzalloc(txr->bd_count * sizeof(struct enetc_tx_swbd)); 8558c2ecf20Sopenharmony_ci if (!txr->tx_swbd) 8568c2ecf20Sopenharmony_ci return -ENOMEM; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci err = enetc_dma_alloc_bdr(txr, sizeof(union enetc_tx_bd)); 8598c2ecf20Sopenharmony_ci if (err) { 8608c2ecf20Sopenharmony_ci vfree(txr->tx_swbd); 8618c2ecf20Sopenharmony_ci return err; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci txr->next_to_clean = 0; 8658c2ecf20Sopenharmony_ci txr->next_to_use = 0; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci return 0; 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_cistatic void enetc_free_txbdr(struct enetc_bdr *txr) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci int size, i; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci for (i = 0; i < txr->bd_count; i++) 8758c2ecf20Sopenharmony_ci enetc_free_tx_skb(txr, &txr->tx_swbd[i]); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci size = txr->bd_count * sizeof(union enetc_tx_bd); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci dma_free_coherent(txr->dev, size, txr->bd_base, txr->bd_dma_base); 8808c2ecf20Sopenharmony_ci txr->bd_base = NULL; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci vfree(txr->tx_swbd); 8838c2ecf20Sopenharmony_ci txr->tx_swbd = NULL; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic int enetc_alloc_tx_resources(struct enetc_ndev_priv *priv) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci int i, err; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) { 8918c2ecf20Sopenharmony_ci err = enetc_alloc_txbdr(priv->tx_ring[i]); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (err) 8948c2ecf20Sopenharmony_ci goto fail; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci return 0; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cifail: 9008c2ecf20Sopenharmony_ci while (i-- > 0) 9018c2ecf20Sopenharmony_ci enetc_free_txbdr(priv->tx_ring[i]); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci return err; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic void enetc_free_tx_resources(struct enetc_ndev_priv *priv) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci int i; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) 9118c2ecf20Sopenharmony_ci enetc_free_txbdr(priv->tx_ring[i]); 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic int enetc_alloc_rxbdr(struct enetc_bdr *rxr, bool extended) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci size_t size = sizeof(union enetc_rx_bd); 9178c2ecf20Sopenharmony_ci int err; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci rxr->rx_swbd = vzalloc(rxr->bd_count * sizeof(struct enetc_rx_swbd)); 9208c2ecf20Sopenharmony_ci if (!rxr->rx_swbd) 9218c2ecf20Sopenharmony_ci return -ENOMEM; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (extended) 9248c2ecf20Sopenharmony_ci size *= 2; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci err = enetc_dma_alloc_bdr(rxr, size); 9278c2ecf20Sopenharmony_ci if (err) { 9288c2ecf20Sopenharmony_ci vfree(rxr->rx_swbd); 9298c2ecf20Sopenharmony_ci return err; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci rxr->next_to_clean = 0; 9338c2ecf20Sopenharmony_ci rxr->next_to_use = 0; 9348c2ecf20Sopenharmony_ci rxr->next_to_alloc = 0; 9358c2ecf20Sopenharmony_ci rxr->ext_en = extended; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci return 0; 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic void enetc_free_rxbdr(struct enetc_bdr *rxr) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci int size; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci size = rxr->bd_count * sizeof(union enetc_rx_bd); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci dma_free_coherent(rxr->dev, size, rxr->bd_base, rxr->bd_dma_base); 9478c2ecf20Sopenharmony_ci rxr->bd_base = NULL; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci vfree(rxr->rx_swbd); 9508c2ecf20Sopenharmony_ci rxr->rx_swbd = NULL; 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic int enetc_alloc_rx_resources(struct enetc_ndev_priv *priv) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci bool extended = !!(priv->active_offloads & ENETC_F_RX_TSTAMP); 9568c2ecf20Sopenharmony_ci int i, err; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) { 9598c2ecf20Sopenharmony_ci err = enetc_alloc_rxbdr(priv->rx_ring[i], extended); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (err) 9628c2ecf20Sopenharmony_ci goto fail; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci return 0; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cifail: 9688c2ecf20Sopenharmony_ci while (i-- > 0) 9698c2ecf20Sopenharmony_ci enetc_free_rxbdr(priv->rx_ring[i]); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci return err; 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_cistatic void enetc_free_rx_resources(struct enetc_ndev_priv *priv) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci int i; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) 9798c2ecf20Sopenharmony_ci enetc_free_rxbdr(priv->rx_ring[i]); 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistatic void enetc_free_tx_ring(struct enetc_bdr *tx_ring) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci int i; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (!tx_ring->tx_swbd) 9878c2ecf20Sopenharmony_ci return; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci for (i = 0; i < tx_ring->bd_count; i++) { 9908c2ecf20Sopenharmony_ci struct enetc_tx_swbd *tx_swbd = &tx_ring->tx_swbd[i]; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci enetc_free_tx_skb(tx_ring, tx_swbd); 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci tx_ring->next_to_clean = 0; 9968c2ecf20Sopenharmony_ci tx_ring->next_to_use = 0; 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic void enetc_free_rx_ring(struct enetc_bdr *rx_ring) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci int i; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (!rx_ring->rx_swbd) 10048c2ecf20Sopenharmony_ci return; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci for (i = 0; i < rx_ring->bd_count; i++) { 10078c2ecf20Sopenharmony_ci struct enetc_rx_swbd *rx_swbd = &rx_ring->rx_swbd[i]; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (!rx_swbd->page) 10108c2ecf20Sopenharmony_ci continue; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci dma_unmap_page(rx_ring->dev, rx_swbd->dma, 10138c2ecf20Sopenharmony_ci PAGE_SIZE, DMA_FROM_DEVICE); 10148c2ecf20Sopenharmony_ci __free_page(rx_swbd->page); 10158c2ecf20Sopenharmony_ci rx_swbd->page = NULL; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci rx_ring->next_to_clean = 0; 10198c2ecf20Sopenharmony_ci rx_ring->next_to_use = 0; 10208c2ecf20Sopenharmony_ci rx_ring->next_to_alloc = 0; 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic void enetc_free_rxtx_rings(struct enetc_ndev_priv *priv) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci int i; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) 10288c2ecf20Sopenharmony_ci enetc_free_rx_ring(priv->rx_ring[i]); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) 10318c2ecf20Sopenharmony_ci enetc_free_tx_ring(priv->tx_ring[i]); 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ciint enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci int size = cbdr->bd_count * sizeof(struct enetc_cbd); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci cbdr->bd_base = dma_alloc_coherent(dev, size, &cbdr->bd_dma_base, 10398c2ecf20Sopenharmony_ci GFP_KERNEL); 10408c2ecf20Sopenharmony_ci if (!cbdr->bd_base) 10418c2ecf20Sopenharmony_ci return -ENOMEM; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* h/w requires 128B alignment */ 10448c2ecf20Sopenharmony_ci if (!IS_ALIGNED(cbdr->bd_dma_base, 128)) { 10458c2ecf20Sopenharmony_ci dma_free_coherent(dev, size, cbdr->bd_base, cbdr->bd_dma_base); 10468c2ecf20Sopenharmony_ci return -EINVAL; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci cbdr->next_to_clean = 0; 10508c2ecf20Sopenharmony_ci cbdr->next_to_use = 0; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci return 0; 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_civoid enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci int size = cbdr->bd_count * sizeof(struct enetc_cbd); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci dma_free_coherent(dev, size, cbdr->bd_base, cbdr->bd_dma_base); 10608c2ecf20Sopenharmony_ci cbdr->bd_base = NULL; 10618c2ecf20Sopenharmony_ci} 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_civoid enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr) 10648c2ecf20Sopenharmony_ci{ 10658c2ecf20Sopenharmony_ci /* set CBDR cache attributes */ 10668c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SICAR2, 10678c2ecf20Sopenharmony_ci ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SICBDRBAR0, lower_32_bits(cbdr->bd_dma_base)); 10708c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SICBDRBAR1, upper_32_bits(cbdr->bd_dma_base)); 10718c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SICBDRLENR, ENETC_RTBLENR_LEN(cbdr->bd_count)); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SICBDRPIR, 0); 10748c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SICBDRCIR, 0); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci /* enable ring */ 10778c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SICBDRMR, BIT(31)); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci cbdr->pir = hw->reg + ENETC_SICBDRPIR; 10808c2ecf20Sopenharmony_ci cbdr->cir = hw->reg + ENETC_SICBDRCIR; 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_civoid enetc_clear_cbdr(struct enetc_hw *hw) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SICBDRMR, 0); 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic int enetc_setup_default_rss_table(struct enetc_si *si, int num_groups) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci int *rss_table; 10918c2ecf20Sopenharmony_ci int i; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci rss_table = kmalloc_array(si->num_rss, sizeof(*rss_table), GFP_KERNEL); 10948c2ecf20Sopenharmony_ci if (!rss_table) 10958c2ecf20Sopenharmony_ci return -ENOMEM; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* Set up RSS table defaults */ 10988c2ecf20Sopenharmony_ci for (i = 0; i < si->num_rss; i++) 10998c2ecf20Sopenharmony_ci rss_table[i] = i % num_groups; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci enetc_set_rss_table(si, rss_table, si->num_rss); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci kfree(rss_table); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci return 0; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ciint enetc_configure_si(struct enetc_ndev_priv *priv) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci struct enetc_si *si = priv->si; 11118c2ecf20Sopenharmony_ci struct enetc_hw *hw = &si->hw; 11128c2ecf20Sopenharmony_ci int err; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci /* set SI cache attributes */ 11158c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SICAR0, 11168c2ecf20Sopenharmony_ci ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT); 11178c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SICAR1, ENETC_SICAR_MSI); 11188c2ecf20Sopenharmony_ci /* enable SI */ 11198c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SIMR, ENETC_SIMR_EN); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci if (si->num_rss) { 11228c2ecf20Sopenharmony_ci err = enetc_setup_default_rss_table(si, priv->num_rx_rings); 11238c2ecf20Sopenharmony_ci if (err) 11248c2ecf20Sopenharmony_ci return err; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci return 0; 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_civoid enetc_init_si_rings_params(struct enetc_ndev_priv *priv) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci struct enetc_si *si = priv->si; 11338c2ecf20Sopenharmony_ci int cpus = num_online_cpus(); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci priv->tx_bd_count = ENETC_TX_RING_DEFAULT_SIZE; 11368c2ecf20Sopenharmony_ci priv->rx_bd_count = ENETC_RX_RING_DEFAULT_SIZE; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci /* Enable all available TX rings in order to configure as many 11398c2ecf20Sopenharmony_ci * priorities as possible, when needed. 11408c2ecf20Sopenharmony_ci * TODO: Make # of TX rings run-time configurable 11418c2ecf20Sopenharmony_ci */ 11428c2ecf20Sopenharmony_ci priv->num_rx_rings = min_t(int, cpus, si->num_rx_rings); 11438c2ecf20Sopenharmony_ci priv->num_tx_rings = si->num_tx_rings; 11448c2ecf20Sopenharmony_ci priv->bdr_int_num = cpus; 11458c2ecf20Sopenharmony_ci priv->ic_mode = ENETC_IC_RX_ADAPTIVE | ENETC_IC_TX_MANUAL; 11468c2ecf20Sopenharmony_ci priv->tx_ictt = ENETC_TXIC_TIMETHR; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci /* SI specific */ 11498c2ecf20Sopenharmony_ci si->cbd_ring.bd_count = ENETC_CBDR_DEFAULT_SIZE; 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ciint enetc_alloc_si_resources(struct enetc_ndev_priv *priv) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci struct enetc_si *si = priv->si; 11558c2ecf20Sopenharmony_ci int err; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci err = enetc_alloc_cbdr(priv->dev, &si->cbd_ring); 11588c2ecf20Sopenharmony_ci if (err) 11598c2ecf20Sopenharmony_ci return err; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci enetc_setup_cbdr(&si->hw, &si->cbd_ring); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci priv->cls_rules = kcalloc(si->num_fs_entries, sizeof(*priv->cls_rules), 11648c2ecf20Sopenharmony_ci GFP_KERNEL); 11658c2ecf20Sopenharmony_ci if (!priv->cls_rules) { 11668c2ecf20Sopenharmony_ci err = -ENOMEM; 11678c2ecf20Sopenharmony_ci goto err_alloc_cls; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci return 0; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cierr_alloc_cls: 11738c2ecf20Sopenharmony_ci enetc_clear_cbdr(&si->hw); 11748c2ecf20Sopenharmony_ci enetc_free_cbdr(priv->dev, &si->cbd_ring); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci return err; 11778c2ecf20Sopenharmony_ci} 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_civoid enetc_free_si_resources(struct enetc_ndev_priv *priv) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci struct enetc_si *si = priv->si; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci enetc_clear_cbdr(&si->hw); 11848c2ecf20Sopenharmony_ci enetc_free_cbdr(priv->dev, &si->cbd_ring); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci kfree(priv->cls_rules); 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_cistatic void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci int idx = tx_ring->index; 11928c2ecf20Sopenharmony_ci u32 tbmr; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci enetc_txbdr_wr(hw, idx, ENETC_TBBAR0, 11958c2ecf20Sopenharmony_ci lower_32_bits(tx_ring->bd_dma_base)); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci enetc_txbdr_wr(hw, idx, ENETC_TBBAR1, 11988c2ecf20Sopenharmony_ci upper_32_bits(tx_ring->bd_dma_base)); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci WARN_ON(!IS_ALIGNED(tx_ring->bd_count, 64)); /* multiple of 64 */ 12018c2ecf20Sopenharmony_ci enetc_txbdr_wr(hw, idx, ENETC_TBLENR, 12028c2ecf20Sopenharmony_ci ENETC_RTBLENR_LEN(tx_ring->bd_count)); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci /* clearing PI/CI registers for Tx not supported, adjust sw indexes */ 12058c2ecf20Sopenharmony_ci tx_ring->next_to_use = enetc_txbdr_rd(hw, idx, ENETC_TBPIR); 12068c2ecf20Sopenharmony_ci tx_ring->next_to_clean = enetc_txbdr_rd(hw, idx, ENETC_TBCIR); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci /* enable Tx ints by setting pkt thr to 1 */ 12098c2ecf20Sopenharmony_ci enetc_txbdr_wr(hw, idx, ENETC_TBICR0, ENETC_TBICR0_ICEN | 0x1); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci tbmr = ENETC_TBMR_EN | ENETC_TBMR_SET_PRIO(tx_ring->prio); 12128c2ecf20Sopenharmony_ci if (tx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_TX) 12138c2ecf20Sopenharmony_ci tbmr |= ENETC_TBMR_VIH; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci /* enable ring */ 12168c2ecf20Sopenharmony_ci enetc_txbdr_wr(hw, idx, ENETC_TBMR, tbmr); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci tx_ring->tpir = hw->reg + ENETC_BDR(TX, idx, ENETC_TBPIR); 12198c2ecf20Sopenharmony_ci tx_ring->tcir = hw->reg + ENETC_BDR(TX, idx, ENETC_TBCIR); 12208c2ecf20Sopenharmony_ci tx_ring->idr = hw->reg + ENETC_SITXIDR; 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci int idx = rx_ring->index; 12268c2ecf20Sopenharmony_ci u32 rbmr; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, idx, ENETC_RBBAR0, 12298c2ecf20Sopenharmony_ci lower_32_bits(rx_ring->bd_dma_base)); 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, idx, ENETC_RBBAR1, 12328c2ecf20Sopenharmony_ci upper_32_bits(rx_ring->bd_dma_base)); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci WARN_ON(!IS_ALIGNED(rx_ring->bd_count, 64)); /* multiple of 64 */ 12358c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, idx, ENETC_RBLENR, 12368c2ecf20Sopenharmony_ci ENETC_RTBLENR_LEN(rx_ring->bd_count)); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, idx, ENETC_RBBSR, ENETC_RXB_DMA_SIZE); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci /* Also prepare the consumer index in case page allocation never 12418c2ecf20Sopenharmony_ci * succeeds. In that case, hardware will never advance producer index 12428c2ecf20Sopenharmony_ci * to match consumer index, and will drop all frames. 12438c2ecf20Sopenharmony_ci */ 12448c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, idx, ENETC_RBPIR, 0); 12458c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, idx, ENETC_RBCIR, 1); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci /* enable Rx ints by setting pkt thr to 1 */ 12488c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, idx, ENETC_RBICR0, ENETC_RBICR0_ICEN | 0x1); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci rbmr = ENETC_RBMR_EN; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if (rx_ring->ext_en) 12538c2ecf20Sopenharmony_ci rbmr |= ENETC_RBMR_BDS; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (rx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_RX) 12568c2ecf20Sopenharmony_ci rbmr |= ENETC_RBMR_VTE; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci rx_ring->rcir = hw->reg + ENETC_BDR(RX, idx, ENETC_RBCIR); 12598c2ecf20Sopenharmony_ci rx_ring->idr = hw->reg + ENETC_SIRXIDR; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci enetc_refill_rx_ring(rx_ring, enetc_bd_unused(rx_ring)); 12628c2ecf20Sopenharmony_ci /* update ENETC's consumer index */ 12638c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, idx, ENETC_RBCIR, rx_ring->next_to_use); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci /* enable ring */ 12668c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, idx, ENETC_RBMR, rbmr); 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cistatic void enetc_setup_bdrs(struct enetc_ndev_priv *priv) 12708c2ecf20Sopenharmony_ci{ 12718c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 12728c2ecf20Sopenharmony_ci int i; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) 12758c2ecf20Sopenharmony_ci enetc_setup_txbdr(hw, priv->tx_ring[i]); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) 12788c2ecf20Sopenharmony_ci enetc_setup_rxbdr(hw, priv->rx_ring[i]); 12798c2ecf20Sopenharmony_ci} 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_cistatic void enetc_clear_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci int idx = rx_ring->index; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci /* disable EN bit on ring */ 12868c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, idx, ENETC_RBMR, 0); 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_cistatic void enetc_clear_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci int delay = 8, timeout = 100; 12928c2ecf20Sopenharmony_ci int idx = tx_ring->index; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* disable EN bit on ring */ 12958c2ecf20Sopenharmony_ci enetc_txbdr_wr(hw, idx, ENETC_TBMR, 0); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci /* wait for busy to clear */ 12988c2ecf20Sopenharmony_ci while (delay < timeout && 12998c2ecf20Sopenharmony_ci enetc_txbdr_rd(hw, idx, ENETC_TBSR) & ENETC_TBSR_BUSY) { 13008c2ecf20Sopenharmony_ci msleep(delay); 13018c2ecf20Sopenharmony_ci delay *= 2; 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci if (delay >= timeout) 13058c2ecf20Sopenharmony_ci netdev_warn(tx_ring->ndev, "timeout for tx ring #%d clear\n", 13068c2ecf20Sopenharmony_ci idx); 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic void enetc_clear_bdrs(struct enetc_ndev_priv *priv) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 13128c2ecf20Sopenharmony_ci int i; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) 13158c2ecf20Sopenharmony_ci enetc_clear_txbdr(hw, priv->tx_ring[i]); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) 13188c2ecf20Sopenharmony_ci enetc_clear_rxbdr(hw, priv->rx_ring[i]); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci udelay(1); 13218c2ecf20Sopenharmony_ci} 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_cistatic int enetc_setup_irqs(struct enetc_ndev_priv *priv) 13248c2ecf20Sopenharmony_ci{ 13258c2ecf20Sopenharmony_ci struct pci_dev *pdev = priv->si->pdev; 13268c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 13278c2ecf20Sopenharmony_ci int i, j, err; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci for (i = 0; i < priv->bdr_int_num; i++) { 13308c2ecf20Sopenharmony_ci int irq = pci_irq_vector(pdev, ENETC_BDR_INT_BASE_IDX + i); 13318c2ecf20Sopenharmony_ci struct enetc_int_vector *v = priv->int_vector[i]; 13328c2ecf20Sopenharmony_ci int entry = ENETC_BDR_INT_BASE_IDX + i; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci snprintf(v->name, sizeof(v->name), "%s-rxtx%d", 13358c2ecf20Sopenharmony_ci priv->ndev->name, i); 13368c2ecf20Sopenharmony_ci err = request_irq(irq, enetc_msix, 0, v->name, v); 13378c2ecf20Sopenharmony_ci if (err) { 13388c2ecf20Sopenharmony_ci dev_err(priv->dev, "request_irq() failed!\n"); 13398c2ecf20Sopenharmony_ci goto irq_err; 13408c2ecf20Sopenharmony_ci } 13418c2ecf20Sopenharmony_ci disable_irq(irq); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci v->tbier_base = hw->reg + ENETC_BDR(TX, 0, ENETC_TBIER); 13448c2ecf20Sopenharmony_ci v->rbier = hw->reg + ENETC_BDR(RX, i, ENETC_RBIER); 13458c2ecf20Sopenharmony_ci v->ricr1 = hw->reg + ENETC_BDR(RX, i, ENETC_RBICR1); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SIMSIRRV(i), entry); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci for (j = 0; j < v->count_tx_rings; j++) { 13508c2ecf20Sopenharmony_ci int idx = v->tx_ring[j].index; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SIMSITRV(idx), entry); 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci irq_set_affinity_hint(irq, get_cpu_mask(i % num_online_cpus())); 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci return 0; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ciirq_err: 13608c2ecf20Sopenharmony_ci while (i--) { 13618c2ecf20Sopenharmony_ci int irq = pci_irq_vector(pdev, ENETC_BDR_INT_BASE_IDX + i); 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci irq_set_affinity_hint(irq, NULL); 13648c2ecf20Sopenharmony_ci free_irq(irq, priv->int_vector[i]); 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci return err; 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic void enetc_free_irqs(struct enetc_ndev_priv *priv) 13718c2ecf20Sopenharmony_ci{ 13728c2ecf20Sopenharmony_ci struct pci_dev *pdev = priv->si->pdev; 13738c2ecf20Sopenharmony_ci int i; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci for (i = 0; i < priv->bdr_int_num; i++) { 13768c2ecf20Sopenharmony_ci int irq = pci_irq_vector(pdev, ENETC_BDR_INT_BASE_IDX + i); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci irq_set_affinity_hint(irq, NULL); 13798c2ecf20Sopenharmony_ci free_irq(irq, priv->int_vector[i]); 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_cistatic void enetc_setup_interrupts(struct enetc_ndev_priv *priv) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 13868c2ecf20Sopenharmony_ci u32 icpt, ictt; 13878c2ecf20Sopenharmony_ci int i; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci /* enable Tx & Rx event indication */ 13908c2ecf20Sopenharmony_ci if (priv->ic_mode & 13918c2ecf20Sopenharmony_ci (ENETC_IC_RX_MANUAL | ENETC_IC_RX_ADAPTIVE)) { 13928c2ecf20Sopenharmony_ci icpt = ENETC_RBICR0_SET_ICPT(ENETC_RXIC_PKTTHR); 13938c2ecf20Sopenharmony_ci /* init to non-0 minimum, will be adjusted later */ 13948c2ecf20Sopenharmony_ci ictt = 0x1; 13958c2ecf20Sopenharmony_ci } else { 13968c2ecf20Sopenharmony_ci icpt = 0x1; /* enable Rx ints by setting pkt thr to 1 */ 13978c2ecf20Sopenharmony_ci ictt = 0; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) { 14018c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, i, ENETC_RBICR1, ictt); 14028c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, i, ENETC_RBICR0, ENETC_RBICR0_ICEN | icpt); 14038c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, i, ENETC_RBIER, ENETC_RBIER_RXTIE); 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci if (priv->ic_mode & ENETC_IC_TX_MANUAL) 14078c2ecf20Sopenharmony_ci icpt = ENETC_TBICR0_SET_ICPT(ENETC_TXIC_PKTTHR); 14088c2ecf20Sopenharmony_ci else 14098c2ecf20Sopenharmony_ci icpt = 0x1; /* enable Tx ints by setting pkt thr to 1 */ 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) { 14128c2ecf20Sopenharmony_ci enetc_txbdr_wr(hw, i, ENETC_TBICR1, priv->tx_ictt); 14138c2ecf20Sopenharmony_ci enetc_txbdr_wr(hw, i, ENETC_TBICR0, ENETC_TBICR0_ICEN | icpt); 14148c2ecf20Sopenharmony_ci enetc_txbdr_wr(hw, i, ENETC_TBIER, ENETC_TBIER_TXTIE); 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci} 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_cistatic void enetc_clear_interrupts(struct enetc_ndev_priv *priv) 14198c2ecf20Sopenharmony_ci{ 14208c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 14218c2ecf20Sopenharmony_ci int i; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) 14248c2ecf20Sopenharmony_ci enetc_txbdr_wr(hw, i, ENETC_TBIER, 0); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) 14278c2ecf20Sopenharmony_ci enetc_rxbdr_wr(hw, i, ENETC_RBIER, 0); 14288c2ecf20Sopenharmony_ci} 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_cistatic int enetc_phylink_connect(struct net_device *ndev) 14318c2ecf20Sopenharmony_ci{ 14328c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 14338c2ecf20Sopenharmony_ci struct ethtool_eee edata; 14348c2ecf20Sopenharmony_ci int err; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci if (!priv->phylink) 14378c2ecf20Sopenharmony_ci return 0; /* phy-less mode */ 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci err = phylink_of_phy_connect(priv->phylink, priv->dev->of_node, 0); 14408c2ecf20Sopenharmony_ci if (err) { 14418c2ecf20Sopenharmony_ci dev_err(&ndev->dev, "could not attach to PHY\n"); 14428c2ecf20Sopenharmony_ci return err; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci /* disable EEE autoneg, until ENETC driver supports it */ 14468c2ecf20Sopenharmony_ci memset(&edata, 0, sizeof(struct ethtool_eee)); 14478c2ecf20Sopenharmony_ci phylink_ethtool_set_eee(priv->phylink, &edata); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci return 0; 14508c2ecf20Sopenharmony_ci} 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_civoid enetc_start(struct net_device *ndev) 14538c2ecf20Sopenharmony_ci{ 14548c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 14558c2ecf20Sopenharmony_ci int i; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci enetc_setup_interrupts(priv); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci for (i = 0; i < priv->bdr_int_num; i++) { 14608c2ecf20Sopenharmony_ci int irq = pci_irq_vector(priv->si->pdev, 14618c2ecf20Sopenharmony_ci ENETC_BDR_INT_BASE_IDX + i); 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci napi_enable(&priv->int_vector[i]->napi); 14648c2ecf20Sopenharmony_ci enable_irq(irq); 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci if (priv->phylink) 14688c2ecf20Sopenharmony_ci phylink_start(priv->phylink); 14698c2ecf20Sopenharmony_ci else 14708c2ecf20Sopenharmony_ci netif_carrier_on(ndev); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci netif_tx_start_all_queues(ndev); 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ciint enetc_open(struct net_device *ndev) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 14788c2ecf20Sopenharmony_ci int err; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci err = enetc_setup_irqs(priv); 14818c2ecf20Sopenharmony_ci if (err) 14828c2ecf20Sopenharmony_ci return err; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci err = enetc_phylink_connect(ndev); 14858c2ecf20Sopenharmony_ci if (err) 14868c2ecf20Sopenharmony_ci goto err_phy_connect; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci err = enetc_alloc_tx_resources(priv); 14898c2ecf20Sopenharmony_ci if (err) 14908c2ecf20Sopenharmony_ci goto err_alloc_tx; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci err = enetc_alloc_rx_resources(priv); 14938c2ecf20Sopenharmony_ci if (err) 14948c2ecf20Sopenharmony_ci goto err_alloc_rx; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci err = netif_set_real_num_tx_queues(ndev, priv->num_tx_rings); 14978c2ecf20Sopenharmony_ci if (err) 14988c2ecf20Sopenharmony_ci goto err_set_queues; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci err = netif_set_real_num_rx_queues(ndev, priv->num_rx_rings); 15018c2ecf20Sopenharmony_ci if (err) 15028c2ecf20Sopenharmony_ci goto err_set_queues; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci enetc_setup_bdrs(priv); 15058c2ecf20Sopenharmony_ci enetc_start(ndev); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci return 0; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_cierr_set_queues: 15108c2ecf20Sopenharmony_ci enetc_free_rx_resources(priv); 15118c2ecf20Sopenharmony_cierr_alloc_rx: 15128c2ecf20Sopenharmony_ci enetc_free_tx_resources(priv); 15138c2ecf20Sopenharmony_cierr_alloc_tx: 15148c2ecf20Sopenharmony_ci if (priv->phylink) 15158c2ecf20Sopenharmony_ci phylink_disconnect_phy(priv->phylink); 15168c2ecf20Sopenharmony_cierr_phy_connect: 15178c2ecf20Sopenharmony_ci enetc_free_irqs(priv); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci return err; 15208c2ecf20Sopenharmony_ci} 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_civoid enetc_stop(struct net_device *ndev) 15238c2ecf20Sopenharmony_ci{ 15248c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 15258c2ecf20Sopenharmony_ci int i; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(ndev); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci for (i = 0; i < priv->bdr_int_num; i++) { 15308c2ecf20Sopenharmony_ci int irq = pci_irq_vector(priv->si->pdev, 15318c2ecf20Sopenharmony_ci ENETC_BDR_INT_BASE_IDX + i); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci disable_irq(irq); 15348c2ecf20Sopenharmony_ci napi_synchronize(&priv->int_vector[i]->napi); 15358c2ecf20Sopenharmony_ci napi_disable(&priv->int_vector[i]->napi); 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (priv->phylink) 15398c2ecf20Sopenharmony_ci phylink_stop(priv->phylink); 15408c2ecf20Sopenharmony_ci else 15418c2ecf20Sopenharmony_ci netif_carrier_off(ndev); 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci enetc_clear_interrupts(priv); 15448c2ecf20Sopenharmony_ci} 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ciint enetc_close(struct net_device *ndev) 15478c2ecf20Sopenharmony_ci{ 15488c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci enetc_stop(ndev); 15518c2ecf20Sopenharmony_ci enetc_clear_bdrs(priv); 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci if (priv->phylink) 15548c2ecf20Sopenharmony_ci phylink_disconnect_phy(priv->phylink); 15558c2ecf20Sopenharmony_ci enetc_free_rxtx_rings(priv); 15568c2ecf20Sopenharmony_ci enetc_free_rx_resources(priv); 15578c2ecf20Sopenharmony_ci enetc_free_tx_resources(priv); 15588c2ecf20Sopenharmony_ci enetc_free_irqs(priv); 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci return 0; 15618c2ecf20Sopenharmony_ci} 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_cistatic int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data) 15648c2ecf20Sopenharmony_ci{ 15658c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 15668c2ecf20Sopenharmony_ci struct tc_mqprio_qopt *mqprio = type_data; 15678c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 15688c2ecf20Sopenharmony_ci struct enetc_bdr *tx_ring; 15698c2ecf20Sopenharmony_ci u8 num_tc; 15708c2ecf20Sopenharmony_ci int i; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; 15738c2ecf20Sopenharmony_ci num_tc = mqprio->num_tc; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci if (!num_tc) { 15768c2ecf20Sopenharmony_ci netdev_reset_tc(ndev); 15778c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(ndev, priv->num_tx_rings); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci /* Reset all ring priorities to 0 */ 15808c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) { 15818c2ecf20Sopenharmony_ci tx_ring = priv->tx_ring[i]; 15828c2ecf20Sopenharmony_ci tx_ring->prio = 0; 15838c2ecf20Sopenharmony_ci enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci return 0; 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci /* Check if we have enough BD rings available to accommodate all TCs */ 15908c2ecf20Sopenharmony_ci if (num_tc > priv->num_tx_rings) { 15918c2ecf20Sopenharmony_ci netdev_err(ndev, "Max %d traffic classes supported\n", 15928c2ecf20Sopenharmony_ci priv->num_tx_rings); 15938c2ecf20Sopenharmony_ci return -EINVAL; 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci /* For the moment, we use only one BD ring per TC. 15978c2ecf20Sopenharmony_ci * 15988c2ecf20Sopenharmony_ci * Configure num_tc BD rings with increasing priorities. 15998c2ecf20Sopenharmony_ci */ 16008c2ecf20Sopenharmony_ci for (i = 0; i < num_tc; i++) { 16018c2ecf20Sopenharmony_ci tx_ring = priv->tx_ring[i]; 16028c2ecf20Sopenharmony_ci tx_ring->prio = i; 16038c2ecf20Sopenharmony_ci enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci /* Reset the number of netdev queues based on the TC count */ 16078c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(ndev, num_tc); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci netdev_set_num_tc(ndev, num_tc); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci /* Each TC is associated with one netdev queue */ 16128c2ecf20Sopenharmony_ci for (i = 0; i < num_tc; i++) 16138c2ecf20Sopenharmony_ci netdev_set_tc_queue(ndev, i, 1, i); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci return 0; 16168c2ecf20Sopenharmony_ci} 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ciint enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type, 16198c2ecf20Sopenharmony_ci void *type_data) 16208c2ecf20Sopenharmony_ci{ 16218c2ecf20Sopenharmony_ci switch (type) { 16228c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_MQPRIO: 16238c2ecf20Sopenharmony_ci return enetc_setup_tc_mqprio(ndev, type_data); 16248c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_TAPRIO: 16258c2ecf20Sopenharmony_ci return enetc_setup_tc_taprio(ndev, type_data); 16268c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_CBS: 16278c2ecf20Sopenharmony_ci return enetc_setup_tc_cbs(ndev, type_data); 16288c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_ETF: 16298c2ecf20Sopenharmony_ci return enetc_setup_tc_txtime(ndev, type_data); 16308c2ecf20Sopenharmony_ci case TC_SETUP_BLOCK: 16318c2ecf20Sopenharmony_ci return enetc_setup_tc_psfp(ndev, type_data); 16328c2ecf20Sopenharmony_ci default: 16338c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_cistruct net_device_stats *enetc_get_stats(struct net_device *ndev) 16388c2ecf20Sopenharmony_ci{ 16398c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 16408c2ecf20Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 16418c2ecf20Sopenharmony_ci unsigned long packets = 0, bytes = 0; 16428c2ecf20Sopenharmony_ci int i; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) { 16458c2ecf20Sopenharmony_ci packets += priv->rx_ring[i]->stats.packets; 16468c2ecf20Sopenharmony_ci bytes += priv->rx_ring[i]->stats.bytes; 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci stats->rx_packets = packets; 16508c2ecf20Sopenharmony_ci stats->rx_bytes = bytes; 16518c2ecf20Sopenharmony_ci bytes = 0; 16528c2ecf20Sopenharmony_ci packets = 0; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) { 16558c2ecf20Sopenharmony_ci packets += priv->tx_ring[i]->stats.packets; 16568c2ecf20Sopenharmony_ci bytes += priv->tx_ring[i]->stats.bytes; 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci stats->tx_packets = packets; 16608c2ecf20Sopenharmony_ci stats->tx_bytes = bytes; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci return stats; 16638c2ecf20Sopenharmony_ci} 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_cistatic int enetc_set_rss(struct net_device *ndev, int en) 16668c2ecf20Sopenharmony_ci{ 16678c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 16688c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 16698c2ecf20Sopenharmony_ci u32 reg; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SIRBGCR, priv->num_rx_rings); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci reg = enetc_rd(hw, ENETC_SIMR); 16748c2ecf20Sopenharmony_ci reg &= ~ENETC_SIMR_RSSE; 16758c2ecf20Sopenharmony_ci reg |= (en) ? ENETC_SIMR_RSSE : 0; 16768c2ecf20Sopenharmony_ci enetc_wr(hw, ENETC_SIMR, reg); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci return 0; 16798c2ecf20Sopenharmony_ci} 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_cistatic void enetc_enable_rxvlan(struct net_device *ndev, bool en) 16828c2ecf20Sopenharmony_ci{ 16838c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 16848c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 16858c2ecf20Sopenharmony_ci int i; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) 16888c2ecf20Sopenharmony_ci enetc_bdr_enable_rxvlan(hw, i, en); 16898c2ecf20Sopenharmony_ci} 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_cistatic void enetc_enable_txvlan(struct net_device *ndev, bool en) 16928c2ecf20Sopenharmony_ci{ 16938c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 16948c2ecf20Sopenharmony_ci struct enetc_hw *hw = &priv->si->hw; 16958c2ecf20Sopenharmony_ci int i; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) 16988c2ecf20Sopenharmony_ci enetc_bdr_enable_txvlan(hw, i, en); 16998c2ecf20Sopenharmony_ci} 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_civoid enetc_set_features(struct net_device *ndev, netdev_features_t features) 17028c2ecf20Sopenharmony_ci{ 17038c2ecf20Sopenharmony_ci netdev_features_t changed = ndev->features ^ features; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (changed & NETIF_F_RXHASH) 17068c2ecf20Sopenharmony_ci enetc_set_rss(ndev, !!(features & NETIF_F_RXHASH)); 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if (changed & NETIF_F_HW_VLAN_CTAG_RX) 17098c2ecf20Sopenharmony_ci enetc_enable_rxvlan(ndev, 17108c2ecf20Sopenharmony_ci !!(features & NETIF_F_HW_VLAN_CTAG_RX)); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (changed & NETIF_F_HW_VLAN_CTAG_TX) 17138c2ecf20Sopenharmony_ci enetc_enable_txvlan(ndev, 17148c2ecf20Sopenharmony_ci !!(features & NETIF_F_HW_VLAN_CTAG_TX)); 17158c2ecf20Sopenharmony_ci} 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_ENETC_PTP_CLOCK 17188c2ecf20Sopenharmony_cistatic int enetc_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr) 17198c2ecf20Sopenharmony_ci{ 17208c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 17218c2ecf20Sopenharmony_ci struct hwtstamp_config config; 17228c2ecf20Sopenharmony_ci int ao; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 17258c2ecf20Sopenharmony_ci return -EFAULT; 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci switch (config.tx_type) { 17288c2ecf20Sopenharmony_ci case HWTSTAMP_TX_OFF: 17298c2ecf20Sopenharmony_ci priv->active_offloads &= ~ENETC_F_TX_TSTAMP; 17308c2ecf20Sopenharmony_ci break; 17318c2ecf20Sopenharmony_ci case HWTSTAMP_TX_ON: 17328c2ecf20Sopenharmony_ci priv->active_offloads |= ENETC_F_TX_TSTAMP; 17338c2ecf20Sopenharmony_ci break; 17348c2ecf20Sopenharmony_ci default: 17358c2ecf20Sopenharmony_ci return -ERANGE; 17368c2ecf20Sopenharmony_ci } 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci ao = priv->active_offloads; 17398c2ecf20Sopenharmony_ci switch (config.rx_filter) { 17408c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 17418c2ecf20Sopenharmony_ci priv->active_offloads &= ~ENETC_F_RX_TSTAMP; 17428c2ecf20Sopenharmony_ci break; 17438c2ecf20Sopenharmony_ci default: 17448c2ecf20Sopenharmony_ci priv->active_offloads |= ENETC_F_RX_TSTAMP; 17458c2ecf20Sopenharmony_ci config.rx_filter = HWTSTAMP_FILTER_ALL; 17468c2ecf20Sopenharmony_ci } 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci if (netif_running(ndev) && ao != priv->active_offloads) { 17498c2ecf20Sopenharmony_ci enetc_close(ndev); 17508c2ecf20Sopenharmony_ci enetc_open(ndev); 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? 17548c2ecf20Sopenharmony_ci -EFAULT : 0; 17558c2ecf20Sopenharmony_ci} 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_cistatic int enetc_hwtstamp_get(struct net_device *ndev, struct ifreq *ifr) 17588c2ecf20Sopenharmony_ci{ 17598c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 17608c2ecf20Sopenharmony_ci struct hwtstamp_config config; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci config.flags = 0; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci if (priv->active_offloads & ENETC_F_TX_TSTAMP) 17658c2ecf20Sopenharmony_ci config.tx_type = HWTSTAMP_TX_ON; 17668c2ecf20Sopenharmony_ci else 17678c2ecf20Sopenharmony_ci config.tx_type = HWTSTAMP_TX_OFF; 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci config.rx_filter = (priv->active_offloads & ENETC_F_RX_TSTAMP) ? 17708c2ecf20Sopenharmony_ci HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? 17738c2ecf20Sopenharmony_ci -EFAULT : 0; 17748c2ecf20Sopenharmony_ci} 17758c2ecf20Sopenharmony_ci#endif 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ciint enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci struct enetc_ndev_priv *priv = netdev_priv(ndev); 17808c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_ENETC_PTP_CLOCK 17818c2ecf20Sopenharmony_ci if (cmd == SIOCSHWTSTAMP) 17828c2ecf20Sopenharmony_ci return enetc_hwtstamp_set(ndev, rq); 17838c2ecf20Sopenharmony_ci if (cmd == SIOCGHWTSTAMP) 17848c2ecf20Sopenharmony_ci return enetc_hwtstamp_get(ndev, rq); 17858c2ecf20Sopenharmony_ci#endif 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci if (!priv->phylink) 17888c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci return phylink_mii_ioctl(priv->phylink, rq, cmd); 17918c2ecf20Sopenharmony_ci} 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ciint enetc_alloc_msix(struct enetc_ndev_priv *priv) 17948c2ecf20Sopenharmony_ci{ 17958c2ecf20Sopenharmony_ci struct pci_dev *pdev = priv->si->pdev; 17968c2ecf20Sopenharmony_ci int v_tx_rings; 17978c2ecf20Sopenharmony_ci int i, n, err, nvec; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci nvec = ENETC_BDR_INT_BASE_IDX + priv->bdr_int_num; 18008c2ecf20Sopenharmony_ci /* allocate MSIX for both messaging and Rx/Tx interrupts */ 18018c2ecf20Sopenharmony_ci n = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_MSIX); 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci if (n < 0) 18048c2ecf20Sopenharmony_ci return n; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci if (n != nvec) 18078c2ecf20Sopenharmony_ci return -EPERM; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci /* # of tx rings per int vector */ 18108c2ecf20Sopenharmony_ci v_tx_rings = priv->num_tx_rings / priv->bdr_int_num; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci for (i = 0; i < priv->bdr_int_num; i++) { 18138c2ecf20Sopenharmony_ci struct enetc_int_vector *v; 18148c2ecf20Sopenharmony_ci struct enetc_bdr *bdr; 18158c2ecf20Sopenharmony_ci int j; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci v = kzalloc(struct_size(v, tx_ring, v_tx_rings), GFP_KERNEL); 18188c2ecf20Sopenharmony_ci if (!v) { 18198c2ecf20Sopenharmony_ci err = -ENOMEM; 18208c2ecf20Sopenharmony_ci goto fail; 18218c2ecf20Sopenharmony_ci } 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci priv->int_vector[i] = v; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci /* init defaults for adaptive IC */ 18268c2ecf20Sopenharmony_ci if (priv->ic_mode & ENETC_IC_RX_ADAPTIVE) { 18278c2ecf20Sopenharmony_ci v->rx_ictt = 0x1; 18288c2ecf20Sopenharmony_ci v->rx_dim_en = true; 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci INIT_WORK(&v->rx_dim.work, enetc_rx_dim_work); 18318c2ecf20Sopenharmony_ci netif_napi_add(priv->ndev, &v->napi, enetc_poll, 18328c2ecf20Sopenharmony_ci NAPI_POLL_WEIGHT); 18338c2ecf20Sopenharmony_ci v->count_tx_rings = v_tx_rings; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci for (j = 0; j < v_tx_rings; j++) { 18368c2ecf20Sopenharmony_ci int idx; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci /* default tx ring mapping policy */ 18398c2ecf20Sopenharmony_ci if (priv->bdr_int_num == ENETC_MAX_BDR_INT) 18408c2ecf20Sopenharmony_ci idx = 2 * j + i; /* 2 CPUs */ 18418c2ecf20Sopenharmony_ci else 18428c2ecf20Sopenharmony_ci idx = j + i * v_tx_rings; /* default */ 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci __set_bit(idx, &v->tx_rings_map); 18458c2ecf20Sopenharmony_ci bdr = &v->tx_ring[j]; 18468c2ecf20Sopenharmony_ci bdr->index = idx; 18478c2ecf20Sopenharmony_ci bdr->ndev = priv->ndev; 18488c2ecf20Sopenharmony_ci bdr->dev = priv->dev; 18498c2ecf20Sopenharmony_ci bdr->bd_count = priv->tx_bd_count; 18508c2ecf20Sopenharmony_ci priv->tx_ring[idx] = bdr; 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci bdr = &v->rx_ring; 18548c2ecf20Sopenharmony_ci bdr->index = i; 18558c2ecf20Sopenharmony_ci bdr->ndev = priv->ndev; 18568c2ecf20Sopenharmony_ci bdr->dev = priv->dev; 18578c2ecf20Sopenharmony_ci bdr->bd_count = priv->rx_bd_count; 18588c2ecf20Sopenharmony_ci priv->rx_ring[i] = bdr; 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci return 0; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_cifail: 18648c2ecf20Sopenharmony_ci while (i--) { 18658c2ecf20Sopenharmony_ci netif_napi_del(&priv->int_vector[i]->napi); 18668c2ecf20Sopenharmony_ci cancel_work_sync(&priv->int_vector[i]->rx_dim.work); 18678c2ecf20Sopenharmony_ci kfree(priv->int_vector[i]); 18688c2ecf20Sopenharmony_ci } 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci pci_free_irq_vectors(pdev); 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci return err; 18738c2ecf20Sopenharmony_ci} 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_civoid enetc_free_msix(struct enetc_ndev_priv *priv) 18768c2ecf20Sopenharmony_ci{ 18778c2ecf20Sopenharmony_ci int i; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci for (i = 0; i < priv->bdr_int_num; i++) { 18808c2ecf20Sopenharmony_ci struct enetc_int_vector *v = priv->int_vector[i]; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci netif_napi_del(&v->napi); 18838c2ecf20Sopenharmony_ci cancel_work_sync(&v->rx_dim.work); 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_rx_rings; i++) 18878c2ecf20Sopenharmony_ci priv->rx_ring[i] = NULL; 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_tx_rings; i++) 18908c2ecf20Sopenharmony_ci priv->tx_ring[i] = NULL; 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci for (i = 0; i < priv->bdr_int_num; i++) { 18938c2ecf20Sopenharmony_ci kfree(priv->int_vector[i]); 18948c2ecf20Sopenharmony_ci priv->int_vector[i] = NULL; 18958c2ecf20Sopenharmony_ci } 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci /* disable all MSIX for this device */ 18988c2ecf20Sopenharmony_ci pci_free_irq_vectors(priv->si->pdev); 18998c2ecf20Sopenharmony_ci} 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_cistatic void enetc_kfree_si(struct enetc_si *si) 19028c2ecf20Sopenharmony_ci{ 19038c2ecf20Sopenharmony_ci char *p = (char *)si - si->pad; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci kfree(p); 19068c2ecf20Sopenharmony_ci} 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_cistatic void enetc_detect_errata(struct enetc_si *si) 19098c2ecf20Sopenharmony_ci{ 19108c2ecf20Sopenharmony_ci if (si->pdev->revision == ENETC_REV1) 19118c2ecf20Sopenharmony_ci si->errata = ENETC_ERR_TXCSUM | ENETC_ERR_VLAN_ISOL | 19128c2ecf20Sopenharmony_ci ENETC_ERR_UCMCSWP; 19138c2ecf20Sopenharmony_ci} 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ciint enetc_pci_probe(struct pci_dev *pdev, const char *name, int sizeof_priv) 19168c2ecf20Sopenharmony_ci{ 19178c2ecf20Sopenharmony_ci struct enetc_si *si, *p; 19188c2ecf20Sopenharmony_ci struct enetc_hw *hw; 19198c2ecf20Sopenharmony_ci size_t alloc_size; 19208c2ecf20Sopenharmony_ci int err, len; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci pcie_flr(pdev); 19238c2ecf20Sopenharmony_ci err = pci_enable_device_mem(pdev); 19248c2ecf20Sopenharmony_ci if (err) { 19258c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "device enable failed\n"); 19268c2ecf20Sopenharmony_ci return err; 19278c2ecf20Sopenharmony_ci } 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci /* set up for high or low dma */ 19308c2ecf20Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 19318c2ecf20Sopenharmony_ci if (err) { 19328c2ecf20Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 19338c2ecf20Sopenharmony_ci if (err) { 19348c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 19358c2ecf20Sopenharmony_ci "DMA configuration failed: 0x%x\n", err); 19368c2ecf20Sopenharmony_ci goto err_dma; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci err = pci_request_mem_regions(pdev, name); 19418c2ecf20Sopenharmony_ci if (err) { 19428c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "pci_request_regions failed err=%d\n", err); 19438c2ecf20Sopenharmony_ci goto err_pci_mem_reg; 19448c2ecf20Sopenharmony_ci } 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci pci_set_master(pdev); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci alloc_size = sizeof(struct enetc_si); 19498c2ecf20Sopenharmony_ci if (sizeof_priv) { 19508c2ecf20Sopenharmony_ci /* align priv to 32B */ 19518c2ecf20Sopenharmony_ci alloc_size = ALIGN(alloc_size, ENETC_SI_ALIGN); 19528c2ecf20Sopenharmony_ci alloc_size += sizeof_priv; 19538c2ecf20Sopenharmony_ci } 19548c2ecf20Sopenharmony_ci /* force 32B alignment for enetc_si */ 19558c2ecf20Sopenharmony_ci alloc_size += ENETC_SI_ALIGN - 1; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci p = kzalloc(alloc_size, GFP_KERNEL); 19588c2ecf20Sopenharmony_ci if (!p) { 19598c2ecf20Sopenharmony_ci err = -ENOMEM; 19608c2ecf20Sopenharmony_ci goto err_alloc_si; 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci si = PTR_ALIGN(p, ENETC_SI_ALIGN); 19648c2ecf20Sopenharmony_ci si->pad = (char *)si - (char *)p; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, si); 19678c2ecf20Sopenharmony_ci si->pdev = pdev; 19688c2ecf20Sopenharmony_ci hw = &si->hw; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci len = pci_resource_len(pdev, ENETC_BAR_REGS); 19718c2ecf20Sopenharmony_ci hw->reg = ioremap(pci_resource_start(pdev, ENETC_BAR_REGS), len); 19728c2ecf20Sopenharmony_ci if (!hw->reg) { 19738c2ecf20Sopenharmony_ci err = -ENXIO; 19748c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "ioremap() failed\n"); 19758c2ecf20Sopenharmony_ci goto err_ioremap; 19768c2ecf20Sopenharmony_ci } 19778c2ecf20Sopenharmony_ci if (len > ENETC_PORT_BASE) 19788c2ecf20Sopenharmony_ci hw->port = hw->reg + ENETC_PORT_BASE; 19798c2ecf20Sopenharmony_ci if (len > ENETC_GLOBAL_BASE) 19808c2ecf20Sopenharmony_ci hw->global = hw->reg + ENETC_GLOBAL_BASE; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci enetc_detect_errata(si); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci return 0; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_cierr_ioremap: 19878c2ecf20Sopenharmony_ci enetc_kfree_si(si); 19888c2ecf20Sopenharmony_cierr_alloc_si: 19898c2ecf20Sopenharmony_ci pci_release_mem_regions(pdev); 19908c2ecf20Sopenharmony_cierr_pci_mem_reg: 19918c2ecf20Sopenharmony_cierr_dma: 19928c2ecf20Sopenharmony_ci pci_disable_device(pdev); 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci return err; 19958c2ecf20Sopenharmony_ci} 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_civoid enetc_pci_remove(struct pci_dev *pdev) 19988c2ecf20Sopenharmony_ci{ 19998c2ecf20Sopenharmony_ci struct enetc_si *si = pci_get_drvdata(pdev); 20008c2ecf20Sopenharmony_ci struct enetc_hw *hw = &si->hw; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci iounmap(hw->reg); 20038c2ecf20Sopenharmony_ci enetc_kfree_si(si); 20048c2ecf20Sopenharmony_ci pci_release_mem_regions(pdev); 20058c2ecf20Sopenharmony_ci pci_disable_device(pdev); 20068c2ecf20Sopenharmony_ci} 2007