18c2ecf20Sopenharmony_ci/* Synopsys DesignWare Core Enterprise Ethernet (XLGMAC) Driver 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Copyright (c) 2017 Synopsys, Inc. (www.synopsys.com) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This program is dual-licensed; you may select either version 2 of 68c2ecf20Sopenharmony_ci * the GNU General Public License ("GPL") or BSD license ("BSD"). 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This Synopsys DWC XLGMAC software driver and associated documentation 98c2ecf20Sopenharmony_ci * (hereinafter the "Software") is an unsupported proprietary work of 108c2ecf20Sopenharmony_ci * Synopsys, Inc. unless otherwise expressly agreed to in writing between 118c2ecf20Sopenharmony_ci * Synopsys and you. The Software IS NOT an item of Licensed Software or a 128c2ecf20Sopenharmony_ci * Licensed Product under any End User Software License Agreement or 138c2ecf20Sopenharmony_ci * Agreement for Licensed Products with Synopsys or any supplement thereto. 148c2ecf20Sopenharmony_ci * Synopsys is a registered trademark of Synopsys, Inc. Other names included 158c2ecf20Sopenharmony_ci * in the SOFTWARE may be the trademarks of their respective owners. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/phy.h> 198c2ecf20Sopenharmony_ci#include <linux/mdio.h> 208c2ecf20Sopenharmony_ci#include <linux/clk.h> 218c2ecf20Sopenharmony_ci#include <linux/bitrev.h> 228c2ecf20Sopenharmony_ci#include <linux/crc32.h> 238c2ecf20Sopenharmony_ci#include <linux/crc32poly.h> 248c2ecf20Sopenharmony_ci#include <linux/dcbnl.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "dwc-xlgmac.h" 278c2ecf20Sopenharmony_ci#include "dwc-xlgmac-reg.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int xlgmac_tx_complete(struct xlgmac_dma_desc *dma_desc) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci return !XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 328c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_OWN_POS, 338c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_OWN_LEN); 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic int xlgmac_disable_rx_csum(struct xlgmac_pdata *pdata) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci u32 regval; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_RCR); 418c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_IPC_POS, 428c2ecf20Sopenharmony_ci MAC_RCR_IPC_LEN, 0); 438c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RCR); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int xlgmac_enable_rx_csum(struct xlgmac_pdata *pdata) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci u32 regval; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_RCR); 538c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_IPC_POS, 548c2ecf20Sopenharmony_ci MAC_RCR_IPC_LEN, 1); 558c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RCR); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return 0; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int xlgmac_set_mac_address(struct xlgmac_pdata *pdata, u8 *addr) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci unsigned int mac_addr_hi, mac_addr_lo; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci mac_addr_hi = (addr[5] << 8) | (addr[4] << 0); 658c2ecf20Sopenharmony_ci mac_addr_lo = (addr[3] << 24) | (addr[2] << 16) | 668c2ecf20Sopenharmony_ci (addr[1] << 8) | (addr[0] << 0); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci writel(mac_addr_hi, pdata->mac_regs + MAC_MACA0HR); 698c2ecf20Sopenharmony_ci writel(mac_addr_lo, pdata->mac_regs + MAC_MACA0LR); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return 0; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic void xlgmac_set_mac_reg(struct xlgmac_pdata *pdata, 758c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha, 768c2ecf20Sopenharmony_ci unsigned int *mac_reg) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci unsigned int mac_addr_hi, mac_addr_lo; 798c2ecf20Sopenharmony_ci u8 *mac_addr; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci mac_addr_lo = 0; 828c2ecf20Sopenharmony_ci mac_addr_hi = 0; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (ha) { 858c2ecf20Sopenharmony_ci mac_addr = (u8 *)&mac_addr_lo; 868c2ecf20Sopenharmony_ci mac_addr[0] = ha->addr[0]; 878c2ecf20Sopenharmony_ci mac_addr[1] = ha->addr[1]; 888c2ecf20Sopenharmony_ci mac_addr[2] = ha->addr[2]; 898c2ecf20Sopenharmony_ci mac_addr[3] = ha->addr[3]; 908c2ecf20Sopenharmony_ci mac_addr = (u8 *)&mac_addr_hi; 918c2ecf20Sopenharmony_ci mac_addr[0] = ha->addr[4]; 928c2ecf20Sopenharmony_ci mac_addr[1] = ha->addr[5]; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 958c2ecf20Sopenharmony_ci "adding mac address %pM at %#x\n", 968c2ecf20Sopenharmony_ci ha->addr, *mac_reg); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci mac_addr_hi = XLGMAC_SET_REG_BITS(mac_addr_hi, 998c2ecf20Sopenharmony_ci MAC_MACA1HR_AE_POS, 1008c2ecf20Sopenharmony_ci MAC_MACA1HR_AE_LEN, 1018c2ecf20Sopenharmony_ci 1); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci writel(mac_addr_hi, pdata->mac_regs + *mac_reg); 1058c2ecf20Sopenharmony_ci *mac_reg += MAC_MACA_INC; 1068c2ecf20Sopenharmony_ci writel(mac_addr_lo, pdata->mac_regs + *mac_reg); 1078c2ecf20Sopenharmony_ci *mac_reg += MAC_MACA_INC; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int xlgmac_enable_rx_vlan_stripping(struct xlgmac_pdata *pdata) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci u32 regval; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_VLANTR); 1158c2ecf20Sopenharmony_ci /* Put the VLAN tag in the Rx descriptor */ 1168c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANTR_EVLRXS_POS, 1178c2ecf20Sopenharmony_ci MAC_VLANTR_EVLRXS_LEN, 1); 1188c2ecf20Sopenharmony_ci /* Don't check the VLAN type */ 1198c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANTR_DOVLTC_POS, 1208c2ecf20Sopenharmony_ci MAC_VLANTR_DOVLTC_LEN, 1); 1218c2ecf20Sopenharmony_ci /* Check only C-TAG (0x8100) packets */ 1228c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANTR_ERSVLM_POS, 1238c2ecf20Sopenharmony_ci MAC_VLANTR_ERSVLM_LEN, 0); 1248c2ecf20Sopenharmony_ci /* Don't consider an S-TAG (0x88A8) packet as a VLAN packet */ 1258c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANTR_ESVL_POS, 1268c2ecf20Sopenharmony_ci MAC_VLANTR_ESVL_LEN, 0); 1278c2ecf20Sopenharmony_ci /* Enable VLAN tag stripping */ 1288c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANTR_EVLS_POS, 1298c2ecf20Sopenharmony_ci MAC_VLANTR_EVLS_LEN, 0x3); 1308c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_VLANTR); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int xlgmac_disable_rx_vlan_stripping(struct xlgmac_pdata *pdata) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci u32 regval; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_VLANTR); 1408c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANTR_EVLS_POS, 1418c2ecf20Sopenharmony_ci MAC_VLANTR_EVLS_LEN, 0); 1428c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_VLANTR); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int xlgmac_enable_rx_vlan_filtering(struct xlgmac_pdata *pdata) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci u32 regval; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_PFR); 1528c2ecf20Sopenharmony_ci /* Enable VLAN filtering */ 1538c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_PFR_VTFE_POS, 1548c2ecf20Sopenharmony_ci MAC_PFR_VTFE_LEN, 1); 1558c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_PFR); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_VLANTR); 1588c2ecf20Sopenharmony_ci /* Enable VLAN Hash Table filtering */ 1598c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANTR_VTHM_POS, 1608c2ecf20Sopenharmony_ci MAC_VLANTR_VTHM_LEN, 1); 1618c2ecf20Sopenharmony_ci /* Disable VLAN tag inverse matching */ 1628c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANTR_VTIM_POS, 1638c2ecf20Sopenharmony_ci MAC_VLANTR_VTIM_LEN, 0); 1648c2ecf20Sopenharmony_ci /* Only filter on the lower 12-bits of the VLAN tag */ 1658c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANTR_ETV_POS, 1668c2ecf20Sopenharmony_ci MAC_VLANTR_ETV_LEN, 1); 1678c2ecf20Sopenharmony_ci /* In order for the VLAN Hash Table filtering to be effective, 1688c2ecf20Sopenharmony_ci * the VLAN tag identifier in the VLAN Tag Register must not 1698c2ecf20Sopenharmony_ci * be zero. Set the VLAN tag identifier to "1" to enable the 1708c2ecf20Sopenharmony_ci * VLAN Hash Table filtering. This implies that a VLAN tag of 1718c2ecf20Sopenharmony_ci * 1 will always pass filtering. 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANTR_VL_POS, 1748c2ecf20Sopenharmony_ci MAC_VLANTR_VL_LEN, 1); 1758c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_VLANTR); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int xlgmac_disable_rx_vlan_filtering(struct xlgmac_pdata *pdata) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci u32 regval; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_PFR); 1858c2ecf20Sopenharmony_ci /* Disable VLAN filtering */ 1868c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_PFR_VTFE_POS, 1878c2ecf20Sopenharmony_ci MAC_PFR_VTFE_LEN, 0); 1888c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_PFR); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic u32 xlgmac_vid_crc32_le(__le16 vid_le) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci unsigned char *data = (unsigned char *)&vid_le; 1968c2ecf20Sopenharmony_ci unsigned char data_byte = 0; 1978c2ecf20Sopenharmony_ci u32 crc = ~0; 1988c2ecf20Sopenharmony_ci u32 temp = 0; 1998c2ecf20Sopenharmony_ci int i, bits; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci bits = get_bitmask_order(VLAN_VID_MASK); 2028c2ecf20Sopenharmony_ci for (i = 0; i < bits; i++) { 2038c2ecf20Sopenharmony_ci if ((i % 8) == 0) 2048c2ecf20Sopenharmony_ci data_byte = data[i / 8]; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci temp = ((crc & 1) ^ data_byte) & 1; 2078c2ecf20Sopenharmony_ci crc >>= 1; 2088c2ecf20Sopenharmony_ci data_byte >>= 1; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (temp) 2118c2ecf20Sopenharmony_ci crc ^= CRC32_POLY_LE; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return crc; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic int xlgmac_update_vlan_hash_table(struct xlgmac_pdata *pdata) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci u16 vlan_hash_table = 0; 2208c2ecf20Sopenharmony_ci __le16 vid_le; 2218c2ecf20Sopenharmony_ci u32 regval; 2228c2ecf20Sopenharmony_ci u32 crc; 2238c2ecf20Sopenharmony_ci u16 vid; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* Generate the VLAN Hash Table value */ 2268c2ecf20Sopenharmony_ci for_each_set_bit(vid, pdata->active_vlans, VLAN_N_VID) { 2278c2ecf20Sopenharmony_ci /* Get the CRC32 value of the VLAN ID */ 2288c2ecf20Sopenharmony_ci vid_le = cpu_to_le16(vid); 2298c2ecf20Sopenharmony_ci crc = bitrev32(~xlgmac_vid_crc32_le(vid_le)) >> 28; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci vlan_hash_table |= (1 << crc); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_VLANHTR); 2358c2ecf20Sopenharmony_ci /* Set the VLAN Hash Table filtering register */ 2368c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANHTR_VLHT_POS, 2378c2ecf20Sopenharmony_ci MAC_VLANHTR_VLHT_LEN, vlan_hash_table); 2388c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_VLANHTR); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return 0; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int xlgmac_set_promiscuous_mode(struct xlgmac_pdata *pdata, 2448c2ecf20Sopenharmony_ci unsigned int enable) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci unsigned int val = enable ? 1 : 0; 2478c2ecf20Sopenharmony_ci u32 regval; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci regval = XLGMAC_GET_REG_BITS(readl(pdata->mac_regs + MAC_PFR), 2508c2ecf20Sopenharmony_ci MAC_PFR_PR_POS, MAC_PFR_PR_LEN); 2518c2ecf20Sopenharmony_ci if (regval == val) 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, "%s promiscuous mode\n", 2558c2ecf20Sopenharmony_ci enable ? "entering" : "leaving"); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_PFR); 2588c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_PFR_PR_POS, 2598c2ecf20Sopenharmony_ci MAC_PFR_PR_LEN, val); 2608c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_PFR); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Hardware will still perform VLAN filtering in promiscuous mode */ 2638c2ecf20Sopenharmony_ci if (enable) { 2648c2ecf20Sopenharmony_ci xlgmac_disable_rx_vlan_filtering(pdata); 2658c2ecf20Sopenharmony_ci } else { 2668c2ecf20Sopenharmony_ci if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER) 2678c2ecf20Sopenharmony_ci xlgmac_enable_rx_vlan_filtering(pdata); 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int xlgmac_set_all_multicast_mode(struct xlgmac_pdata *pdata, 2748c2ecf20Sopenharmony_ci unsigned int enable) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci unsigned int val = enable ? 1 : 0; 2778c2ecf20Sopenharmony_ci u32 regval; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci regval = XLGMAC_GET_REG_BITS(readl(pdata->mac_regs + MAC_PFR), 2808c2ecf20Sopenharmony_ci MAC_PFR_PM_POS, MAC_PFR_PM_LEN); 2818c2ecf20Sopenharmony_ci if (regval == val) 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, "%s allmulti mode\n", 2858c2ecf20Sopenharmony_ci enable ? "entering" : "leaving"); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_PFR); 2888c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_PFR_PM_POS, 2898c2ecf20Sopenharmony_ci MAC_PFR_PM_LEN, val); 2908c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_PFR); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic void xlgmac_set_mac_addn_addrs(struct xlgmac_pdata *pdata) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct net_device *netdev = pdata->netdev; 2988c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 2998c2ecf20Sopenharmony_ci unsigned int addn_macs; 3008c2ecf20Sopenharmony_ci unsigned int mac_reg; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci mac_reg = MAC_MACA1HR; 3038c2ecf20Sopenharmony_ci addn_macs = pdata->hw_feat.addn_mac; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (netdev_uc_count(netdev) > addn_macs) { 3068c2ecf20Sopenharmony_ci xlgmac_set_promiscuous_mode(pdata, 1); 3078c2ecf20Sopenharmony_ci } else { 3088c2ecf20Sopenharmony_ci netdev_for_each_uc_addr(ha, netdev) { 3098c2ecf20Sopenharmony_ci xlgmac_set_mac_reg(pdata, ha, &mac_reg); 3108c2ecf20Sopenharmony_ci addn_macs--; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (netdev_mc_count(netdev) > addn_macs) { 3148c2ecf20Sopenharmony_ci xlgmac_set_all_multicast_mode(pdata, 1); 3158c2ecf20Sopenharmony_ci } else { 3168c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) { 3178c2ecf20Sopenharmony_ci xlgmac_set_mac_reg(pdata, ha, &mac_reg); 3188c2ecf20Sopenharmony_ci addn_macs--; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* Clear remaining additional MAC address entries */ 3248c2ecf20Sopenharmony_ci while (addn_macs--) 3258c2ecf20Sopenharmony_ci xlgmac_set_mac_reg(pdata, NULL, &mac_reg); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic void xlgmac_set_mac_hash_table(struct xlgmac_pdata *pdata) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci unsigned int hash_table_shift, hash_table_count; 3318c2ecf20Sopenharmony_ci u32 hash_table[XLGMAC_MAC_HASH_TABLE_SIZE]; 3328c2ecf20Sopenharmony_ci struct net_device *netdev = pdata->netdev; 3338c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 3348c2ecf20Sopenharmony_ci unsigned int hash_reg; 3358c2ecf20Sopenharmony_ci unsigned int i; 3368c2ecf20Sopenharmony_ci u32 crc; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci hash_table_shift = 26 - (pdata->hw_feat.hash_table_size >> 7); 3398c2ecf20Sopenharmony_ci hash_table_count = pdata->hw_feat.hash_table_size / 32; 3408c2ecf20Sopenharmony_ci memset(hash_table, 0, sizeof(hash_table)); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* Build the MAC Hash Table register values */ 3438c2ecf20Sopenharmony_ci netdev_for_each_uc_addr(ha, netdev) { 3448c2ecf20Sopenharmony_ci crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)); 3458c2ecf20Sopenharmony_ci crc >>= hash_table_shift; 3468c2ecf20Sopenharmony_ci hash_table[crc >> 5] |= (1 << (crc & 0x1f)); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) { 3508c2ecf20Sopenharmony_ci crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)); 3518c2ecf20Sopenharmony_ci crc >>= hash_table_shift; 3528c2ecf20Sopenharmony_ci hash_table[crc >> 5] |= (1 << (crc & 0x1f)); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* Set the MAC Hash Table registers */ 3568c2ecf20Sopenharmony_ci hash_reg = MAC_HTR0; 3578c2ecf20Sopenharmony_ci for (i = 0; i < hash_table_count; i++) { 3588c2ecf20Sopenharmony_ci writel(hash_table[i], pdata->mac_regs + hash_reg); 3598c2ecf20Sopenharmony_ci hash_reg += MAC_HTR_INC; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int xlgmac_add_mac_addresses(struct xlgmac_pdata *pdata) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci if (pdata->hw_feat.hash_table_size) 3668c2ecf20Sopenharmony_ci xlgmac_set_mac_hash_table(pdata); 3678c2ecf20Sopenharmony_ci else 3688c2ecf20Sopenharmony_ci xlgmac_set_mac_addn_addrs(pdata); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic void xlgmac_config_mac_address(struct xlgmac_pdata *pdata) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci u32 regval; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci xlgmac_set_mac_address(pdata, pdata->netdev->dev_addr); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Filtering is done using perfect filtering and hash filtering */ 3808c2ecf20Sopenharmony_ci if (pdata->hw_feat.hash_table_size) { 3818c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_PFR); 3828c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_PFR_HPF_POS, 3838c2ecf20Sopenharmony_ci MAC_PFR_HPF_LEN, 1); 3848c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_PFR_HUC_POS, 3858c2ecf20Sopenharmony_ci MAC_PFR_HUC_LEN, 1); 3868c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_PFR_HMC_POS, 3878c2ecf20Sopenharmony_ci MAC_PFR_HMC_LEN, 1); 3888c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_PFR); 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic void xlgmac_config_jumbo_enable(struct xlgmac_pdata *pdata) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci unsigned int val; 3958c2ecf20Sopenharmony_ci u32 regval; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci val = (pdata->netdev->mtu > XLGMAC_STD_PACKET_MTU) ? 1 : 0; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_RCR); 4008c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_JE_POS, 4018c2ecf20Sopenharmony_ci MAC_RCR_JE_LEN, val); 4028c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RCR); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic void xlgmac_config_checksum_offload(struct xlgmac_pdata *pdata) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci if (pdata->netdev->features & NETIF_F_RXCSUM) 4088c2ecf20Sopenharmony_ci xlgmac_enable_rx_csum(pdata); 4098c2ecf20Sopenharmony_ci else 4108c2ecf20Sopenharmony_ci xlgmac_disable_rx_csum(pdata); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic void xlgmac_config_vlan_support(struct xlgmac_pdata *pdata) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci u32 regval; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_VLANIR); 4188c2ecf20Sopenharmony_ci /* Indicate that VLAN Tx CTAGs come from context descriptors */ 4198c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANIR_CSVL_POS, 4208c2ecf20Sopenharmony_ci MAC_VLANIR_CSVL_LEN, 0); 4218c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_VLANIR_VLTI_POS, 4228c2ecf20Sopenharmony_ci MAC_VLANIR_VLTI_LEN, 1); 4238c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_VLANIR); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* Set the current VLAN Hash Table register value */ 4268c2ecf20Sopenharmony_ci xlgmac_update_vlan_hash_table(pdata); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER) 4298c2ecf20Sopenharmony_ci xlgmac_enable_rx_vlan_filtering(pdata); 4308c2ecf20Sopenharmony_ci else 4318c2ecf20Sopenharmony_ci xlgmac_disable_rx_vlan_filtering(pdata); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) 4348c2ecf20Sopenharmony_ci xlgmac_enable_rx_vlan_stripping(pdata); 4358c2ecf20Sopenharmony_ci else 4368c2ecf20Sopenharmony_ci xlgmac_disable_rx_vlan_stripping(pdata); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int xlgmac_config_rx_mode(struct xlgmac_pdata *pdata) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct net_device *netdev = pdata->netdev; 4428c2ecf20Sopenharmony_ci unsigned int pr_mode, am_mode; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci pr_mode = ((netdev->flags & IFF_PROMISC) != 0); 4458c2ecf20Sopenharmony_ci am_mode = ((netdev->flags & IFF_ALLMULTI) != 0); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci xlgmac_set_promiscuous_mode(pdata, pr_mode); 4488c2ecf20Sopenharmony_ci xlgmac_set_all_multicast_mode(pdata, am_mode); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci xlgmac_add_mac_addresses(pdata); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic void xlgmac_prepare_tx_stop(struct xlgmac_pdata *pdata, 4568c2ecf20Sopenharmony_ci struct xlgmac_channel *channel) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci unsigned int tx_dsr, tx_pos, tx_qidx; 4598c2ecf20Sopenharmony_ci unsigned long tx_timeout; 4608c2ecf20Sopenharmony_ci unsigned int tx_status; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* Calculate the status register to read and the position within */ 4638c2ecf20Sopenharmony_ci if (channel->queue_index < DMA_DSRX_FIRST_QUEUE) { 4648c2ecf20Sopenharmony_ci tx_dsr = DMA_DSR0; 4658c2ecf20Sopenharmony_ci tx_pos = (channel->queue_index * DMA_DSR_Q_LEN) + 4668c2ecf20Sopenharmony_ci DMA_DSR0_TPS_START; 4678c2ecf20Sopenharmony_ci } else { 4688c2ecf20Sopenharmony_ci tx_qidx = channel->queue_index - DMA_DSRX_FIRST_QUEUE; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci tx_dsr = DMA_DSR1 + ((tx_qidx / DMA_DSRX_QPR) * DMA_DSRX_INC); 4718c2ecf20Sopenharmony_ci tx_pos = ((tx_qidx % DMA_DSRX_QPR) * DMA_DSR_Q_LEN) + 4728c2ecf20Sopenharmony_ci DMA_DSRX_TPS_START; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* The Tx engine cannot be stopped if it is actively processing 4768c2ecf20Sopenharmony_ci * descriptors. Wait for the Tx engine to enter the stopped or 4778c2ecf20Sopenharmony_ci * suspended state. Don't wait forever though... 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci tx_timeout = jiffies + (XLGMAC_DMA_STOP_TIMEOUT * HZ); 4808c2ecf20Sopenharmony_ci while (time_before(jiffies, tx_timeout)) { 4818c2ecf20Sopenharmony_ci tx_status = readl(pdata->mac_regs + tx_dsr); 4828c2ecf20Sopenharmony_ci tx_status = XLGMAC_GET_REG_BITS(tx_status, tx_pos, 4838c2ecf20Sopenharmony_ci DMA_DSR_TPS_LEN); 4848c2ecf20Sopenharmony_ci if ((tx_status == DMA_TPS_STOPPED) || 4858c2ecf20Sopenharmony_ci (tx_status == DMA_TPS_SUSPENDED)) 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci usleep_range(500, 1000); 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (!time_before(jiffies, tx_timeout)) 4928c2ecf20Sopenharmony_ci netdev_info(pdata->netdev, 4938c2ecf20Sopenharmony_ci "timed out waiting for Tx DMA channel %u to stop\n", 4948c2ecf20Sopenharmony_ci channel->queue_index); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic void xlgmac_enable_tx(struct xlgmac_pdata *pdata) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 5008c2ecf20Sopenharmony_ci unsigned int i; 5018c2ecf20Sopenharmony_ci u32 regval; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* Enable each Tx DMA channel */ 5048c2ecf20Sopenharmony_ci channel = pdata->channel_head; 5058c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 5068c2ecf20Sopenharmony_ci if (!channel->tx_ring) 5078c2ecf20Sopenharmony_ci break; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_TCR)); 5108c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_TCR_ST_POS, 5118c2ecf20Sopenharmony_ci DMA_CH_TCR_ST_LEN, 1); 5128c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_TCR)); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* Enable each Tx queue */ 5168c2ecf20Sopenharmony_ci for (i = 0; i < pdata->tx_q_count; i++) { 5178c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 5188c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_TXQEN_POS, 5198c2ecf20Sopenharmony_ci MTL_Q_TQOMR_TXQEN_LEN, 5208c2ecf20Sopenharmony_ci MTL_Q_ENABLED); 5218c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* Enable MAC Tx */ 5258c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_TCR); 5268c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_TCR_TE_POS, 5278c2ecf20Sopenharmony_ci MAC_TCR_TE_LEN, 1); 5288c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_TCR); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic void xlgmac_disable_tx(struct xlgmac_pdata *pdata) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 5348c2ecf20Sopenharmony_ci unsigned int i; 5358c2ecf20Sopenharmony_ci u32 regval; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* Prepare for Tx DMA channel stop */ 5388c2ecf20Sopenharmony_ci channel = pdata->channel_head; 5398c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 5408c2ecf20Sopenharmony_ci if (!channel->tx_ring) 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci xlgmac_prepare_tx_stop(pdata, channel); 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* Disable MAC Tx */ 5478c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_TCR); 5488c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_TCR_TE_POS, 5498c2ecf20Sopenharmony_ci MAC_TCR_TE_LEN, 0); 5508c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_TCR); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* Disable each Tx queue */ 5538c2ecf20Sopenharmony_ci for (i = 0; i < pdata->tx_q_count; i++) { 5548c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 5558c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_TXQEN_POS, 5568c2ecf20Sopenharmony_ci MTL_Q_TQOMR_TXQEN_LEN, 0); 5578c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* Disable each Tx DMA channel */ 5618c2ecf20Sopenharmony_ci channel = pdata->channel_head; 5628c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 5638c2ecf20Sopenharmony_ci if (!channel->tx_ring) 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_TCR)); 5678c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_TCR_ST_POS, 5688c2ecf20Sopenharmony_ci DMA_CH_TCR_ST_LEN, 0); 5698c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_TCR)); 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic void xlgmac_prepare_rx_stop(struct xlgmac_pdata *pdata, 5748c2ecf20Sopenharmony_ci unsigned int queue) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci unsigned int rx_status, prxq, rxqsts; 5778c2ecf20Sopenharmony_ci unsigned long rx_timeout; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* The Rx engine cannot be stopped if it is actively processing 5808c2ecf20Sopenharmony_ci * packets. Wait for the Rx queue to empty the Rx fifo. Don't 5818c2ecf20Sopenharmony_ci * wait forever though... 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ci rx_timeout = jiffies + (XLGMAC_DMA_STOP_TIMEOUT * HZ); 5848c2ecf20Sopenharmony_ci while (time_before(jiffies, rx_timeout)) { 5858c2ecf20Sopenharmony_ci rx_status = readl(XLGMAC_MTL_REG(pdata, queue, MTL_Q_RQDR)); 5868c2ecf20Sopenharmony_ci prxq = XLGMAC_GET_REG_BITS(rx_status, MTL_Q_RQDR_PRXQ_POS, 5878c2ecf20Sopenharmony_ci MTL_Q_RQDR_PRXQ_LEN); 5888c2ecf20Sopenharmony_ci rxqsts = XLGMAC_GET_REG_BITS(rx_status, MTL_Q_RQDR_RXQSTS_POS, 5898c2ecf20Sopenharmony_ci MTL_Q_RQDR_RXQSTS_LEN); 5908c2ecf20Sopenharmony_ci if ((prxq == 0) && (rxqsts == 0)) 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci usleep_range(500, 1000); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (!time_before(jiffies, rx_timeout)) 5978c2ecf20Sopenharmony_ci netdev_info(pdata->netdev, 5988c2ecf20Sopenharmony_ci "timed out waiting for Rx queue %u to empty\n", 5998c2ecf20Sopenharmony_ci queue); 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic void xlgmac_enable_rx(struct xlgmac_pdata *pdata) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 6058c2ecf20Sopenharmony_ci unsigned int regval, i; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* Enable each Rx DMA channel */ 6088c2ecf20Sopenharmony_ci channel = pdata->channel_head; 6098c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 6108c2ecf20Sopenharmony_ci if (!channel->rx_ring) 6118c2ecf20Sopenharmony_ci break; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_RCR)); 6148c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_RCR_SR_POS, 6158c2ecf20Sopenharmony_ci DMA_CH_RCR_SR_LEN, 1); 6168c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_RCR)); 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* Enable each Rx queue */ 6208c2ecf20Sopenharmony_ci regval = 0; 6218c2ecf20Sopenharmony_ci for (i = 0; i < pdata->rx_q_count; i++) 6228c2ecf20Sopenharmony_ci regval |= (0x02 << (i << 1)); 6238c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RQC0R); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* Enable MAC Rx */ 6268c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_RCR); 6278c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_DCRCC_POS, 6288c2ecf20Sopenharmony_ci MAC_RCR_DCRCC_LEN, 1); 6298c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_CST_POS, 6308c2ecf20Sopenharmony_ci MAC_RCR_CST_LEN, 1); 6318c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_ACS_POS, 6328c2ecf20Sopenharmony_ci MAC_RCR_ACS_LEN, 1); 6338c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_RE_POS, 6348c2ecf20Sopenharmony_ci MAC_RCR_RE_LEN, 1); 6358c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RCR); 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic void xlgmac_disable_rx(struct xlgmac_pdata *pdata) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 6418c2ecf20Sopenharmony_ci unsigned int i; 6428c2ecf20Sopenharmony_ci u32 regval; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci /* Disable MAC Rx */ 6458c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_RCR); 6468c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_DCRCC_POS, 6478c2ecf20Sopenharmony_ci MAC_RCR_DCRCC_LEN, 0); 6488c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_CST_POS, 6498c2ecf20Sopenharmony_ci MAC_RCR_CST_LEN, 0); 6508c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_ACS_POS, 6518c2ecf20Sopenharmony_ci MAC_RCR_ACS_LEN, 0); 6528c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_RE_POS, 6538c2ecf20Sopenharmony_ci MAC_RCR_RE_LEN, 0); 6548c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RCR); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* Prepare for Rx DMA channel stop */ 6578c2ecf20Sopenharmony_ci for (i = 0; i < pdata->rx_q_count; i++) 6588c2ecf20Sopenharmony_ci xlgmac_prepare_rx_stop(pdata, i); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* Disable each Rx queue */ 6618c2ecf20Sopenharmony_ci writel(0, pdata->mac_regs + MAC_RQC0R); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* Disable each Rx DMA channel */ 6648c2ecf20Sopenharmony_ci channel = pdata->channel_head; 6658c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 6668c2ecf20Sopenharmony_ci if (!channel->rx_ring) 6678c2ecf20Sopenharmony_ci break; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_RCR)); 6708c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_RCR_SR_POS, 6718c2ecf20Sopenharmony_ci DMA_CH_RCR_SR_LEN, 0); 6728c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_RCR)); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic void xlgmac_tx_start_xmit(struct xlgmac_channel *channel, 6778c2ecf20Sopenharmony_ci struct xlgmac_ring *ring) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci struct xlgmac_pdata *pdata = channel->pdata; 6808c2ecf20Sopenharmony_ci struct xlgmac_desc_data *desc_data; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci /* Make sure everything is written before the register write */ 6838c2ecf20Sopenharmony_ci wmb(); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* Issue a poll command to Tx DMA by writing address 6868c2ecf20Sopenharmony_ci * of next immediate free descriptor 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_ci desc_data = XLGMAC_GET_DESC_DATA(ring, ring->cur); 6898c2ecf20Sopenharmony_ci writel(lower_32_bits(desc_data->dma_desc_addr), 6908c2ecf20Sopenharmony_ci XLGMAC_DMA_REG(channel, DMA_CH_TDTR_LO)); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* Start the Tx timer */ 6938c2ecf20Sopenharmony_ci if (pdata->tx_usecs && !channel->tx_timer_active) { 6948c2ecf20Sopenharmony_ci channel->tx_timer_active = 1; 6958c2ecf20Sopenharmony_ci mod_timer(&channel->tx_timer, 6968c2ecf20Sopenharmony_ci jiffies + usecs_to_jiffies(pdata->tx_usecs)); 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci ring->tx.xmit_more = 0; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic void xlgmac_dev_xmit(struct xlgmac_channel *channel) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct xlgmac_pdata *pdata = channel->pdata; 7058c2ecf20Sopenharmony_ci struct xlgmac_ring *ring = channel->tx_ring; 7068c2ecf20Sopenharmony_ci unsigned int tso_context, vlan_context; 7078c2ecf20Sopenharmony_ci struct xlgmac_desc_data *desc_data; 7088c2ecf20Sopenharmony_ci struct xlgmac_dma_desc *dma_desc; 7098c2ecf20Sopenharmony_ci struct xlgmac_pkt_info *pkt_info; 7108c2ecf20Sopenharmony_ci unsigned int csum, tso, vlan; 7118c2ecf20Sopenharmony_ci int start_index = ring->cur; 7128c2ecf20Sopenharmony_ci int cur_index = ring->cur; 7138c2ecf20Sopenharmony_ci unsigned int tx_set_ic; 7148c2ecf20Sopenharmony_ci int i; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci pkt_info = &ring->pkt_info; 7178c2ecf20Sopenharmony_ci csum = XLGMAC_GET_REG_BITS(pkt_info->attributes, 7188c2ecf20Sopenharmony_ci TX_PACKET_ATTRIBUTES_CSUM_ENABLE_POS, 7198c2ecf20Sopenharmony_ci TX_PACKET_ATTRIBUTES_CSUM_ENABLE_LEN); 7208c2ecf20Sopenharmony_ci tso = XLGMAC_GET_REG_BITS(pkt_info->attributes, 7218c2ecf20Sopenharmony_ci TX_PACKET_ATTRIBUTES_TSO_ENABLE_POS, 7228c2ecf20Sopenharmony_ci TX_PACKET_ATTRIBUTES_TSO_ENABLE_LEN); 7238c2ecf20Sopenharmony_ci vlan = XLGMAC_GET_REG_BITS(pkt_info->attributes, 7248c2ecf20Sopenharmony_ci TX_PACKET_ATTRIBUTES_VLAN_CTAG_POS, 7258c2ecf20Sopenharmony_ci TX_PACKET_ATTRIBUTES_VLAN_CTAG_LEN); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (tso && (pkt_info->mss != ring->tx.cur_mss)) 7288c2ecf20Sopenharmony_ci tso_context = 1; 7298c2ecf20Sopenharmony_ci else 7308c2ecf20Sopenharmony_ci tso_context = 0; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (vlan && (pkt_info->vlan_ctag != ring->tx.cur_vlan_ctag)) 7338c2ecf20Sopenharmony_ci vlan_context = 1; 7348c2ecf20Sopenharmony_ci else 7358c2ecf20Sopenharmony_ci vlan_context = 0; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Determine if an interrupt should be generated for this Tx: 7388c2ecf20Sopenharmony_ci * Interrupt: 7398c2ecf20Sopenharmony_ci * - Tx frame count exceeds the frame count setting 7408c2ecf20Sopenharmony_ci * - Addition of Tx frame count to the frame count since the 7418c2ecf20Sopenharmony_ci * last interrupt was set exceeds the frame count setting 7428c2ecf20Sopenharmony_ci * No interrupt: 7438c2ecf20Sopenharmony_ci * - No frame count setting specified (ethtool -C ethX tx-frames 0) 7448c2ecf20Sopenharmony_ci * - Addition of Tx frame count to the frame count since the 7458c2ecf20Sopenharmony_ci * last interrupt was set does not exceed the frame count setting 7468c2ecf20Sopenharmony_ci */ 7478c2ecf20Sopenharmony_ci ring->coalesce_count += pkt_info->tx_packets; 7488c2ecf20Sopenharmony_ci if (!pdata->tx_frames) 7498c2ecf20Sopenharmony_ci tx_set_ic = 0; 7508c2ecf20Sopenharmony_ci else if (pkt_info->tx_packets > pdata->tx_frames) 7518c2ecf20Sopenharmony_ci tx_set_ic = 1; 7528c2ecf20Sopenharmony_ci else if ((ring->coalesce_count % pdata->tx_frames) < 7538c2ecf20Sopenharmony_ci pkt_info->tx_packets) 7548c2ecf20Sopenharmony_ci tx_set_ic = 1; 7558c2ecf20Sopenharmony_ci else 7568c2ecf20Sopenharmony_ci tx_set_ic = 0; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci desc_data = XLGMAC_GET_DESC_DATA(ring, cur_index); 7598c2ecf20Sopenharmony_ci dma_desc = desc_data->dma_desc; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci /* Create a context descriptor if this is a TSO pkt_info */ 7628c2ecf20Sopenharmony_ci if (tso_context || vlan_context) { 7638c2ecf20Sopenharmony_ci if (tso_context) { 7648c2ecf20Sopenharmony_ci netif_dbg(pdata, tx_queued, pdata->netdev, 7658c2ecf20Sopenharmony_ci "TSO context descriptor, mss=%u\n", 7668c2ecf20Sopenharmony_ci pkt_info->mss); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* Set the MSS size */ 7698c2ecf20Sopenharmony_ci dma_desc->desc2 = XLGMAC_SET_REG_BITS_LE( 7708c2ecf20Sopenharmony_ci dma_desc->desc2, 7718c2ecf20Sopenharmony_ci TX_CONTEXT_DESC2_MSS_POS, 7728c2ecf20Sopenharmony_ci TX_CONTEXT_DESC2_MSS_LEN, 7738c2ecf20Sopenharmony_ci pkt_info->mss); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci /* Mark it as a CONTEXT descriptor */ 7768c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 7778c2ecf20Sopenharmony_ci dma_desc->desc3, 7788c2ecf20Sopenharmony_ci TX_CONTEXT_DESC3_CTXT_POS, 7798c2ecf20Sopenharmony_ci TX_CONTEXT_DESC3_CTXT_LEN, 7808c2ecf20Sopenharmony_ci 1); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci /* Indicate this descriptor contains the MSS */ 7838c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 7848c2ecf20Sopenharmony_ci dma_desc->desc3, 7858c2ecf20Sopenharmony_ci TX_CONTEXT_DESC3_TCMSSV_POS, 7868c2ecf20Sopenharmony_ci TX_CONTEXT_DESC3_TCMSSV_LEN, 7878c2ecf20Sopenharmony_ci 1); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci ring->tx.cur_mss = pkt_info->mss; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (vlan_context) { 7938c2ecf20Sopenharmony_ci netif_dbg(pdata, tx_queued, pdata->netdev, 7948c2ecf20Sopenharmony_ci "VLAN context descriptor, ctag=%u\n", 7958c2ecf20Sopenharmony_ci pkt_info->vlan_ctag); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci /* Mark it as a CONTEXT descriptor */ 7988c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 7998c2ecf20Sopenharmony_ci dma_desc->desc3, 8008c2ecf20Sopenharmony_ci TX_CONTEXT_DESC3_CTXT_POS, 8018c2ecf20Sopenharmony_ci TX_CONTEXT_DESC3_CTXT_LEN, 8028c2ecf20Sopenharmony_ci 1); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* Set the VLAN tag */ 8058c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 8068c2ecf20Sopenharmony_ci dma_desc->desc3, 8078c2ecf20Sopenharmony_ci TX_CONTEXT_DESC3_VT_POS, 8088c2ecf20Sopenharmony_ci TX_CONTEXT_DESC3_VT_LEN, 8098c2ecf20Sopenharmony_ci pkt_info->vlan_ctag); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* Indicate this descriptor contains the VLAN tag */ 8128c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 8138c2ecf20Sopenharmony_ci dma_desc->desc3, 8148c2ecf20Sopenharmony_ci TX_CONTEXT_DESC3_VLTV_POS, 8158c2ecf20Sopenharmony_ci TX_CONTEXT_DESC3_VLTV_LEN, 8168c2ecf20Sopenharmony_ci 1); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci ring->tx.cur_vlan_ctag = pkt_info->vlan_ctag; 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci cur_index++; 8228c2ecf20Sopenharmony_ci desc_data = XLGMAC_GET_DESC_DATA(ring, cur_index); 8238c2ecf20Sopenharmony_ci dma_desc = desc_data->dma_desc; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci /* Update buffer address (for TSO this is the header) */ 8278c2ecf20Sopenharmony_ci dma_desc->desc0 = cpu_to_le32(lower_32_bits(desc_data->skb_dma)); 8288c2ecf20Sopenharmony_ci dma_desc->desc1 = cpu_to_le32(upper_32_bits(desc_data->skb_dma)); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* Update the buffer length */ 8318c2ecf20Sopenharmony_ci dma_desc->desc2 = XLGMAC_SET_REG_BITS_LE( 8328c2ecf20Sopenharmony_ci dma_desc->desc2, 8338c2ecf20Sopenharmony_ci TX_NORMAL_DESC2_HL_B1L_POS, 8348c2ecf20Sopenharmony_ci TX_NORMAL_DESC2_HL_B1L_LEN, 8358c2ecf20Sopenharmony_ci desc_data->skb_dma_len); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* VLAN tag insertion check */ 8388c2ecf20Sopenharmony_ci if (vlan) { 8398c2ecf20Sopenharmony_ci dma_desc->desc2 = XLGMAC_SET_REG_BITS_LE( 8408c2ecf20Sopenharmony_ci dma_desc->desc2, 8418c2ecf20Sopenharmony_ci TX_NORMAL_DESC2_VTIR_POS, 8428c2ecf20Sopenharmony_ci TX_NORMAL_DESC2_VTIR_LEN, 8438c2ecf20Sopenharmony_ci TX_NORMAL_DESC2_VLAN_INSERT); 8448c2ecf20Sopenharmony_ci pdata->stats.tx_vlan_packets++; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* Timestamp enablement check */ 8488c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(pkt_info->attributes, 8498c2ecf20Sopenharmony_ci TX_PACKET_ATTRIBUTES_PTP_POS, 8508c2ecf20Sopenharmony_ci TX_PACKET_ATTRIBUTES_PTP_LEN)) 8518c2ecf20Sopenharmony_ci dma_desc->desc2 = XLGMAC_SET_REG_BITS_LE( 8528c2ecf20Sopenharmony_ci dma_desc->desc2, 8538c2ecf20Sopenharmony_ci TX_NORMAL_DESC2_TTSE_POS, 8548c2ecf20Sopenharmony_ci TX_NORMAL_DESC2_TTSE_LEN, 8558c2ecf20Sopenharmony_ci 1); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* Mark it as First Descriptor */ 8588c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 8598c2ecf20Sopenharmony_ci dma_desc->desc3, 8608c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_FD_POS, 8618c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_FD_LEN, 8628c2ecf20Sopenharmony_ci 1); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci /* Mark it as a NORMAL descriptor */ 8658c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 8668c2ecf20Sopenharmony_ci dma_desc->desc3, 8678c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CTXT_POS, 8688c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CTXT_LEN, 8698c2ecf20Sopenharmony_ci 0); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* Set OWN bit if not the first descriptor */ 8728c2ecf20Sopenharmony_ci if (cur_index != start_index) 8738c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 8748c2ecf20Sopenharmony_ci dma_desc->desc3, 8758c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_OWN_POS, 8768c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_OWN_LEN, 8778c2ecf20Sopenharmony_ci 1); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (tso) { 8808c2ecf20Sopenharmony_ci /* Enable TSO */ 8818c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 8828c2ecf20Sopenharmony_ci dma_desc->desc3, 8838c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_TSE_POS, 8848c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_TSE_LEN, 1); 8858c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 8868c2ecf20Sopenharmony_ci dma_desc->desc3, 8878c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_TCPPL_POS, 8888c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_TCPPL_LEN, 8898c2ecf20Sopenharmony_ci pkt_info->tcp_payload_len); 8908c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 8918c2ecf20Sopenharmony_ci dma_desc->desc3, 8928c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_TCPHDRLEN_POS, 8938c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_TCPHDRLEN_LEN, 8948c2ecf20Sopenharmony_ci pkt_info->tcp_header_len / 4); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci pdata->stats.tx_tso_packets++; 8978c2ecf20Sopenharmony_ci } else { 8988c2ecf20Sopenharmony_ci /* Enable CRC and Pad Insertion */ 8998c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 9008c2ecf20Sopenharmony_ci dma_desc->desc3, 9018c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CPC_POS, 9028c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CPC_LEN, 0); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci /* Enable HW CSUM */ 9058c2ecf20Sopenharmony_ci if (csum) 9068c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 9078c2ecf20Sopenharmony_ci dma_desc->desc3, 9088c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CIC_POS, 9098c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CIC_LEN, 9108c2ecf20Sopenharmony_ci 0x3); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* Set the total length to be transmitted */ 9138c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 9148c2ecf20Sopenharmony_ci dma_desc->desc3, 9158c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_FL_POS, 9168c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_FL_LEN, 9178c2ecf20Sopenharmony_ci pkt_info->length); 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci for (i = cur_index - start_index + 1; i < pkt_info->desc_count; i++) { 9218c2ecf20Sopenharmony_ci cur_index++; 9228c2ecf20Sopenharmony_ci desc_data = XLGMAC_GET_DESC_DATA(ring, cur_index); 9238c2ecf20Sopenharmony_ci dma_desc = desc_data->dma_desc; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* Update buffer address */ 9268c2ecf20Sopenharmony_ci dma_desc->desc0 = 9278c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(desc_data->skb_dma)); 9288c2ecf20Sopenharmony_ci dma_desc->desc1 = 9298c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(desc_data->skb_dma)); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* Update the buffer length */ 9328c2ecf20Sopenharmony_ci dma_desc->desc2 = XLGMAC_SET_REG_BITS_LE( 9338c2ecf20Sopenharmony_ci dma_desc->desc2, 9348c2ecf20Sopenharmony_ci TX_NORMAL_DESC2_HL_B1L_POS, 9358c2ecf20Sopenharmony_ci TX_NORMAL_DESC2_HL_B1L_LEN, 9368c2ecf20Sopenharmony_ci desc_data->skb_dma_len); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci /* Set OWN bit */ 9398c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 9408c2ecf20Sopenharmony_ci dma_desc->desc3, 9418c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_OWN_POS, 9428c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_OWN_LEN, 1); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* Mark it as NORMAL descriptor */ 9458c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 9468c2ecf20Sopenharmony_ci dma_desc->desc3, 9478c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CTXT_POS, 9488c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CTXT_LEN, 0); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci /* Enable HW CSUM */ 9518c2ecf20Sopenharmony_ci if (csum) 9528c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 9538c2ecf20Sopenharmony_ci dma_desc->desc3, 9548c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CIC_POS, 9558c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CIC_LEN, 9568c2ecf20Sopenharmony_ci 0x3); 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci /* Set LAST bit for the last descriptor */ 9608c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 9618c2ecf20Sopenharmony_ci dma_desc->desc3, 9628c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_LD_POS, 9638c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_LD_LEN, 1); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci /* Set IC bit based on Tx coalescing settings */ 9668c2ecf20Sopenharmony_ci if (tx_set_ic) 9678c2ecf20Sopenharmony_ci dma_desc->desc2 = XLGMAC_SET_REG_BITS_LE( 9688c2ecf20Sopenharmony_ci dma_desc->desc2, 9698c2ecf20Sopenharmony_ci TX_NORMAL_DESC2_IC_POS, 9708c2ecf20Sopenharmony_ci TX_NORMAL_DESC2_IC_LEN, 1); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* Save the Tx info to report back during cleanup */ 9738c2ecf20Sopenharmony_ci desc_data->tx.packets = pkt_info->tx_packets; 9748c2ecf20Sopenharmony_ci desc_data->tx.bytes = pkt_info->tx_bytes; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci /* In case the Tx DMA engine is running, make sure everything 9778c2ecf20Sopenharmony_ci * is written to the descriptor(s) before setting the OWN bit 9788c2ecf20Sopenharmony_ci * for the first descriptor 9798c2ecf20Sopenharmony_ci */ 9808c2ecf20Sopenharmony_ci dma_wmb(); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* Set OWN bit for the first descriptor */ 9838c2ecf20Sopenharmony_ci desc_data = XLGMAC_GET_DESC_DATA(ring, start_index); 9848c2ecf20Sopenharmony_ci dma_desc = desc_data->dma_desc; 9858c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 9868c2ecf20Sopenharmony_ci dma_desc->desc3, 9878c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_OWN_POS, 9888c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_OWN_LEN, 1); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (netif_msg_tx_queued(pdata)) 9918c2ecf20Sopenharmony_ci xlgmac_dump_tx_desc(pdata, ring, start_index, 9928c2ecf20Sopenharmony_ci pkt_info->desc_count, 1); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci /* Make sure ownership is written to the descriptor */ 9958c2ecf20Sopenharmony_ci smp_wmb(); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci ring->cur = cur_index + 1; 9988c2ecf20Sopenharmony_ci if (!netdev_xmit_more() || 9998c2ecf20Sopenharmony_ci netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev, 10008c2ecf20Sopenharmony_ci channel->queue_index))) 10018c2ecf20Sopenharmony_ci xlgmac_tx_start_xmit(channel, ring); 10028c2ecf20Sopenharmony_ci else 10038c2ecf20Sopenharmony_ci ring->tx.xmit_more = 1; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci XLGMAC_PR("%s: descriptors %u to %u written\n", 10068c2ecf20Sopenharmony_ci channel->name, start_index & (ring->dma_desc_count - 1), 10078c2ecf20Sopenharmony_ci (ring->cur - 1) & (ring->dma_desc_count - 1)); 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_cistatic void xlgmac_get_rx_tstamp(struct xlgmac_pkt_info *pkt_info, 10118c2ecf20Sopenharmony_ci struct xlgmac_dma_desc *dma_desc) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci u32 tsa, tsd; 10148c2ecf20Sopenharmony_ci u64 nsec; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci tsa = XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 10178c2ecf20Sopenharmony_ci RX_CONTEXT_DESC3_TSA_POS, 10188c2ecf20Sopenharmony_ci RX_CONTEXT_DESC3_TSA_LEN); 10198c2ecf20Sopenharmony_ci tsd = XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 10208c2ecf20Sopenharmony_ci RX_CONTEXT_DESC3_TSD_POS, 10218c2ecf20Sopenharmony_ci RX_CONTEXT_DESC3_TSD_LEN); 10228c2ecf20Sopenharmony_ci if (tsa && !tsd) { 10238c2ecf20Sopenharmony_ci nsec = le32_to_cpu(dma_desc->desc1); 10248c2ecf20Sopenharmony_ci nsec <<= 32; 10258c2ecf20Sopenharmony_ci nsec |= le32_to_cpu(dma_desc->desc0); 10268c2ecf20Sopenharmony_ci if (nsec != 0xffffffffffffffffULL) { 10278c2ecf20Sopenharmony_ci pkt_info->rx_tstamp = nsec; 10288c2ecf20Sopenharmony_ci pkt_info->attributes = XLGMAC_SET_REG_BITS( 10298c2ecf20Sopenharmony_ci pkt_info->attributes, 10308c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_RX_TSTAMP_POS, 10318c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_RX_TSTAMP_LEN, 10328c2ecf20Sopenharmony_ci 1); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_cistatic void xlgmac_tx_desc_reset(struct xlgmac_desc_data *desc_data) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci struct xlgmac_dma_desc *dma_desc = desc_data->dma_desc; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* Reset the Tx descriptor 10428c2ecf20Sopenharmony_ci * Set buffer 1 (lo) address to zero 10438c2ecf20Sopenharmony_ci * Set buffer 1 (hi) address to zero 10448c2ecf20Sopenharmony_ci * Reset all other control bits (IC, TTSE, B2L & B1L) 10458c2ecf20Sopenharmony_ci * Reset all other control bits (OWN, CTXT, FD, LD, CPC, CIC, etc) 10468c2ecf20Sopenharmony_ci */ 10478c2ecf20Sopenharmony_ci dma_desc->desc0 = 0; 10488c2ecf20Sopenharmony_ci dma_desc->desc1 = 0; 10498c2ecf20Sopenharmony_ci dma_desc->desc2 = 0; 10508c2ecf20Sopenharmony_ci dma_desc->desc3 = 0; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* Make sure ownership is written to the descriptor */ 10538c2ecf20Sopenharmony_ci dma_wmb(); 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_cistatic void xlgmac_tx_desc_init(struct xlgmac_channel *channel) 10578c2ecf20Sopenharmony_ci{ 10588c2ecf20Sopenharmony_ci struct xlgmac_ring *ring = channel->tx_ring; 10598c2ecf20Sopenharmony_ci struct xlgmac_desc_data *desc_data; 10608c2ecf20Sopenharmony_ci int start_index = ring->cur; 10618c2ecf20Sopenharmony_ci int i; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* Initialze all descriptors */ 10648c2ecf20Sopenharmony_ci for (i = 0; i < ring->dma_desc_count; i++) { 10658c2ecf20Sopenharmony_ci desc_data = XLGMAC_GET_DESC_DATA(ring, i); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci /* Initialize Tx descriptor */ 10688c2ecf20Sopenharmony_ci xlgmac_tx_desc_reset(desc_data); 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci /* Update the total number of Tx descriptors */ 10728c2ecf20Sopenharmony_ci writel(ring->dma_desc_count - 1, XLGMAC_DMA_REG(channel, DMA_CH_TDRLR)); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* Update the starting address of descriptor ring */ 10758c2ecf20Sopenharmony_ci desc_data = XLGMAC_GET_DESC_DATA(ring, start_index); 10768c2ecf20Sopenharmony_ci writel(upper_32_bits(desc_data->dma_desc_addr), 10778c2ecf20Sopenharmony_ci XLGMAC_DMA_REG(channel, DMA_CH_TDLR_HI)); 10788c2ecf20Sopenharmony_ci writel(lower_32_bits(desc_data->dma_desc_addr), 10798c2ecf20Sopenharmony_ci XLGMAC_DMA_REG(channel, DMA_CH_TDLR_LO)); 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic void xlgmac_rx_desc_reset(struct xlgmac_pdata *pdata, 10838c2ecf20Sopenharmony_ci struct xlgmac_desc_data *desc_data, 10848c2ecf20Sopenharmony_ci unsigned int index) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci struct xlgmac_dma_desc *dma_desc = desc_data->dma_desc; 10878c2ecf20Sopenharmony_ci unsigned int rx_frames = pdata->rx_frames; 10888c2ecf20Sopenharmony_ci unsigned int rx_usecs = pdata->rx_usecs; 10898c2ecf20Sopenharmony_ci dma_addr_t hdr_dma, buf_dma; 10908c2ecf20Sopenharmony_ci unsigned int inte; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (!rx_usecs && !rx_frames) { 10938c2ecf20Sopenharmony_ci /* No coalescing, interrupt for every descriptor */ 10948c2ecf20Sopenharmony_ci inte = 1; 10958c2ecf20Sopenharmony_ci } else { 10968c2ecf20Sopenharmony_ci /* Set interrupt based on Rx frame coalescing setting */ 10978c2ecf20Sopenharmony_ci if (rx_frames && !((index + 1) % rx_frames)) 10988c2ecf20Sopenharmony_ci inte = 1; 10998c2ecf20Sopenharmony_ci else 11008c2ecf20Sopenharmony_ci inte = 0; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci /* Reset the Rx descriptor 11048c2ecf20Sopenharmony_ci * Set buffer 1 (lo) address to header dma address (lo) 11058c2ecf20Sopenharmony_ci * Set buffer 1 (hi) address to header dma address (hi) 11068c2ecf20Sopenharmony_ci * Set buffer 2 (lo) address to buffer dma address (lo) 11078c2ecf20Sopenharmony_ci * Set buffer 2 (hi) address to buffer dma address (hi) and 11088c2ecf20Sopenharmony_ci * set control bits OWN and INTE 11098c2ecf20Sopenharmony_ci */ 11108c2ecf20Sopenharmony_ci hdr_dma = desc_data->rx.hdr.dma_base + desc_data->rx.hdr.dma_off; 11118c2ecf20Sopenharmony_ci buf_dma = desc_data->rx.buf.dma_base + desc_data->rx.buf.dma_off; 11128c2ecf20Sopenharmony_ci dma_desc->desc0 = cpu_to_le32(lower_32_bits(hdr_dma)); 11138c2ecf20Sopenharmony_ci dma_desc->desc1 = cpu_to_le32(upper_32_bits(hdr_dma)); 11148c2ecf20Sopenharmony_ci dma_desc->desc2 = cpu_to_le32(lower_32_bits(buf_dma)); 11158c2ecf20Sopenharmony_ci dma_desc->desc3 = cpu_to_le32(upper_32_bits(buf_dma)); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 11188c2ecf20Sopenharmony_ci dma_desc->desc3, 11198c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_INTE_POS, 11208c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_INTE_LEN, 11218c2ecf20Sopenharmony_ci inte); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* Since the Rx DMA engine is likely running, make sure everything 11248c2ecf20Sopenharmony_ci * is written to the descriptor(s) before setting the OWN bit 11258c2ecf20Sopenharmony_ci * for the descriptor 11268c2ecf20Sopenharmony_ci */ 11278c2ecf20Sopenharmony_ci dma_wmb(); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci dma_desc->desc3 = XLGMAC_SET_REG_BITS_LE( 11308c2ecf20Sopenharmony_ci dma_desc->desc3, 11318c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_OWN_POS, 11328c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_OWN_LEN, 11338c2ecf20Sopenharmony_ci 1); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci /* Make sure ownership is written to the descriptor */ 11368c2ecf20Sopenharmony_ci dma_wmb(); 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_cistatic void xlgmac_rx_desc_init(struct xlgmac_channel *channel) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci struct xlgmac_pdata *pdata = channel->pdata; 11428c2ecf20Sopenharmony_ci struct xlgmac_ring *ring = channel->rx_ring; 11438c2ecf20Sopenharmony_ci unsigned int start_index = ring->cur; 11448c2ecf20Sopenharmony_ci struct xlgmac_desc_data *desc_data; 11458c2ecf20Sopenharmony_ci unsigned int i; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci /* Initialize all descriptors */ 11488c2ecf20Sopenharmony_ci for (i = 0; i < ring->dma_desc_count; i++) { 11498c2ecf20Sopenharmony_ci desc_data = XLGMAC_GET_DESC_DATA(ring, i); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci /* Initialize Rx descriptor */ 11528c2ecf20Sopenharmony_ci xlgmac_rx_desc_reset(pdata, desc_data, i); 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* Update the total number of Rx descriptors */ 11568c2ecf20Sopenharmony_ci writel(ring->dma_desc_count - 1, XLGMAC_DMA_REG(channel, DMA_CH_RDRLR)); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci /* Update the starting address of descriptor ring */ 11598c2ecf20Sopenharmony_ci desc_data = XLGMAC_GET_DESC_DATA(ring, start_index); 11608c2ecf20Sopenharmony_ci writel(upper_32_bits(desc_data->dma_desc_addr), 11618c2ecf20Sopenharmony_ci XLGMAC_DMA_REG(channel, DMA_CH_RDLR_HI)); 11628c2ecf20Sopenharmony_ci writel(lower_32_bits(desc_data->dma_desc_addr), 11638c2ecf20Sopenharmony_ci XLGMAC_DMA_REG(channel, DMA_CH_RDLR_LO)); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* Update the Rx Descriptor Tail Pointer */ 11668c2ecf20Sopenharmony_ci desc_data = XLGMAC_GET_DESC_DATA(ring, start_index + 11678c2ecf20Sopenharmony_ci ring->dma_desc_count - 1); 11688c2ecf20Sopenharmony_ci writel(lower_32_bits(desc_data->dma_desc_addr), 11698c2ecf20Sopenharmony_ci XLGMAC_DMA_REG(channel, DMA_CH_RDTR_LO)); 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic int xlgmac_is_context_desc(struct xlgmac_dma_desc *dma_desc) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci /* Rx and Tx share CTXT bit, so check TDES3.CTXT bit */ 11758c2ecf20Sopenharmony_ci return XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 11768c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CTXT_POS, 11778c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_CTXT_LEN); 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_cistatic int xlgmac_is_last_desc(struct xlgmac_dma_desc *dma_desc) 11818c2ecf20Sopenharmony_ci{ 11828c2ecf20Sopenharmony_ci /* Rx and Tx share LD bit, so check TDES3.LD bit */ 11838c2ecf20Sopenharmony_ci return XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 11848c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_LD_POS, 11858c2ecf20Sopenharmony_ci TX_NORMAL_DESC3_LD_LEN); 11868c2ecf20Sopenharmony_ci} 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cistatic int xlgmac_disable_tx_flow_control(struct xlgmac_pdata *pdata) 11898c2ecf20Sopenharmony_ci{ 11908c2ecf20Sopenharmony_ci unsigned int max_q_count, q_count; 11918c2ecf20Sopenharmony_ci unsigned int reg, regval; 11928c2ecf20Sopenharmony_ci unsigned int i; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /* Clear MTL flow control */ 11958c2ecf20Sopenharmony_ci for (i = 0; i < pdata->rx_q_count; i++) { 11968c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 11978c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_EHFC_POS, 11988c2ecf20Sopenharmony_ci MTL_Q_RQOMR_EHFC_LEN, 0); 11998c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci /* Clear MAC flow control */ 12038c2ecf20Sopenharmony_ci max_q_count = XLGMAC_MAX_FLOW_CONTROL_QUEUES; 12048c2ecf20Sopenharmony_ci q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count); 12058c2ecf20Sopenharmony_ci reg = MAC_Q0TFCR; 12068c2ecf20Sopenharmony_ci for (i = 0; i < q_count; i++) { 12078c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + reg); 12088c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, 12098c2ecf20Sopenharmony_ci MAC_Q0TFCR_TFE_POS, 12108c2ecf20Sopenharmony_ci MAC_Q0TFCR_TFE_LEN, 12118c2ecf20Sopenharmony_ci 0); 12128c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + reg); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci reg += MAC_QTFCR_INC; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci return 0; 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_cistatic int xlgmac_enable_tx_flow_control(struct xlgmac_pdata *pdata) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci unsigned int max_q_count, q_count; 12238c2ecf20Sopenharmony_ci unsigned int reg, regval; 12248c2ecf20Sopenharmony_ci unsigned int i; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* Set MTL flow control */ 12278c2ecf20Sopenharmony_ci for (i = 0; i < pdata->rx_q_count; i++) { 12288c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 12298c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_EHFC_POS, 12308c2ecf20Sopenharmony_ci MTL_Q_RQOMR_EHFC_LEN, 1); 12318c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci /* Set MAC flow control */ 12358c2ecf20Sopenharmony_ci max_q_count = XLGMAC_MAX_FLOW_CONTROL_QUEUES; 12368c2ecf20Sopenharmony_ci q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count); 12378c2ecf20Sopenharmony_ci reg = MAC_Q0TFCR; 12388c2ecf20Sopenharmony_ci for (i = 0; i < q_count; i++) { 12398c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + reg); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci /* Enable transmit flow control */ 12428c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_Q0TFCR_TFE_POS, 12438c2ecf20Sopenharmony_ci MAC_Q0TFCR_TFE_LEN, 1); 12448c2ecf20Sopenharmony_ci /* Set pause time */ 12458c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_Q0TFCR_PT_POS, 12468c2ecf20Sopenharmony_ci MAC_Q0TFCR_PT_LEN, 0xffff); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + reg); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci reg += MAC_QTFCR_INC; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci return 0; 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic int xlgmac_disable_rx_flow_control(struct xlgmac_pdata *pdata) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci u32 regval; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_RFCR); 12618c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RFCR_RFE_POS, 12628c2ecf20Sopenharmony_ci MAC_RFCR_RFE_LEN, 0); 12638c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RFCR); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci return 0; 12668c2ecf20Sopenharmony_ci} 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_cistatic int xlgmac_enable_rx_flow_control(struct xlgmac_pdata *pdata) 12698c2ecf20Sopenharmony_ci{ 12708c2ecf20Sopenharmony_ci u32 regval; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_RFCR); 12738c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RFCR_RFE_POS, 12748c2ecf20Sopenharmony_ci MAC_RFCR_RFE_LEN, 1); 12758c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RFCR); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci return 0; 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic int xlgmac_config_tx_flow_control(struct xlgmac_pdata *pdata) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci if (pdata->tx_pause) 12838c2ecf20Sopenharmony_ci xlgmac_enable_tx_flow_control(pdata); 12848c2ecf20Sopenharmony_ci else 12858c2ecf20Sopenharmony_ci xlgmac_disable_tx_flow_control(pdata); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci return 0; 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_cistatic int xlgmac_config_rx_flow_control(struct xlgmac_pdata *pdata) 12918c2ecf20Sopenharmony_ci{ 12928c2ecf20Sopenharmony_ci if (pdata->rx_pause) 12938c2ecf20Sopenharmony_ci xlgmac_enable_rx_flow_control(pdata); 12948c2ecf20Sopenharmony_ci else 12958c2ecf20Sopenharmony_ci xlgmac_disable_rx_flow_control(pdata); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci return 0; 12988c2ecf20Sopenharmony_ci} 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_cistatic int xlgmac_config_rx_coalesce(struct xlgmac_pdata *pdata) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 13038c2ecf20Sopenharmony_ci unsigned int i; 13048c2ecf20Sopenharmony_ci u32 regval; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci channel = pdata->channel_head; 13078c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 13088c2ecf20Sopenharmony_ci if (!channel->rx_ring) 13098c2ecf20Sopenharmony_ci break; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_RIWT)); 13128c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_RIWT_RWT_POS, 13138c2ecf20Sopenharmony_ci DMA_CH_RIWT_RWT_LEN, 13148c2ecf20Sopenharmony_ci pdata->rx_riwt); 13158c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_RIWT)); 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci return 0; 13198c2ecf20Sopenharmony_ci} 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cistatic void xlgmac_config_flow_control(struct xlgmac_pdata *pdata) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci xlgmac_config_tx_flow_control(pdata); 13248c2ecf20Sopenharmony_ci xlgmac_config_rx_flow_control(pdata); 13258c2ecf20Sopenharmony_ci} 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_cistatic void xlgmac_config_rx_fep_enable(struct xlgmac_pdata *pdata) 13288c2ecf20Sopenharmony_ci{ 13298c2ecf20Sopenharmony_ci unsigned int i; 13308c2ecf20Sopenharmony_ci u32 regval; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci for (i = 0; i < pdata->rx_q_count; i++) { 13338c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 13348c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_FEP_POS, 13358c2ecf20Sopenharmony_ci MTL_Q_RQOMR_FEP_LEN, 1); 13368c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic void xlgmac_config_rx_fup_enable(struct xlgmac_pdata *pdata) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci unsigned int i; 13438c2ecf20Sopenharmony_ci u32 regval; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci for (i = 0; i < pdata->rx_q_count; i++) { 13468c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 13478c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_FUP_POS, 13488c2ecf20Sopenharmony_ci MTL_Q_RQOMR_FUP_LEN, 1); 13498c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_cistatic int xlgmac_config_tx_coalesce(struct xlgmac_pdata *pdata) 13548c2ecf20Sopenharmony_ci{ 13558c2ecf20Sopenharmony_ci return 0; 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_cistatic void xlgmac_config_rx_buffer_size(struct xlgmac_pdata *pdata) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 13618c2ecf20Sopenharmony_ci unsigned int i; 13628c2ecf20Sopenharmony_ci u32 regval; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci channel = pdata->channel_head; 13658c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 13668c2ecf20Sopenharmony_ci if (!channel->rx_ring) 13678c2ecf20Sopenharmony_ci break; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_RCR)); 13708c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_RCR_RBSZ_POS, 13718c2ecf20Sopenharmony_ci DMA_CH_RCR_RBSZ_LEN, 13728c2ecf20Sopenharmony_ci pdata->rx_buf_size); 13738c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_RCR)); 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic void xlgmac_config_tso_mode(struct xlgmac_pdata *pdata) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 13808c2ecf20Sopenharmony_ci unsigned int i; 13818c2ecf20Sopenharmony_ci u32 regval; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci channel = pdata->channel_head; 13848c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 13858c2ecf20Sopenharmony_ci if (!channel->tx_ring) 13868c2ecf20Sopenharmony_ci break; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (pdata->hw_feat.tso) { 13898c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_TCR)); 13908c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_TCR_TSE_POS, 13918c2ecf20Sopenharmony_ci DMA_CH_TCR_TSE_LEN, 1); 13928c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_TCR)); 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic void xlgmac_config_sph_mode(struct xlgmac_pdata *pdata) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 14008c2ecf20Sopenharmony_ci unsigned int i; 14018c2ecf20Sopenharmony_ci u32 regval; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci channel = pdata->channel_head; 14048c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 14058c2ecf20Sopenharmony_ci if (!channel->rx_ring) 14068c2ecf20Sopenharmony_ci break; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_CR)); 14098c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_CR_SPH_POS, 14108c2ecf20Sopenharmony_ci DMA_CH_CR_SPH_LEN, 1); 14118c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_CR)); 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_RCR); 14158c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RCR_HDSMS_POS, 14168c2ecf20Sopenharmony_ci MAC_RCR_HDSMS_LEN, 14178c2ecf20Sopenharmony_ci XLGMAC_SPH_HDSMS_SIZE); 14188c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RCR); 14198c2ecf20Sopenharmony_ci} 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_cistatic unsigned int xlgmac_usec_to_riwt(struct xlgmac_pdata *pdata, 14228c2ecf20Sopenharmony_ci unsigned int usec) 14238c2ecf20Sopenharmony_ci{ 14248c2ecf20Sopenharmony_ci unsigned long rate; 14258c2ecf20Sopenharmony_ci unsigned int ret; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci rate = pdata->sysclk_rate; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci /* Convert the input usec value to the watchdog timer value. Each 14308c2ecf20Sopenharmony_ci * watchdog timer value is equivalent to 256 clock cycles. 14318c2ecf20Sopenharmony_ci * Calculate the required value as: 14328c2ecf20Sopenharmony_ci * ( usec * ( system_clock_mhz / 10^6 ) / 256 14338c2ecf20Sopenharmony_ci */ 14348c2ecf20Sopenharmony_ci ret = (usec * (rate / 1000000)) / 256; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci return ret; 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic unsigned int xlgmac_riwt_to_usec(struct xlgmac_pdata *pdata, 14408c2ecf20Sopenharmony_ci unsigned int riwt) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci unsigned long rate; 14438c2ecf20Sopenharmony_ci unsigned int ret; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci rate = pdata->sysclk_rate; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci /* Convert the input watchdog timer value to the usec value. Each 14488c2ecf20Sopenharmony_ci * watchdog timer value is equivalent to 256 clock cycles. 14498c2ecf20Sopenharmony_ci * Calculate the required value as: 14508c2ecf20Sopenharmony_ci * ( riwt * 256 ) / ( system_clock_mhz / 10^6 ) 14518c2ecf20Sopenharmony_ci */ 14528c2ecf20Sopenharmony_ci ret = (riwt * 256) / (rate / 1000000); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci return ret; 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_cistatic int xlgmac_config_rx_threshold(struct xlgmac_pdata *pdata, 14588c2ecf20Sopenharmony_ci unsigned int val) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci unsigned int i; 14618c2ecf20Sopenharmony_ci u32 regval; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci for (i = 0; i < pdata->rx_q_count; i++) { 14648c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 14658c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_RTC_POS, 14668c2ecf20Sopenharmony_ci MTL_Q_RQOMR_RTC_LEN, val); 14678c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci return 0; 14718c2ecf20Sopenharmony_ci} 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_cistatic void xlgmac_config_mtl_mode(struct xlgmac_pdata *pdata) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci unsigned int i; 14768c2ecf20Sopenharmony_ci u32 regval; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci /* Set Tx to weighted round robin scheduling algorithm */ 14798c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MTL_OMR); 14808c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_OMR_ETSALG_POS, 14818c2ecf20Sopenharmony_ci MTL_OMR_ETSALG_LEN, MTL_ETSALG_WRR); 14828c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MTL_OMR); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* Set Tx traffic classes to use WRR algorithm with equal weights */ 14858c2ecf20Sopenharmony_ci for (i = 0; i < pdata->hw_feat.tc_cnt; i++) { 14868c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_TC_ETSCR)); 14878c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_TC_ETSCR_TSA_POS, 14888c2ecf20Sopenharmony_ci MTL_TC_ETSCR_TSA_LEN, MTL_TSA_ETS); 14898c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_TC_ETSCR)); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_TC_QWR)); 14928c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_TC_QWR_QW_POS, 14938c2ecf20Sopenharmony_ci MTL_TC_QWR_QW_LEN, 1); 14948c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_TC_QWR)); 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci /* Set Rx to strict priority algorithm */ 14988c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MTL_OMR); 14998c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_OMR_RAA_POS, 15008c2ecf20Sopenharmony_ci MTL_OMR_RAA_LEN, MTL_RAA_SP); 15018c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MTL_OMR); 15028c2ecf20Sopenharmony_ci} 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_cistatic void xlgmac_config_queue_mapping(struct xlgmac_pdata *pdata) 15058c2ecf20Sopenharmony_ci{ 15068c2ecf20Sopenharmony_ci unsigned int ppq, ppq_extra, prio, prio_queues; 15078c2ecf20Sopenharmony_ci unsigned int qptc, qptc_extra, queue; 15088c2ecf20Sopenharmony_ci unsigned int reg, regval; 15098c2ecf20Sopenharmony_ci unsigned int mask; 15108c2ecf20Sopenharmony_ci unsigned int i, j; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci /* Map the MTL Tx Queues to Traffic Classes 15138c2ecf20Sopenharmony_ci * Note: Tx Queues >= Traffic Classes 15148c2ecf20Sopenharmony_ci */ 15158c2ecf20Sopenharmony_ci qptc = pdata->tx_q_count / pdata->hw_feat.tc_cnt; 15168c2ecf20Sopenharmony_ci qptc_extra = pdata->tx_q_count % pdata->hw_feat.tc_cnt; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci for (i = 0, queue = 0; i < pdata->hw_feat.tc_cnt; i++) { 15198c2ecf20Sopenharmony_ci for (j = 0; j < qptc; j++) { 15208c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 15218c2ecf20Sopenharmony_ci "TXq%u mapped to TC%u\n", queue, i); 15228c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, queue, 15238c2ecf20Sopenharmony_ci MTL_Q_TQOMR)); 15248c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, 15258c2ecf20Sopenharmony_ci MTL_Q_TQOMR_Q2TCMAP_POS, 15268c2ecf20Sopenharmony_ci MTL_Q_TQOMR_Q2TCMAP_LEN, 15278c2ecf20Sopenharmony_ci i); 15288c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, queue, 15298c2ecf20Sopenharmony_ci MTL_Q_TQOMR)); 15308c2ecf20Sopenharmony_ci queue++; 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (i < qptc_extra) { 15348c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 15358c2ecf20Sopenharmony_ci "TXq%u mapped to TC%u\n", queue, i); 15368c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, queue, 15378c2ecf20Sopenharmony_ci MTL_Q_TQOMR)); 15388c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, 15398c2ecf20Sopenharmony_ci MTL_Q_TQOMR_Q2TCMAP_POS, 15408c2ecf20Sopenharmony_ci MTL_Q_TQOMR_Q2TCMAP_LEN, 15418c2ecf20Sopenharmony_ci i); 15428c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, queue, 15438c2ecf20Sopenharmony_ci MTL_Q_TQOMR)); 15448c2ecf20Sopenharmony_ci queue++; 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci /* Map the 8 VLAN priority values to available MTL Rx queues */ 15498c2ecf20Sopenharmony_ci prio_queues = min_t(unsigned int, IEEE_8021QAZ_MAX_TCS, 15508c2ecf20Sopenharmony_ci pdata->rx_q_count); 15518c2ecf20Sopenharmony_ci ppq = IEEE_8021QAZ_MAX_TCS / prio_queues; 15528c2ecf20Sopenharmony_ci ppq_extra = IEEE_8021QAZ_MAX_TCS % prio_queues; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci reg = MAC_RQC2R; 15558c2ecf20Sopenharmony_ci regval = 0; 15568c2ecf20Sopenharmony_ci for (i = 0, prio = 0; i < prio_queues;) { 15578c2ecf20Sopenharmony_ci mask = 0; 15588c2ecf20Sopenharmony_ci for (j = 0; j < ppq; j++) { 15598c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 15608c2ecf20Sopenharmony_ci "PRIO%u mapped to RXq%u\n", prio, i); 15618c2ecf20Sopenharmony_ci mask |= (1 << prio); 15628c2ecf20Sopenharmony_ci prio++; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci if (i < ppq_extra) { 15668c2ecf20Sopenharmony_ci netif_dbg(pdata, drv, pdata->netdev, 15678c2ecf20Sopenharmony_ci "PRIO%u mapped to RXq%u\n", prio, i); 15688c2ecf20Sopenharmony_ci mask |= (1 << prio); 15698c2ecf20Sopenharmony_ci prio++; 15708c2ecf20Sopenharmony_ci } 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci regval |= (mask << ((i++ % MAC_RQC2_Q_PER_REG) << 3)); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci if ((i % MAC_RQC2_Q_PER_REG) && (i != prio_queues)) 15758c2ecf20Sopenharmony_ci continue; 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + reg); 15788c2ecf20Sopenharmony_ci reg += MAC_RQC2_INC; 15798c2ecf20Sopenharmony_ci regval = 0; 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci /* Configure one to one, MTL Rx queue to DMA Rx channel mapping 15838c2ecf20Sopenharmony_ci * ie Q0 <--> CH0, Q1 <--> CH1 ... Q11 <--> CH11 15848c2ecf20Sopenharmony_ci */ 15858c2ecf20Sopenharmony_ci reg = MTL_RQDCM0R; 15868c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + reg); 15878c2ecf20Sopenharmony_ci regval |= (MTL_RQDCM0R_Q0MDMACH | MTL_RQDCM0R_Q1MDMACH | 15888c2ecf20Sopenharmony_ci MTL_RQDCM0R_Q2MDMACH | MTL_RQDCM0R_Q3MDMACH); 15898c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + reg); 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci reg += MTL_RQDCM_INC; 15928c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + reg); 15938c2ecf20Sopenharmony_ci regval |= (MTL_RQDCM1R_Q4MDMACH | MTL_RQDCM1R_Q5MDMACH | 15948c2ecf20Sopenharmony_ci MTL_RQDCM1R_Q6MDMACH | MTL_RQDCM1R_Q7MDMACH); 15958c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + reg); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci reg += MTL_RQDCM_INC; 15988c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + reg); 15998c2ecf20Sopenharmony_ci regval |= (MTL_RQDCM2R_Q8MDMACH | MTL_RQDCM2R_Q9MDMACH | 16008c2ecf20Sopenharmony_ci MTL_RQDCM2R_Q10MDMACH | MTL_RQDCM2R_Q11MDMACH); 16018c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + reg); 16028c2ecf20Sopenharmony_ci} 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_cistatic unsigned int xlgmac_calculate_per_queue_fifo( 16058c2ecf20Sopenharmony_ci unsigned int fifo_size, 16068c2ecf20Sopenharmony_ci unsigned int queue_count) 16078c2ecf20Sopenharmony_ci{ 16088c2ecf20Sopenharmony_ci unsigned int q_fifo_size; 16098c2ecf20Sopenharmony_ci unsigned int p_fifo; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci /* Calculate the configured fifo size */ 16128c2ecf20Sopenharmony_ci q_fifo_size = 1 << (fifo_size + 7); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* The configured value may not be the actual amount of fifo RAM */ 16158c2ecf20Sopenharmony_ci q_fifo_size = min_t(unsigned int, XLGMAC_MAX_FIFO, q_fifo_size); 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci q_fifo_size = q_fifo_size / queue_count; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci /* Each increment in the queue fifo size represents 256 bytes of 16208c2ecf20Sopenharmony_ci * fifo, with 0 representing 256 bytes. Distribute the fifo equally 16218c2ecf20Sopenharmony_ci * between the queues. 16228c2ecf20Sopenharmony_ci */ 16238c2ecf20Sopenharmony_ci p_fifo = q_fifo_size / 256; 16248c2ecf20Sopenharmony_ci if (p_fifo) 16258c2ecf20Sopenharmony_ci p_fifo--; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci return p_fifo; 16288c2ecf20Sopenharmony_ci} 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_cistatic void xlgmac_config_tx_fifo_size(struct xlgmac_pdata *pdata) 16318c2ecf20Sopenharmony_ci{ 16328c2ecf20Sopenharmony_ci unsigned int fifo_size; 16338c2ecf20Sopenharmony_ci unsigned int i; 16348c2ecf20Sopenharmony_ci u32 regval; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci fifo_size = xlgmac_calculate_per_queue_fifo( 16378c2ecf20Sopenharmony_ci pdata->hw_feat.tx_fifo_size, 16388c2ecf20Sopenharmony_ci pdata->tx_q_count); 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci for (i = 0; i < pdata->tx_q_count; i++) { 16418c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 16428c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_TQS_POS, 16438c2ecf20Sopenharmony_ci MTL_Q_TQOMR_TQS_LEN, fifo_size); 16448c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 16458c2ecf20Sopenharmony_ci } 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci netif_info(pdata, drv, pdata->netdev, 16488c2ecf20Sopenharmony_ci "%d Tx hardware queues, %d byte fifo per queue\n", 16498c2ecf20Sopenharmony_ci pdata->tx_q_count, ((fifo_size + 1) * 256)); 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_cistatic void xlgmac_config_rx_fifo_size(struct xlgmac_pdata *pdata) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci unsigned int fifo_size; 16558c2ecf20Sopenharmony_ci unsigned int i; 16568c2ecf20Sopenharmony_ci u32 regval; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci fifo_size = xlgmac_calculate_per_queue_fifo( 16598c2ecf20Sopenharmony_ci pdata->hw_feat.rx_fifo_size, 16608c2ecf20Sopenharmony_ci pdata->rx_q_count); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci for (i = 0; i < pdata->rx_q_count; i++) { 16638c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 16648c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_RQS_POS, 16658c2ecf20Sopenharmony_ci MTL_Q_RQOMR_RQS_LEN, fifo_size); 16668c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 16678c2ecf20Sopenharmony_ci } 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci netif_info(pdata, drv, pdata->netdev, 16708c2ecf20Sopenharmony_ci "%d Rx hardware queues, %d byte fifo per queue\n", 16718c2ecf20Sopenharmony_ci pdata->rx_q_count, ((fifo_size + 1) * 256)); 16728c2ecf20Sopenharmony_ci} 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_cistatic void xlgmac_config_flow_control_threshold(struct xlgmac_pdata *pdata) 16758c2ecf20Sopenharmony_ci{ 16768c2ecf20Sopenharmony_ci unsigned int i; 16778c2ecf20Sopenharmony_ci u32 regval; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci for (i = 0; i < pdata->rx_q_count; i++) { 16808c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_RQFCR)); 16818c2ecf20Sopenharmony_ci /* Activate flow control when less than 4k left in fifo */ 16828c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_RQFCR_RFA_POS, 16838c2ecf20Sopenharmony_ci MTL_Q_RQFCR_RFA_LEN, 2); 16848c2ecf20Sopenharmony_ci /* De-activate flow control when more than 6k left in fifo */ 16858c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_RQFCR_RFD_POS, 16868c2ecf20Sopenharmony_ci MTL_Q_RQFCR_RFD_LEN, 4); 16878c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_RQFCR)); 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci} 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_cistatic int xlgmac_config_tx_threshold(struct xlgmac_pdata *pdata, 16928c2ecf20Sopenharmony_ci unsigned int val) 16938c2ecf20Sopenharmony_ci{ 16948c2ecf20Sopenharmony_ci unsigned int i; 16958c2ecf20Sopenharmony_ci u32 regval; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci for (i = 0; i < pdata->tx_q_count; i++) { 16988c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 16998c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_TTC_POS, 17008c2ecf20Sopenharmony_ci MTL_Q_TQOMR_TTC_LEN, val); 17018c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 17028c2ecf20Sopenharmony_ci } 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci return 0; 17058c2ecf20Sopenharmony_ci} 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_cistatic int xlgmac_config_rsf_mode(struct xlgmac_pdata *pdata, 17088c2ecf20Sopenharmony_ci unsigned int val) 17098c2ecf20Sopenharmony_ci{ 17108c2ecf20Sopenharmony_ci unsigned int i; 17118c2ecf20Sopenharmony_ci u32 regval; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci for (i = 0; i < pdata->rx_q_count; i++) { 17148c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 17158c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_RSF_POS, 17168c2ecf20Sopenharmony_ci MTL_Q_RQOMR_RSF_LEN, val); 17178c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci return 0; 17218c2ecf20Sopenharmony_ci} 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_cistatic int xlgmac_config_tsf_mode(struct xlgmac_pdata *pdata, 17248c2ecf20Sopenharmony_ci unsigned int val) 17258c2ecf20Sopenharmony_ci{ 17268c2ecf20Sopenharmony_ci unsigned int i; 17278c2ecf20Sopenharmony_ci u32 regval; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci for (i = 0; i < pdata->tx_q_count; i++) { 17308c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 17318c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_TSF_POS, 17328c2ecf20Sopenharmony_ci MTL_Q_TQOMR_TSF_LEN, val); 17338c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci return 0; 17378c2ecf20Sopenharmony_ci} 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_cistatic int xlgmac_config_osp_mode(struct xlgmac_pdata *pdata) 17408c2ecf20Sopenharmony_ci{ 17418c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 17428c2ecf20Sopenharmony_ci unsigned int i; 17438c2ecf20Sopenharmony_ci u32 regval; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci channel = pdata->channel_head; 17468c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 17478c2ecf20Sopenharmony_ci if (!channel->tx_ring) 17488c2ecf20Sopenharmony_ci break; 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_TCR)); 17518c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_TCR_OSP_POS, 17528c2ecf20Sopenharmony_ci DMA_CH_TCR_OSP_LEN, 17538c2ecf20Sopenharmony_ci pdata->tx_osp_mode); 17548c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_TCR)); 17558c2ecf20Sopenharmony_ci } 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci return 0; 17588c2ecf20Sopenharmony_ci} 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_cistatic int xlgmac_config_pblx8(struct xlgmac_pdata *pdata) 17618c2ecf20Sopenharmony_ci{ 17628c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 17638c2ecf20Sopenharmony_ci unsigned int i; 17648c2ecf20Sopenharmony_ci u32 regval; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci channel = pdata->channel_head; 17678c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 17688c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_CR)); 17698c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_CR_PBLX8_POS, 17708c2ecf20Sopenharmony_ci DMA_CH_CR_PBLX8_LEN, 17718c2ecf20Sopenharmony_ci pdata->pblx8); 17728c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_CR)); 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci return 0; 17768c2ecf20Sopenharmony_ci} 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_cistatic int xlgmac_get_tx_pbl_val(struct xlgmac_pdata *pdata) 17798c2ecf20Sopenharmony_ci{ 17808c2ecf20Sopenharmony_ci u32 regval; 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(pdata->channel_head, DMA_CH_TCR)); 17838c2ecf20Sopenharmony_ci regval = XLGMAC_GET_REG_BITS(regval, DMA_CH_TCR_PBL_POS, 17848c2ecf20Sopenharmony_ci DMA_CH_TCR_PBL_LEN); 17858c2ecf20Sopenharmony_ci return regval; 17868c2ecf20Sopenharmony_ci} 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_cistatic int xlgmac_config_tx_pbl_val(struct xlgmac_pdata *pdata) 17898c2ecf20Sopenharmony_ci{ 17908c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 17918c2ecf20Sopenharmony_ci unsigned int i; 17928c2ecf20Sopenharmony_ci u32 regval; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci channel = pdata->channel_head; 17958c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 17968c2ecf20Sopenharmony_ci if (!channel->tx_ring) 17978c2ecf20Sopenharmony_ci break; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_TCR)); 18008c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_TCR_PBL_POS, 18018c2ecf20Sopenharmony_ci DMA_CH_TCR_PBL_LEN, 18028c2ecf20Sopenharmony_ci pdata->tx_pbl); 18038c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_TCR)); 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci return 0; 18078c2ecf20Sopenharmony_ci} 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_cistatic int xlgmac_get_rx_pbl_val(struct xlgmac_pdata *pdata) 18108c2ecf20Sopenharmony_ci{ 18118c2ecf20Sopenharmony_ci u32 regval; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(pdata->channel_head, DMA_CH_RCR)); 18148c2ecf20Sopenharmony_ci regval = XLGMAC_GET_REG_BITS(regval, DMA_CH_RCR_PBL_POS, 18158c2ecf20Sopenharmony_ci DMA_CH_RCR_PBL_LEN); 18168c2ecf20Sopenharmony_ci return regval; 18178c2ecf20Sopenharmony_ci} 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_cistatic int xlgmac_config_rx_pbl_val(struct xlgmac_pdata *pdata) 18208c2ecf20Sopenharmony_ci{ 18218c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 18228c2ecf20Sopenharmony_ci unsigned int i; 18238c2ecf20Sopenharmony_ci u32 regval; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci channel = pdata->channel_head; 18268c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 18278c2ecf20Sopenharmony_ci if (!channel->rx_ring) 18288c2ecf20Sopenharmony_ci break; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci regval = readl(XLGMAC_DMA_REG(channel, DMA_CH_RCR)); 18318c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_CH_RCR_PBL_POS, 18328c2ecf20Sopenharmony_ci DMA_CH_RCR_PBL_LEN, 18338c2ecf20Sopenharmony_ci pdata->rx_pbl); 18348c2ecf20Sopenharmony_ci writel(regval, XLGMAC_DMA_REG(channel, DMA_CH_RCR)); 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci return 0; 18388c2ecf20Sopenharmony_ci} 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_cistatic u64 xlgmac_mmc_read(struct xlgmac_pdata *pdata, unsigned int reg_lo) 18418c2ecf20Sopenharmony_ci{ 18428c2ecf20Sopenharmony_ci bool read_hi; 18438c2ecf20Sopenharmony_ci u64 val; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci switch (reg_lo) { 18468c2ecf20Sopenharmony_ci /* These registers are always 64 bit */ 18478c2ecf20Sopenharmony_ci case MMC_TXOCTETCOUNT_GB_LO: 18488c2ecf20Sopenharmony_ci case MMC_TXOCTETCOUNT_G_LO: 18498c2ecf20Sopenharmony_ci case MMC_RXOCTETCOUNT_GB_LO: 18508c2ecf20Sopenharmony_ci case MMC_RXOCTETCOUNT_G_LO: 18518c2ecf20Sopenharmony_ci read_hi = true; 18528c2ecf20Sopenharmony_ci break; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci default: 18558c2ecf20Sopenharmony_ci read_hi = false; 18568c2ecf20Sopenharmony_ci } 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci val = (u64)readl(pdata->mac_regs + reg_lo); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci if (read_hi) 18618c2ecf20Sopenharmony_ci val |= ((u64)readl(pdata->mac_regs + reg_lo + 4) << 32); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci return val; 18648c2ecf20Sopenharmony_ci} 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_cistatic void xlgmac_tx_mmc_int(struct xlgmac_pdata *pdata) 18678c2ecf20Sopenharmony_ci{ 18688c2ecf20Sopenharmony_ci unsigned int mmc_isr = readl(pdata->mac_regs + MMC_TISR); 18698c2ecf20Sopenharmony_ci struct xlgmac_stats *stats = &pdata->stats; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 18728c2ecf20Sopenharmony_ci MMC_TISR_TXOCTETCOUNT_GB_POS, 18738c2ecf20Sopenharmony_ci MMC_TISR_TXOCTETCOUNT_GB_LEN)) 18748c2ecf20Sopenharmony_ci stats->txoctetcount_gb += 18758c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXOCTETCOUNT_GB_LO); 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 18788c2ecf20Sopenharmony_ci MMC_TISR_TXFRAMECOUNT_GB_POS, 18798c2ecf20Sopenharmony_ci MMC_TISR_TXFRAMECOUNT_GB_LEN)) 18808c2ecf20Sopenharmony_ci stats->txframecount_gb += 18818c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXFRAMECOUNT_GB_LO); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 18848c2ecf20Sopenharmony_ci MMC_TISR_TXBROADCASTFRAMES_G_POS, 18858c2ecf20Sopenharmony_ci MMC_TISR_TXBROADCASTFRAMES_G_LEN)) 18868c2ecf20Sopenharmony_ci stats->txbroadcastframes_g += 18878c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXBROADCASTFRAMES_G_LO); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 18908c2ecf20Sopenharmony_ci MMC_TISR_TXMULTICASTFRAMES_G_POS, 18918c2ecf20Sopenharmony_ci MMC_TISR_TXMULTICASTFRAMES_G_LEN)) 18928c2ecf20Sopenharmony_ci stats->txmulticastframes_g += 18938c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXMULTICASTFRAMES_G_LO); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 18968c2ecf20Sopenharmony_ci MMC_TISR_TX64OCTETS_GB_POS, 18978c2ecf20Sopenharmony_ci MMC_TISR_TX64OCTETS_GB_LEN)) 18988c2ecf20Sopenharmony_ci stats->tx64octets_gb += 18998c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX64OCTETS_GB_LO); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19028c2ecf20Sopenharmony_ci MMC_TISR_TX65TO127OCTETS_GB_POS, 19038c2ecf20Sopenharmony_ci MMC_TISR_TX65TO127OCTETS_GB_LEN)) 19048c2ecf20Sopenharmony_ci stats->tx65to127octets_gb += 19058c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX65TO127OCTETS_GB_LO); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19088c2ecf20Sopenharmony_ci MMC_TISR_TX128TO255OCTETS_GB_POS, 19098c2ecf20Sopenharmony_ci MMC_TISR_TX128TO255OCTETS_GB_LEN)) 19108c2ecf20Sopenharmony_ci stats->tx128to255octets_gb += 19118c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX128TO255OCTETS_GB_LO); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19148c2ecf20Sopenharmony_ci MMC_TISR_TX256TO511OCTETS_GB_POS, 19158c2ecf20Sopenharmony_ci MMC_TISR_TX256TO511OCTETS_GB_LEN)) 19168c2ecf20Sopenharmony_ci stats->tx256to511octets_gb += 19178c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX256TO511OCTETS_GB_LO); 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19208c2ecf20Sopenharmony_ci MMC_TISR_TX512TO1023OCTETS_GB_POS, 19218c2ecf20Sopenharmony_ci MMC_TISR_TX512TO1023OCTETS_GB_LEN)) 19228c2ecf20Sopenharmony_ci stats->tx512to1023octets_gb += 19238c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX512TO1023OCTETS_GB_LO); 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19268c2ecf20Sopenharmony_ci MMC_TISR_TX1024TOMAXOCTETS_GB_POS, 19278c2ecf20Sopenharmony_ci MMC_TISR_TX1024TOMAXOCTETS_GB_LEN)) 19288c2ecf20Sopenharmony_ci stats->tx1024tomaxoctets_gb += 19298c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX1024TOMAXOCTETS_GB_LO); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19328c2ecf20Sopenharmony_ci MMC_TISR_TXUNICASTFRAMES_GB_POS, 19338c2ecf20Sopenharmony_ci MMC_TISR_TXUNICASTFRAMES_GB_LEN)) 19348c2ecf20Sopenharmony_ci stats->txunicastframes_gb += 19358c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXUNICASTFRAMES_GB_LO); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19388c2ecf20Sopenharmony_ci MMC_TISR_TXMULTICASTFRAMES_GB_POS, 19398c2ecf20Sopenharmony_ci MMC_TISR_TXMULTICASTFRAMES_GB_LEN)) 19408c2ecf20Sopenharmony_ci stats->txmulticastframes_gb += 19418c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXMULTICASTFRAMES_GB_LO); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19448c2ecf20Sopenharmony_ci MMC_TISR_TXBROADCASTFRAMES_GB_POS, 19458c2ecf20Sopenharmony_ci MMC_TISR_TXBROADCASTFRAMES_GB_LEN)) 19468c2ecf20Sopenharmony_ci stats->txbroadcastframes_g += 19478c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXBROADCASTFRAMES_GB_LO); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19508c2ecf20Sopenharmony_ci MMC_TISR_TXUNDERFLOWERROR_POS, 19518c2ecf20Sopenharmony_ci MMC_TISR_TXUNDERFLOWERROR_LEN)) 19528c2ecf20Sopenharmony_ci stats->txunderflowerror += 19538c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXUNDERFLOWERROR_LO); 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19568c2ecf20Sopenharmony_ci MMC_TISR_TXOCTETCOUNT_G_POS, 19578c2ecf20Sopenharmony_ci MMC_TISR_TXOCTETCOUNT_G_LEN)) 19588c2ecf20Sopenharmony_ci stats->txoctetcount_g += 19598c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXOCTETCOUNT_G_LO); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19628c2ecf20Sopenharmony_ci MMC_TISR_TXFRAMECOUNT_G_POS, 19638c2ecf20Sopenharmony_ci MMC_TISR_TXFRAMECOUNT_G_LEN)) 19648c2ecf20Sopenharmony_ci stats->txframecount_g += 19658c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXFRAMECOUNT_G_LO); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19688c2ecf20Sopenharmony_ci MMC_TISR_TXPAUSEFRAMES_POS, 19698c2ecf20Sopenharmony_ci MMC_TISR_TXPAUSEFRAMES_LEN)) 19708c2ecf20Sopenharmony_ci stats->txpauseframes += 19718c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXPAUSEFRAMES_LO); 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19748c2ecf20Sopenharmony_ci MMC_TISR_TXVLANFRAMES_G_POS, 19758c2ecf20Sopenharmony_ci MMC_TISR_TXVLANFRAMES_G_LEN)) 19768c2ecf20Sopenharmony_ci stats->txvlanframes_g += 19778c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXVLANFRAMES_G_LO); 19788c2ecf20Sopenharmony_ci} 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_cistatic void xlgmac_rx_mmc_int(struct xlgmac_pdata *pdata) 19818c2ecf20Sopenharmony_ci{ 19828c2ecf20Sopenharmony_ci unsigned int mmc_isr = readl(pdata->mac_regs + MMC_RISR); 19838c2ecf20Sopenharmony_ci struct xlgmac_stats *stats = &pdata->stats; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19868c2ecf20Sopenharmony_ci MMC_RISR_RXFRAMECOUNT_GB_POS, 19878c2ecf20Sopenharmony_ci MMC_RISR_RXFRAMECOUNT_GB_LEN)) 19888c2ecf20Sopenharmony_ci stats->rxframecount_gb += 19898c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXFRAMECOUNT_GB_LO); 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19928c2ecf20Sopenharmony_ci MMC_RISR_RXOCTETCOUNT_GB_POS, 19938c2ecf20Sopenharmony_ci MMC_RISR_RXOCTETCOUNT_GB_LEN)) 19948c2ecf20Sopenharmony_ci stats->rxoctetcount_gb += 19958c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXOCTETCOUNT_GB_LO); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 19988c2ecf20Sopenharmony_ci MMC_RISR_RXOCTETCOUNT_G_POS, 19998c2ecf20Sopenharmony_ci MMC_RISR_RXOCTETCOUNT_G_LEN)) 20008c2ecf20Sopenharmony_ci stats->rxoctetcount_g += 20018c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXOCTETCOUNT_G_LO); 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20048c2ecf20Sopenharmony_ci MMC_RISR_RXBROADCASTFRAMES_G_POS, 20058c2ecf20Sopenharmony_ci MMC_RISR_RXBROADCASTFRAMES_G_LEN)) 20068c2ecf20Sopenharmony_ci stats->rxbroadcastframes_g += 20078c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXBROADCASTFRAMES_G_LO); 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20108c2ecf20Sopenharmony_ci MMC_RISR_RXMULTICASTFRAMES_G_POS, 20118c2ecf20Sopenharmony_ci MMC_RISR_RXMULTICASTFRAMES_G_LEN)) 20128c2ecf20Sopenharmony_ci stats->rxmulticastframes_g += 20138c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXMULTICASTFRAMES_G_LO); 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20168c2ecf20Sopenharmony_ci MMC_RISR_RXCRCERROR_POS, 20178c2ecf20Sopenharmony_ci MMC_RISR_RXCRCERROR_LEN)) 20188c2ecf20Sopenharmony_ci stats->rxcrcerror += 20198c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXCRCERROR_LO); 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20228c2ecf20Sopenharmony_ci MMC_RISR_RXRUNTERROR_POS, 20238c2ecf20Sopenharmony_ci MMC_RISR_RXRUNTERROR_LEN)) 20248c2ecf20Sopenharmony_ci stats->rxrunterror += 20258c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXRUNTERROR); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20288c2ecf20Sopenharmony_ci MMC_RISR_RXJABBERERROR_POS, 20298c2ecf20Sopenharmony_ci MMC_RISR_RXJABBERERROR_LEN)) 20308c2ecf20Sopenharmony_ci stats->rxjabbererror += 20318c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXJABBERERROR); 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20348c2ecf20Sopenharmony_ci MMC_RISR_RXUNDERSIZE_G_POS, 20358c2ecf20Sopenharmony_ci MMC_RISR_RXUNDERSIZE_G_LEN)) 20368c2ecf20Sopenharmony_ci stats->rxundersize_g += 20378c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXUNDERSIZE_G); 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20408c2ecf20Sopenharmony_ci MMC_RISR_RXOVERSIZE_G_POS, 20418c2ecf20Sopenharmony_ci MMC_RISR_RXOVERSIZE_G_LEN)) 20428c2ecf20Sopenharmony_ci stats->rxoversize_g += 20438c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXOVERSIZE_G); 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20468c2ecf20Sopenharmony_ci MMC_RISR_RX64OCTETS_GB_POS, 20478c2ecf20Sopenharmony_ci MMC_RISR_RX64OCTETS_GB_LEN)) 20488c2ecf20Sopenharmony_ci stats->rx64octets_gb += 20498c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX64OCTETS_GB_LO); 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20528c2ecf20Sopenharmony_ci MMC_RISR_RX65TO127OCTETS_GB_POS, 20538c2ecf20Sopenharmony_ci MMC_RISR_RX65TO127OCTETS_GB_LEN)) 20548c2ecf20Sopenharmony_ci stats->rx65to127octets_gb += 20558c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX65TO127OCTETS_GB_LO); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20588c2ecf20Sopenharmony_ci MMC_RISR_RX128TO255OCTETS_GB_POS, 20598c2ecf20Sopenharmony_ci MMC_RISR_RX128TO255OCTETS_GB_LEN)) 20608c2ecf20Sopenharmony_ci stats->rx128to255octets_gb += 20618c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX128TO255OCTETS_GB_LO); 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20648c2ecf20Sopenharmony_ci MMC_RISR_RX256TO511OCTETS_GB_POS, 20658c2ecf20Sopenharmony_ci MMC_RISR_RX256TO511OCTETS_GB_LEN)) 20668c2ecf20Sopenharmony_ci stats->rx256to511octets_gb += 20678c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX256TO511OCTETS_GB_LO); 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20708c2ecf20Sopenharmony_ci MMC_RISR_RX512TO1023OCTETS_GB_POS, 20718c2ecf20Sopenharmony_ci MMC_RISR_RX512TO1023OCTETS_GB_LEN)) 20728c2ecf20Sopenharmony_ci stats->rx512to1023octets_gb += 20738c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX512TO1023OCTETS_GB_LO); 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20768c2ecf20Sopenharmony_ci MMC_RISR_RX1024TOMAXOCTETS_GB_POS, 20778c2ecf20Sopenharmony_ci MMC_RISR_RX1024TOMAXOCTETS_GB_LEN)) 20788c2ecf20Sopenharmony_ci stats->rx1024tomaxoctets_gb += 20798c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX1024TOMAXOCTETS_GB_LO); 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20828c2ecf20Sopenharmony_ci MMC_RISR_RXUNICASTFRAMES_G_POS, 20838c2ecf20Sopenharmony_ci MMC_RISR_RXUNICASTFRAMES_G_LEN)) 20848c2ecf20Sopenharmony_ci stats->rxunicastframes_g += 20858c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXUNICASTFRAMES_G_LO); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20888c2ecf20Sopenharmony_ci MMC_RISR_RXLENGTHERROR_POS, 20898c2ecf20Sopenharmony_ci MMC_RISR_RXLENGTHERROR_LEN)) 20908c2ecf20Sopenharmony_ci stats->rxlengtherror += 20918c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXLENGTHERROR_LO); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 20948c2ecf20Sopenharmony_ci MMC_RISR_RXOUTOFRANGETYPE_POS, 20958c2ecf20Sopenharmony_ci MMC_RISR_RXOUTOFRANGETYPE_LEN)) 20968c2ecf20Sopenharmony_ci stats->rxoutofrangetype += 20978c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXOUTOFRANGETYPE_LO); 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 21008c2ecf20Sopenharmony_ci MMC_RISR_RXPAUSEFRAMES_POS, 21018c2ecf20Sopenharmony_ci MMC_RISR_RXPAUSEFRAMES_LEN)) 21028c2ecf20Sopenharmony_ci stats->rxpauseframes += 21038c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXPAUSEFRAMES_LO); 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 21068c2ecf20Sopenharmony_ci MMC_RISR_RXFIFOOVERFLOW_POS, 21078c2ecf20Sopenharmony_ci MMC_RISR_RXFIFOOVERFLOW_LEN)) 21088c2ecf20Sopenharmony_ci stats->rxfifooverflow += 21098c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXFIFOOVERFLOW_LO); 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 21128c2ecf20Sopenharmony_ci MMC_RISR_RXVLANFRAMES_GB_POS, 21138c2ecf20Sopenharmony_ci MMC_RISR_RXVLANFRAMES_GB_LEN)) 21148c2ecf20Sopenharmony_ci stats->rxvlanframes_gb += 21158c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXVLANFRAMES_GB_LO); 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS(mmc_isr, 21188c2ecf20Sopenharmony_ci MMC_RISR_RXWATCHDOGERROR_POS, 21198c2ecf20Sopenharmony_ci MMC_RISR_RXWATCHDOGERROR_LEN)) 21208c2ecf20Sopenharmony_ci stats->rxwatchdogerror += 21218c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXWATCHDOGERROR); 21228c2ecf20Sopenharmony_ci} 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_cistatic void xlgmac_read_mmc_stats(struct xlgmac_pdata *pdata) 21258c2ecf20Sopenharmony_ci{ 21268c2ecf20Sopenharmony_ci struct xlgmac_stats *stats = &pdata->stats; 21278c2ecf20Sopenharmony_ci u32 regval; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci /* Freeze counters */ 21308c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MMC_CR); 21318c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MMC_CR_MCF_POS, 21328c2ecf20Sopenharmony_ci MMC_CR_MCF_LEN, 1); 21338c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MMC_CR); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci stats->txoctetcount_gb += 21368c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXOCTETCOUNT_GB_LO); 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci stats->txframecount_gb += 21398c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXFRAMECOUNT_GB_LO); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci stats->txbroadcastframes_g += 21428c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXBROADCASTFRAMES_G_LO); 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci stats->txmulticastframes_g += 21458c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXMULTICASTFRAMES_G_LO); 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci stats->tx64octets_gb += 21488c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX64OCTETS_GB_LO); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci stats->tx65to127octets_gb += 21518c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX65TO127OCTETS_GB_LO); 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci stats->tx128to255octets_gb += 21548c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX128TO255OCTETS_GB_LO); 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci stats->tx256to511octets_gb += 21578c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX256TO511OCTETS_GB_LO); 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci stats->tx512to1023octets_gb += 21608c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX512TO1023OCTETS_GB_LO); 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci stats->tx1024tomaxoctets_gb += 21638c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TX1024TOMAXOCTETS_GB_LO); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci stats->txunicastframes_gb += 21668c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXUNICASTFRAMES_GB_LO); 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci stats->txmulticastframes_gb += 21698c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXMULTICASTFRAMES_GB_LO); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci stats->txbroadcastframes_g += 21728c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXBROADCASTFRAMES_GB_LO); 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci stats->txunderflowerror += 21758c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXUNDERFLOWERROR_LO); 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci stats->txoctetcount_g += 21788c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXOCTETCOUNT_G_LO); 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci stats->txframecount_g += 21818c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXFRAMECOUNT_G_LO); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci stats->txpauseframes += 21848c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXPAUSEFRAMES_LO); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci stats->txvlanframes_g += 21878c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_TXVLANFRAMES_G_LO); 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci stats->rxframecount_gb += 21908c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXFRAMECOUNT_GB_LO); 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci stats->rxoctetcount_gb += 21938c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXOCTETCOUNT_GB_LO); 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci stats->rxoctetcount_g += 21968c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXOCTETCOUNT_G_LO); 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci stats->rxbroadcastframes_g += 21998c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXBROADCASTFRAMES_G_LO); 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci stats->rxmulticastframes_g += 22028c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXMULTICASTFRAMES_G_LO); 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci stats->rxcrcerror += 22058c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXCRCERROR_LO); 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci stats->rxrunterror += 22088c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXRUNTERROR); 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci stats->rxjabbererror += 22118c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXJABBERERROR); 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci stats->rxundersize_g += 22148c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXUNDERSIZE_G); 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci stats->rxoversize_g += 22178c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXOVERSIZE_G); 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci stats->rx64octets_gb += 22208c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX64OCTETS_GB_LO); 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci stats->rx65to127octets_gb += 22238c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX65TO127OCTETS_GB_LO); 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci stats->rx128to255octets_gb += 22268c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX128TO255OCTETS_GB_LO); 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci stats->rx256to511octets_gb += 22298c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX256TO511OCTETS_GB_LO); 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci stats->rx512to1023octets_gb += 22328c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX512TO1023OCTETS_GB_LO); 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci stats->rx1024tomaxoctets_gb += 22358c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RX1024TOMAXOCTETS_GB_LO); 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci stats->rxunicastframes_g += 22388c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXUNICASTFRAMES_G_LO); 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci stats->rxlengtherror += 22418c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXLENGTHERROR_LO); 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci stats->rxoutofrangetype += 22448c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXOUTOFRANGETYPE_LO); 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci stats->rxpauseframes += 22478c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXPAUSEFRAMES_LO); 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci stats->rxfifooverflow += 22508c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXFIFOOVERFLOW_LO); 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci stats->rxvlanframes_gb += 22538c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXVLANFRAMES_GB_LO); 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci stats->rxwatchdogerror += 22568c2ecf20Sopenharmony_ci xlgmac_mmc_read(pdata, MMC_RXWATCHDOGERROR); 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci /* Un-freeze counters */ 22598c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MMC_CR); 22608c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MMC_CR_MCF_POS, 22618c2ecf20Sopenharmony_ci MMC_CR_MCF_LEN, 0); 22628c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MMC_CR); 22638c2ecf20Sopenharmony_ci} 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_cistatic void xlgmac_config_mmc(struct xlgmac_pdata *pdata) 22668c2ecf20Sopenharmony_ci{ 22678c2ecf20Sopenharmony_ci u32 regval; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MMC_CR); 22708c2ecf20Sopenharmony_ci /* Set counters to reset on read */ 22718c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MMC_CR_ROR_POS, 22728c2ecf20Sopenharmony_ci MMC_CR_ROR_LEN, 1); 22738c2ecf20Sopenharmony_ci /* Reset the counters */ 22748c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MMC_CR_CR_POS, 22758c2ecf20Sopenharmony_ci MMC_CR_CR_LEN, 1); 22768c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MMC_CR); 22778c2ecf20Sopenharmony_ci} 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_cistatic int xlgmac_write_rss_reg(struct xlgmac_pdata *pdata, unsigned int type, 22808c2ecf20Sopenharmony_ci unsigned int index, unsigned int val) 22818c2ecf20Sopenharmony_ci{ 22828c2ecf20Sopenharmony_ci unsigned int wait; 22838c2ecf20Sopenharmony_ci int ret = 0; 22848c2ecf20Sopenharmony_ci u32 regval; 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci mutex_lock(&pdata->rss_mutex); 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci regval = XLGMAC_GET_REG_BITS(readl(pdata->mac_regs + MAC_RSSAR), 22898c2ecf20Sopenharmony_ci MAC_RSSAR_OB_POS, MAC_RSSAR_OB_LEN); 22908c2ecf20Sopenharmony_ci if (regval) { 22918c2ecf20Sopenharmony_ci ret = -EBUSY; 22928c2ecf20Sopenharmony_ci goto unlock; 22938c2ecf20Sopenharmony_ci } 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci writel(val, pdata->mac_regs + MAC_RSSDR); 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_RSSAR); 22988c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RSSAR_RSSIA_POS, 22998c2ecf20Sopenharmony_ci MAC_RSSAR_RSSIA_LEN, index); 23008c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RSSAR_ADDRT_POS, 23018c2ecf20Sopenharmony_ci MAC_RSSAR_ADDRT_LEN, type); 23028c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RSSAR_CT_POS, 23038c2ecf20Sopenharmony_ci MAC_RSSAR_CT_LEN, 0); 23048c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RSSAR_OB_POS, 23058c2ecf20Sopenharmony_ci MAC_RSSAR_OB_LEN, 1); 23068c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RSSAR); 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci wait = 1000; 23098c2ecf20Sopenharmony_ci while (wait--) { 23108c2ecf20Sopenharmony_ci regval = XLGMAC_GET_REG_BITS(readl(pdata->mac_regs + MAC_RSSAR), 23118c2ecf20Sopenharmony_ci MAC_RSSAR_OB_POS, 23128c2ecf20Sopenharmony_ci MAC_RSSAR_OB_LEN); 23138c2ecf20Sopenharmony_ci if (!regval) 23148c2ecf20Sopenharmony_ci goto unlock; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci usleep_range(1000, 1500); 23178c2ecf20Sopenharmony_ci } 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci ret = -EBUSY; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ciunlock: 23228c2ecf20Sopenharmony_ci mutex_unlock(&pdata->rss_mutex); 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci return ret; 23258c2ecf20Sopenharmony_ci} 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_cistatic int xlgmac_write_rss_hash_key(struct xlgmac_pdata *pdata) 23288c2ecf20Sopenharmony_ci{ 23298c2ecf20Sopenharmony_ci unsigned int key_regs = sizeof(pdata->rss_key) / sizeof(u32); 23308c2ecf20Sopenharmony_ci unsigned int *key = (unsigned int *)&pdata->rss_key; 23318c2ecf20Sopenharmony_ci int ret; 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci while (key_regs--) { 23348c2ecf20Sopenharmony_ci ret = xlgmac_write_rss_reg(pdata, XLGMAC_RSS_HASH_KEY_TYPE, 23358c2ecf20Sopenharmony_ci key_regs, *key++); 23368c2ecf20Sopenharmony_ci if (ret) 23378c2ecf20Sopenharmony_ci return ret; 23388c2ecf20Sopenharmony_ci } 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci return 0; 23418c2ecf20Sopenharmony_ci} 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_cistatic int xlgmac_write_rss_lookup_table(struct xlgmac_pdata *pdata) 23448c2ecf20Sopenharmony_ci{ 23458c2ecf20Sopenharmony_ci unsigned int i; 23468c2ecf20Sopenharmony_ci int ret; 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++) { 23498c2ecf20Sopenharmony_ci ret = xlgmac_write_rss_reg(pdata, 23508c2ecf20Sopenharmony_ci XLGMAC_RSS_LOOKUP_TABLE_TYPE, i, 23518c2ecf20Sopenharmony_ci pdata->rss_table[i]); 23528c2ecf20Sopenharmony_ci if (ret) 23538c2ecf20Sopenharmony_ci return ret; 23548c2ecf20Sopenharmony_ci } 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci return 0; 23578c2ecf20Sopenharmony_ci} 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_cistatic int xlgmac_set_rss_hash_key(struct xlgmac_pdata *pdata, const u8 *key) 23608c2ecf20Sopenharmony_ci{ 23618c2ecf20Sopenharmony_ci memcpy(pdata->rss_key, key, sizeof(pdata->rss_key)); 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci return xlgmac_write_rss_hash_key(pdata); 23648c2ecf20Sopenharmony_ci} 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_cistatic int xlgmac_set_rss_lookup_table(struct xlgmac_pdata *pdata, 23678c2ecf20Sopenharmony_ci const u32 *table) 23688c2ecf20Sopenharmony_ci{ 23698c2ecf20Sopenharmony_ci unsigned int i; 23708c2ecf20Sopenharmony_ci u32 tval; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++) { 23738c2ecf20Sopenharmony_ci tval = table[i]; 23748c2ecf20Sopenharmony_ci pdata->rss_table[i] = XLGMAC_SET_REG_BITS( 23758c2ecf20Sopenharmony_ci pdata->rss_table[i], 23768c2ecf20Sopenharmony_ci MAC_RSSDR_DMCH_POS, 23778c2ecf20Sopenharmony_ci MAC_RSSDR_DMCH_LEN, 23788c2ecf20Sopenharmony_ci tval); 23798c2ecf20Sopenharmony_ci } 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci return xlgmac_write_rss_lookup_table(pdata); 23828c2ecf20Sopenharmony_ci} 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_cistatic int xlgmac_enable_rss(struct xlgmac_pdata *pdata) 23858c2ecf20Sopenharmony_ci{ 23868c2ecf20Sopenharmony_ci u32 regval; 23878c2ecf20Sopenharmony_ci int ret; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci if (!pdata->hw_feat.rss) 23908c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci /* Program the hash key */ 23938c2ecf20Sopenharmony_ci ret = xlgmac_write_rss_hash_key(pdata); 23948c2ecf20Sopenharmony_ci if (ret) 23958c2ecf20Sopenharmony_ci return ret; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci /* Program the lookup table */ 23988c2ecf20Sopenharmony_ci ret = xlgmac_write_rss_lookup_table(pdata); 23998c2ecf20Sopenharmony_ci if (ret) 24008c2ecf20Sopenharmony_ci return ret; 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci /* Set the RSS options */ 24038c2ecf20Sopenharmony_ci writel(pdata->rss_options, pdata->mac_regs + MAC_RSSCR); 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci /* Enable RSS */ 24068c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_RSSCR); 24078c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RSSCR_RSSE_POS, 24088c2ecf20Sopenharmony_ci MAC_RSSCR_RSSE_LEN, 1); 24098c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RSSCR); 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci return 0; 24128c2ecf20Sopenharmony_ci} 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_cistatic int xlgmac_disable_rss(struct xlgmac_pdata *pdata) 24158c2ecf20Sopenharmony_ci{ 24168c2ecf20Sopenharmony_ci u32 regval; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci if (!pdata->hw_feat.rss) 24198c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_RSSCR); 24228c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_RSSCR_RSSE_POS, 24238c2ecf20Sopenharmony_ci MAC_RSSCR_RSSE_LEN, 0); 24248c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_RSSCR); 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci return 0; 24278c2ecf20Sopenharmony_ci} 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_cistatic void xlgmac_config_rss(struct xlgmac_pdata *pdata) 24308c2ecf20Sopenharmony_ci{ 24318c2ecf20Sopenharmony_ci int ret; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci if (!pdata->hw_feat.rss) 24348c2ecf20Sopenharmony_ci return; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci if (pdata->netdev->features & NETIF_F_RXHASH) 24378c2ecf20Sopenharmony_ci ret = xlgmac_enable_rss(pdata); 24388c2ecf20Sopenharmony_ci else 24398c2ecf20Sopenharmony_ci ret = xlgmac_disable_rss(pdata); 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci if (ret) 24428c2ecf20Sopenharmony_ci netdev_err(pdata->netdev, 24438c2ecf20Sopenharmony_ci "error configuring RSS, RSS disabled\n"); 24448c2ecf20Sopenharmony_ci} 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_cistatic void xlgmac_enable_dma_interrupts(struct xlgmac_pdata *pdata) 24478c2ecf20Sopenharmony_ci{ 24488c2ecf20Sopenharmony_ci unsigned int dma_ch_isr, dma_ch_ier; 24498c2ecf20Sopenharmony_ci struct xlgmac_channel *channel; 24508c2ecf20Sopenharmony_ci unsigned int i; 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci channel = pdata->channel_head; 24538c2ecf20Sopenharmony_ci for (i = 0; i < pdata->channel_count; i++, channel++) { 24548c2ecf20Sopenharmony_ci /* Clear all the interrupts which are set */ 24558c2ecf20Sopenharmony_ci dma_ch_isr = readl(XLGMAC_DMA_REG(channel, DMA_CH_SR)); 24568c2ecf20Sopenharmony_ci writel(dma_ch_isr, XLGMAC_DMA_REG(channel, DMA_CH_SR)); 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci /* Clear all interrupt enable bits */ 24598c2ecf20Sopenharmony_ci dma_ch_ier = 0; 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_ci /* Enable following interrupts 24628c2ecf20Sopenharmony_ci * NIE - Normal Interrupt Summary Enable 24638c2ecf20Sopenharmony_ci * AIE - Abnormal Interrupt Summary Enable 24648c2ecf20Sopenharmony_ci * FBEE - Fatal Bus Error Enable 24658c2ecf20Sopenharmony_ci */ 24668c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS(dma_ch_ier, 24678c2ecf20Sopenharmony_ci DMA_CH_IER_NIE_POS, 24688c2ecf20Sopenharmony_ci DMA_CH_IER_NIE_LEN, 1); 24698c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS(dma_ch_ier, 24708c2ecf20Sopenharmony_ci DMA_CH_IER_AIE_POS, 24718c2ecf20Sopenharmony_ci DMA_CH_IER_AIE_LEN, 1); 24728c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS(dma_ch_ier, 24738c2ecf20Sopenharmony_ci DMA_CH_IER_FBEE_POS, 24748c2ecf20Sopenharmony_ci DMA_CH_IER_FBEE_LEN, 1); 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci if (channel->tx_ring) { 24778c2ecf20Sopenharmony_ci /* Enable the following Tx interrupts 24788c2ecf20Sopenharmony_ci * TIE - Transmit Interrupt Enable (unless using 24798c2ecf20Sopenharmony_ci * per channel interrupts) 24808c2ecf20Sopenharmony_ci */ 24818c2ecf20Sopenharmony_ci if (!pdata->per_channel_irq) 24828c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 24838c2ecf20Sopenharmony_ci dma_ch_ier, 24848c2ecf20Sopenharmony_ci DMA_CH_IER_TIE_POS, 24858c2ecf20Sopenharmony_ci DMA_CH_IER_TIE_LEN, 24868c2ecf20Sopenharmony_ci 1); 24878c2ecf20Sopenharmony_ci } 24888c2ecf20Sopenharmony_ci if (channel->rx_ring) { 24898c2ecf20Sopenharmony_ci /* Enable following Rx interrupts 24908c2ecf20Sopenharmony_ci * RBUE - Receive Buffer Unavailable Enable 24918c2ecf20Sopenharmony_ci * RIE - Receive Interrupt Enable (unless using 24928c2ecf20Sopenharmony_ci * per channel interrupts) 24938c2ecf20Sopenharmony_ci */ 24948c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 24958c2ecf20Sopenharmony_ci dma_ch_ier, 24968c2ecf20Sopenharmony_ci DMA_CH_IER_RBUE_POS, 24978c2ecf20Sopenharmony_ci DMA_CH_IER_RBUE_LEN, 24988c2ecf20Sopenharmony_ci 1); 24998c2ecf20Sopenharmony_ci if (!pdata->per_channel_irq) 25008c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 25018c2ecf20Sopenharmony_ci dma_ch_ier, 25028c2ecf20Sopenharmony_ci DMA_CH_IER_RIE_POS, 25038c2ecf20Sopenharmony_ci DMA_CH_IER_RIE_LEN, 25048c2ecf20Sopenharmony_ci 1); 25058c2ecf20Sopenharmony_ci } 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci writel(dma_ch_isr, XLGMAC_DMA_REG(channel, DMA_CH_IER)); 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci} 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_cistatic void xlgmac_enable_mtl_interrupts(struct xlgmac_pdata *pdata) 25128c2ecf20Sopenharmony_ci{ 25138c2ecf20Sopenharmony_ci unsigned int q_count, i; 25148c2ecf20Sopenharmony_ci unsigned int mtl_q_isr; 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci q_count = max(pdata->hw_feat.tx_q_cnt, pdata->hw_feat.rx_q_cnt); 25178c2ecf20Sopenharmony_ci for (i = 0; i < q_count; i++) { 25188c2ecf20Sopenharmony_ci /* Clear all the interrupts which are set */ 25198c2ecf20Sopenharmony_ci mtl_q_isr = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_ISR)); 25208c2ecf20Sopenharmony_ci writel(mtl_q_isr, XLGMAC_MTL_REG(pdata, i, MTL_Q_ISR)); 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci /* No MTL interrupts to be enabled */ 25238c2ecf20Sopenharmony_ci writel(0, XLGMAC_MTL_REG(pdata, i, MTL_Q_IER)); 25248c2ecf20Sopenharmony_ci } 25258c2ecf20Sopenharmony_ci} 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_cistatic void xlgmac_enable_mac_interrupts(struct xlgmac_pdata *pdata) 25288c2ecf20Sopenharmony_ci{ 25298c2ecf20Sopenharmony_ci unsigned int mac_ier = 0; 25308c2ecf20Sopenharmony_ci u32 regval; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci /* Enable Timestamp interrupt */ 25338c2ecf20Sopenharmony_ci mac_ier = XLGMAC_SET_REG_BITS(mac_ier, MAC_IER_TSIE_POS, 25348c2ecf20Sopenharmony_ci MAC_IER_TSIE_LEN, 1); 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci writel(mac_ier, pdata->mac_regs + MAC_IER); 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci /* Enable all counter interrupts */ 25398c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MMC_RIER); 25408c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MMC_RIER_ALL_INTERRUPTS_POS, 25418c2ecf20Sopenharmony_ci MMC_RIER_ALL_INTERRUPTS_LEN, 0xffffffff); 25428c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MMC_RIER); 25438c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MMC_TIER); 25448c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MMC_TIER_ALL_INTERRUPTS_POS, 25458c2ecf20Sopenharmony_ci MMC_TIER_ALL_INTERRUPTS_LEN, 0xffffffff); 25468c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MMC_TIER); 25478c2ecf20Sopenharmony_ci} 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_cistatic int xlgmac_set_xlgmii_25000_speed(struct xlgmac_pdata *pdata) 25508c2ecf20Sopenharmony_ci{ 25518c2ecf20Sopenharmony_ci u32 regval; 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci regval = XLGMAC_GET_REG_BITS(readl(pdata->mac_regs + MAC_TCR), 25548c2ecf20Sopenharmony_ci MAC_TCR_SS_POS, MAC_TCR_SS_LEN); 25558c2ecf20Sopenharmony_ci if (regval == 0x1) 25568c2ecf20Sopenharmony_ci return 0; 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_TCR); 25598c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_TCR_SS_POS, 25608c2ecf20Sopenharmony_ci MAC_TCR_SS_LEN, 0x1); 25618c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_TCR); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci return 0; 25648c2ecf20Sopenharmony_ci} 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_cistatic int xlgmac_set_xlgmii_40000_speed(struct xlgmac_pdata *pdata) 25678c2ecf20Sopenharmony_ci{ 25688c2ecf20Sopenharmony_ci u32 regval; 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci regval = XLGMAC_GET_REG_BITS(readl(pdata->mac_regs + MAC_TCR), 25718c2ecf20Sopenharmony_ci MAC_TCR_SS_POS, MAC_TCR_SS_LEN); 25728c2ecf20Sopenharmony_ci if (regval == 0) 25738c2ecf20Sopenharmony_ci return 0; 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_TCR); 25768c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_TCR_SS_POS, 25778c2ecf20Sopenharmony_ci MAC_TCR_SS_LEN, 0); 25788c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_TCR); 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci return 0; 25818c2ecf20Sopenharmony_ci} 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_cistatic int xlgmac_set_xlgmii_50000_speed(struct xlgmac_pdata *pdata) 25848c2ecf20Sopenharmony_ci{ 25858c2ecf20Sopenharmony_ci u32 regval; 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci regval = XLGMAC_GET_REG_BITS(readl(pdata->mac_regs + MAC_TCR), 25888c2ecf20Sopenharmony_ci MAC_TCR_SS_POS, MAC_TCR_SS_LEN); 25898c2ecf20Sopenharmony_ci if (regval == 0x2) 25908c2ecf20Sopenharmony_ci return 0; 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_TCR); 25938c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_TCR_SS_POS, 25948c2ecf20Sopenharmony_ci MAC_TCR_SS_LEN, 0x2); 25958c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_TCR); 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci return 0; 25988c2ecf20Sopenharmony_ci} 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_cistatic int xlgmac_set_xlgmii_100000_speed(struct xlgmac_pdata *pdata) 26018c2ecf20Sopenharmony_ci{ 26028c2ecf20Sopenharmony_ci u32 regval; 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci regval = XLGMAC_GET_REG_BITS(readl(pdata->mac_regs + MAC_TCR), 26058c2ecf20Sopenharmony_ci MAC_TCR_SS_POS, MAC_TCR_SS_LEN); 26068c2ecf20Sopenharmony_ci if (regval == 0x3) 26078c2ecf20Sopenharmony_ci return 0; 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + MAC_TCR); 26108c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MAC_TCR_SS_POS, 26118c2ecf20Sopenharmony_ci MAC_TCR_SS_LEN, 0x3); 26128c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + MAC_TCR); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci return 0; 26158c2ecf20Sopenharmony_ci} 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_cistatic void xlgmac_config_mac_speed(struct xlgmac_pdata *pdata) 26188c2ecf20Sopenharmony_ci{ 26198c2ecf20Sopenharmony_ci switch (pdata->phy_speed) { 26208c2ecf20Sopenharmony_ci case SPEED_100000: 26218c2ecf20Sopenharmony_ci xlgmac_set_xlgmii_100000_speed(pdata); 26228c2ecf20Sopenharmony_ci break; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci case SPEED_50000: 26258c2ecf20Sopenharmony_ci xlgmac_set_xlgmii_50000_speed(pdata); 26268c2ecf20Sopenharmony_ci break; 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci case SPEED_40000: 26298c2ecf20Sopenharmony_ci xlgmac_set_xlgmii_40000_speed(pdata); 26308c2ecf20Sopenharmony_ci break; 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci case SPEED_25000: 26338c2ecf20Sopenharmony_ci xlgmac_set_xlgmii_25000_speed(pdata); 26348c2ecf20Sopenharmony_ci break; 26358c2ecf20Sopenharmony_ci } 26368c2ecf20Sopenharmony_ci} 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_cistatic int xlgmac_dev_read(struct xlgmac_channel *channel) 26398c2ecf20Sopenharmony_ci{ 26408c2ecf20Sopenharmony_ci struct xlgmac_pdata *pdata = channel->pdata; 26418c2ecf20Sopenharmony_ci struct xlgmac_ring *ring = channel->rx_ring; 26428c2ecf20Sopenharmony_ci struct net_device *netdev = pdata->netdev; 26438c2ecf20Sopenharmony_ci struct xlgmac_desc_data *desc_data; 26448c2ecf20Sopenharmony_ci struct xlgmac_dma_desc *dma_desc; 26458c2ecf20Sopenharmony_ci struct xlgmac_pkt_info *pkt_info; 26468c2ecf20Sopenharmony_ci unsigned int err, etlt, l34t; 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci desc_data = XLGMAC_GET_DESC_DATA(ring, ring->cur); 26498c2ecf20Sopenharmony_ci dma_desc = desc_data->dma_desc; 26508c2ecf20Sopenharmony_ci pkt_info = &ring->pkt_info; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci /* Check for data availability */ 26538c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 26548c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_OWN_POS, 26558c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_OWN_LEN)) 26568c2ecf20Sopenharmony_ci return 1; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci /* Make sure descriptor fields are read after reading the OWN bit */ 26598c2ecf20Sopenharmony_ci dma_rmb(); 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci if (netif_msg_rx_status(pdata)) 26628c2ecf20Sopenharmony_ci xlgmac_dump_rx_desc(pdata, ring, ring->cur); 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 26658c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_CTXT_POS, 26668c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_CTXT_LEN)) { 26678c2ecf20Sopenharmony_ci /* Timestamp Context Descriptor */ 26688c2ecf20Sopenharmony_ci xlgmac_get_rx_tstamp(pkt_info, dma_desc); 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci pkt_info->attributes = XLGMAC_SET_REG_BITS( 26718c2ecf20Sopenharmony_ci pkt_info->attributes, 26728c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CONTEXT_POS, 26738c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CONTEXT_LEN, 26748c2ecf20Sopenharmony_ci 1); 26758c2ecf20Sopenharmony_ci pkt_info->attributes = XLGMAC_SET_REG_BITS( 26768c2ecf20Sopenharmony_ci pkt_info->attributes, 26778c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_POS, 26788c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_LEN, 26798c2ecf20Sopenharmony_ci 0); 26808c2ecf20Sopenharmony_ci return 0; 26818c2ecf20Sopenharmony_ci } 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci /* Normal Descriptor, be sure Context Descriptor bit is off */ 26848c2ecf20Sopenharmony_ci pkt_info->attributes = XLGMAC_SET_REG_BITS( 26858c2ecf20Sopenharmony_ci pkt_info->attributes, 26868c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CONTEXT_POS, 26878c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CONTEXT_LEN, 26888c2ecf20Sopenharmony_ci 0); 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci /* Indicate if a Context Descriptor is next */ 26918c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 26928c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_CDA_POS, 26938c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_CDA_LEN)) 26948c2ecf20Sopenharmony_ci pkt_info->attributes = XLGMAC_SET_REG_BITS( 26958c2ecf20Sopenharmony_ci pkt_info->attributes, 26968c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_POS, 26978c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_LEN, 26988c2ecf20Sopenharmony_ci 1); 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci /* Get the header length */ 27018c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 27028c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_FD_POS, 27038c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_FD_LEN)) { 27048c2ecf20Sopenharmony_ci desc_data->rx.hdr_len = XLGMAC_GET_REG_BITS_LE(dma_desc->desc2, 27058c2ecf20Sopenharmony_ci RX_NORMAL_DESC2_HL_POS, 27068c2ecf20Sopenharmony_ci RX_NORMAL_DESC2_HL_LEN); 27078c2ecf20Sopenharmony_ci if (desc_data->rx.hdr_len) 27088c2ecf20Sopenharmony_ci pdata->stats.rx_split_header_packets++; 27098c2ecf20Sopenharmony_ci } 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci /* Get the RSS hash */ 27128c2ecf20Sopenharmony_ci if (XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 27138c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_RSV_POS, 27148c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_RSV_LEN)) { 27158c2ecf20Sopenharmony_ci pkt_info->attributes = XLGMAC_SET_REG_BITS( 27168c2ecf20Sopenharmony_ci pkt_info->attributes, 27178c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_RSS_HASH_POS, 27188c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_RSS_HASH_LEN, 27198c2ecf20Sopenharmony_ci 1); 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci pkt_info->rss_hash = le32_to_cpu(dma_desc->desc1); 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci l34t = XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 27248c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_L34T_POS, 27258c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_L34T_LEN); 27268c2ecf20Sopenharmony_ci switch (l34t) { 27278c2ecf20Sopenharmony_ci case RX_DESC3_L34T_IPV4_TCP: 27288c2ecf20Sopenharmony_ci case RX_DESC3_L34T_IPV4_UDP: 27298c2ecf20Sopenharmony_ci case RX_DESC3_L34T_IPV6_TCP: 27308c2ecf20Sopenharmony_ci case RX_DESC3_L34T_IPV6_UDP: 27318c2ecf20Sopenharmony_ci pkt_info->rss_hash_type = PKT_HASH_TYPE_L4; 27328c2ecf20Sopenharmony_ci break; 27338c2ecf20Sopenharmony_ci default: 27348c2ecf20Sopenharmony_ci pkt_info->rss_hash_type = PKT_HASH_TYPE_L3; 27358c2ecf20Sopenharmony_ci } 27368c2ecf20Sopenharmony_ci } 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci /* Get the pkt_info length */ 27398c2ecf20Sopenharmony_ci desc_data->rx.len = XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 27408c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_PL_POS, 27418c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_PL_LEN); 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci if (!XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 27448c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_LD_POS, 27458c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_LD_LEN)) { 27468c2ecf20Sopenharmony_ci /* Not all the data has been transferred for this pkt_info */ 27478c2ecf20Sopenharmony_ci pkt_info->attributes = XLGMAC_SET_REG_BITS( 27488c2ecf20Sopenharmony_ci pkt_info->attributes, 27498c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_INCOMPLETE_POS, 27508c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_INCOMPLETE_LEN, 27518c2ecf20Sopenharmony_ci 1); 27528c2ecf20Sopenharmony_ci return 0; 27538c2ecf20Sopenharmony_ci } 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci /* This is the last of the data for this pkt_info */ 27568c2ecf20Sopenharmony_ci pkt_info->attributes = XLGMAC_SET_REG_BITS( 27578c2ecf20Sopenharmony_ci pkt_info->attributes, 27588c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_INCOMPLETE_POS, 27598c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_INCOMPLETE_LEN, 27608c2ecf20Sopenharmony_ci 0); 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci /* Set checksum done indicator as appropriate */ 27638c2ecf20Sopenharmony_ci if (netdev->features & NETIF_F_RXCSUM) 27648c2ecf20Sopenharmony_ci pkt_info->attributes = XLGMAC_SET_REG_BITS( 27658c2ecf20Sopenharmony_ci pkt_info->attributes, 27668c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CSUM_DONE_POS, 27678c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CSUM_DONE_LEN, 27688c2ecf20Sopenharmony_ci 1); 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci /* Check for errors (only valid in last descriptor) */ 27718c2ecf20Sopenharmony_ci err = XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 27728c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_ES_POS, 27738c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_ES_LEN); 27748c2ecf20Sopenharmony_ci etlt = XLGMAC_GET_REG_BITS_LE(dma_desc->desc3, 27758c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_ETLT_POS, 27768c2ecf20Sopenharmony_ci RX_NORMAL_DESC3_ETLT_LEN); 27778c2ecf20Sopenharmony_ci netif_dbg(pdata, rx_status, netdev, "err=%u, etlt=%#x\n", err, etlt); 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci if (!err || !etlt) { 27808c2ecf20Sopenharmony_ci /* No error if err is 0 or etlt is 0 */ 27818c2ecf20Sopenharmony_ci if ((etlt == 0x09) && 27828c2ecf20Sopenharmony_ci (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) { 27838c2ecf20Sopenharmony_ci pkt_info->attributes = XLGMAC_SET_REG_BITS( 27848c2ecf20Sopenharmony_ci pkt_info->attributes, 27858c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_VLAN_CTAG_POS, 27868c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_VLAN_CTAG_LEN, 27878c2ecf20Sopenharmony_ci 1); 27888c2ecf20Sopenharmony_ci pkt_info->vlan_ctag = 27898c2ecf20Sopenharmony_ci XLGMAC_GET_REG_BITS_LE(dma_desc->desc0, 27908c2ecf20Sopenharmony_ci RX_NORMAL_DESC0_OVT_POS, 27918c2ecf20Sopenharmony_ci RX_NORMAL_DESC0_OVT_LEN); 27928c2ecf20Sopenharmony_ci netif_dbg(pdata, rx_status, netdev, "vlan-ctag=%#06x\n", 27938c2ecf20Sopenharmony_ci pkt_info->vlan_ctag); 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci } else { 27968c2ecf20Sopenharmony_ci if ((etlt == 0x05) || (etlt == 0x06)) 27978c2ecf20Sopenharmony_ci pkt_info->attributes = XLGMAC_SET_REG_BITS( 27988c2ecf20Sopenharmony_ci pkt_info->attributes, 27998c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CSUM_DONE_POS, 28008c2ecf20Sopenharmony_ci RX_PACKET_ATTRIBUTES_CSUM_DONE_LEN, 28018c2ecf20Sopenharmony_ci 0); 28028c2ecf20Sopenharmony_ci else 28038c2ecf20Sopenharmony_ci pkt_info->errors = XLGMAC_SET_REG_BITS( 28048c2ecf20Sopenharmony_ci pkt_info->errors, 28058c2ecf20Sopenharmony_ci RX_PACKET_ERRORS_FRAME_POS, 28068c2ecf20Sopenharmony_ci RX_PACKET_ERRORS_FRAME_LEN, 28078c2ecf20Sopenharmony_ci 1); 28088c2ecf20Sopenharmony_ci } 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci XLGMAC_PR("%s - descriptor=%u (cur=%d)\n", channel->name, 28118c2ecf20Sopenharmony_ci ring->cur & (ring->dma_desc_count - 1), ring->cur); 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci return 0; 28148c2ecf20Sopenharmony_ci} 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_cistatic int xlgmac_enable_int(struct xlgmac_channel *channel, 28178c2ecf20Sopenharmony_ci enum xlgmac_int int_id) 28188c2ecf20Sopenharmony_ci{ 28198c2ecf20Sopenharmony_ci unsigned int dma_ch_ier; 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci dma_ch_ier = readl(XLGMAC_DMA_REG(channel, DMA_CH_IER)); 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci switch (int_id) { 28248c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_TI: 28258c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28268c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_TIE_POS, 28278c2ecf20Sopenharmony_ci DMA_CH_IER_TIE_LEN, 1); 28288c2ecf20Sopenharmony_ci break; 28298c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_TPS: 28308c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28318c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_TXSE_POS, 28328c2ecf20Sopenharmony_ci DMA_CH_IER_TXSE_LEN, 1); 28338c2ecf20Sopenharmony_ci break; 28348c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_TBU: 28358c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28368c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_TBUE_POS, 28378c2ecf20Sopenharmony_ci DMA_CH_IER_TBUE_LEN, 1); 28388c2ecf20Sopenharmony_ci break; 28398c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_RI: 28408c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28418c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_RIE_POS, 28428c2ecf20Sopenharmony_ci DMA_CH_IER_RIE_LEN, 1); 28438c2ecf20Sopenharmony_ci break; 28448c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_RBU: 28458c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28468c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_RBUE_POS, 28478c2ecf20Sopenharmony_ci DMA_CH_IER_RBUE_LEN, 1); 28488c2ecf20Sopenharmony_ci break; 28498c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_RPS: 28508c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28518c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_RSE_POS, 28528c2ecf20Sopenharmony_ci DMA_CH_IER_RSE_LEN, 1); 28538c2ecf20Sopenharmony_ci break; 28548c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_TI_RI: 28558c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28568c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_TIE_POS, 28578c2ecf20Sopenharmony_ci DMA_CH_IER_TIE_LEN, 1); 28588c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28598c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_RIE_POS, 28608c2ecf20Sopenharmony_ci DMA_CH_IER_RIE_LEN, 1); 28618c2ecf20Sopenharmony_ci break; 28628c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_FBE: 28638c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28648c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_FBEE_POS, 28658c2ecf20Sopenharmony_ci DMA_CH_IER_FBEE_LEN, 1); 28668c2ecf20Sopenharmony_ci break; 28678c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_ALL: 28688c2ecf20Sopenharmony_ci dma_ch_ier |= channel->saved_ier; 28698c2ecf20Sopenharmony_ci break; 28708c2ecf20Sopenharmony_ci default: 28718c2ecf20Sopenharmony_ci return -1; 28728c2ecf20Sopenharmony_ci } 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci writel(dma_ch_ier, XLGMAC_DMA_REG(channel, DMA_CH_IER)); 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_ci return 0; 28778c2ecf20Sopenharmony_ci} 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_cistatic int xlgmac_disable_int(struct xlgmac_channel *channel, 28808c2ecf20Sopenharmony_ci enum xlgmac_int int_id) 28818c2ecf20Sopenharmony_ci{ 28828c2ecf20Sopenharmony_ci unsigned int dma_ch_ier; 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_ci dma_ch_ier = readl(XLGMAC_DMA_REG(channel, DMA_CH_IER)); 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci switch (int_id) { 28878c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_TI: 28888c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28898c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_TIE_POS, 28908c2ecf20Sopenharmony_ci DMA_CH_IER_TIE_LEN, 0); 28918c2ecf20Sopenharmony_ci break; 28928c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_TPS: 28938c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28948c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_TXSE_POS, 28958c2ecf20Sopenharmony_ci DMA_CH_IER_TXSE_LEN, 0); 28968c2ecf20Sopenharmony_ci break; 28978c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_TBU: 28988c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 28998c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_TBUE_POS, 29008c2ecf20Sopenharmony_ci DMA_CH_IER_TBUE_LEN, 0); 29018c2ecf20Sopenharmony_ci break; 29028c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_RI: 29038c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 29048c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_RIE_POS, 29058c2ecf20Sopenharmony_ci DMA_CH_IER_RIE_LEN, 0); 29068c2ecf20Sopenharmony_ci break; 29078c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_RBU: 29088c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 29098c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_RBUE_POS, 29108c2ecf20Sopenharmony_ci DMA_CH_IER_RBUE_LEN, 0); 29118c2ecf20Sopenharmony_ci break; 29128c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_RPS: 29138c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 29148c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_RSE_POS, 29158c2ecf20Sopenharmony_ci DMA_CH_IER_RSE_LEN, 0); 29168c2ecf20Sopenharmony_ci break; 29178c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_TI_RI: 29188c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 29198c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_TIE_POS, 29208c2ecf20Sopenharmony_ci DMA_CH_IER_TIE_LEN, 0); 29218c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 29228c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_RIE_POS, 29238c2ecf20Sopenharmony_ci DMA_CH_IER_RIE_LEN, 0); 29248c2ecf20Sopenharmony_ci break; 29258c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_CH_SR_FBE: 29268c2ecf20Sopenharmony_ci dma_ch_ier = XLGMAC_SET_REG_BITS( 29278c2ecf20Sopenharmony_ci dma_ch_ier, DMA_CH_IER_FBEE_POS, 29288c2ecf20Sopenharmony_ci DMA_CH_IER_FBEE_LEN, 0); 29298c2ecf20Sopenharmony_ci break; 29308c2ecf20Sopenharmony_ci case XLGMAC_INT_DMA_ALL: 29318c2ecf20Sopenharmony_ci channel->saved_ier = dma_ch_ier & XLGMAC_DMA_INTERRUPT_MASK; 29328c2ecf20Sopenharmony_ci dma_ch_ier &= ~XLGMAC_DMA_INTERRUPT_MASK; 29338c2ecf20Sopenharmony_ci break; 29348c2ecf20Sopenharmony_ci default: 29358c2ecf20Sopenharmony_ci return -1; 29368c2ecf20Sopenharmony_ci } 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci writel(dma_ch_ier, XLGMAC_DMA_REG(channel, DMA_CH_IER)); 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci return 0; 29418c2ecf20Sopenharmony_ci} 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_cistatic int xlgmac_flush_tx_queues(struct xlgmac_pdata *pdata) 29448c2ecf20Sopenharmony_ci{ 29458c2ecf20Sopenharmony_ci unsigned int i, count; 29468c2ecf20Sopenharmony_ci u32 regval; 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci for (i = 0; i < pdata->tx_q_count; i++) { 29498c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 29508c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_FTQ_POS, 29518c2ecf20Sopenharmony_ci MTL_Q_TQOMR_FTQ_LEN, 1); 29528c2ecf20Sopenharmony_ci writel(regval, XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 29538c2ecf20Sopenharmony_ci } 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci /* Poll Until Poll Condition */ 29568c2ecf20Sopenharmony_ci for (i = 0; i < pdata->tx_q_count; i++) { 29578c2ecf20Sopenharmony_ci count = 2000; 29588c2ecf20Sopenharmony_ci regval = readl(XLGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); 29598c2ecf20Sopenharmony_ci regval = XLGMAC_GET_REG_BITS(regval, MTL_Q_TQOMR_FTQ_POS, 29608c2ecf20Sopenharmony_ci MTL_Q_TQOMR_FTQ_LEN); 29618c2ecf20Sopenharmony_ci while (--count && regval) 29628c2ecf20Sopenharmony_ci usleep_range(500, 600); 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci if (!count) 29658c2ecf20Sopenharmony_ci return -EBUSY; 29668c2ecf20Sopenharmony_ci } 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci return 0; 29698c2ecf20Sopenharmony_ci} 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_cistatic void xlgmac_config_dma_bus(struct xlgmac_pdata *pdata) 29728c2ecf20Sopenharmony_ci{ 29738c2ecf20Sopenharmony_ci u32 regval; 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + DMA_SBMR); 29768c2ecf20Sopenharmony_ci /* Set enhanced addressing mode */ 29778c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_SBMR_EAME_POS, 29788c2ecf20Sopenharmony_ci DMA_SBMR_EAME_LEN, 1); 29798c2ecf20Sopenharmony_ci /* Set the System Bus mode */ 29808c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_SBMR_UNDEF_POS, 29818c2ecf20Sopenharmony_ci DMA_SBMR_UNDEF_LEN, 1); 29828c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_SBMR_BLEN_256_POS, 29838c2ecf20Sopenharmony_ci DMA_SBMR_BLEN_256_LEN, 1); 29848c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + DMA_SBMR); 29858c2ecf20Sopenharmony_ci} 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_cistatic int xlgmac_hw_init(struct xlgmac_pdata *pdata) 29888c2ecf20Sopenharmony_ci{ 29898c2ecf20Sopenharmony_ci struct xlgmac_desc_ops *desc_ops = &pdata->desc_ops; 29908c2ecf20Sopenharmony_ci int ret; 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci /* Flush Tx queues */ 29938c2ecf20Sopenharmony_ci ret = xlgmac_flush_tx_queues(pdata); 29948c2ecf20Sopenharmony_ci if (ret) 29958c2ecf20Sopenharmony_ci return ret; 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci /* Initialize DMA related features */ 29988c2ecf20Sopenharmony_ci xlgmac_config_dma_bus(pdata); 29998c2ecf20Sopenharmony_ci xlgmac_config_osp_mode(pdata); 30008c2ecf20Sopenharmony_ci xlgmac_config_pblx8(pdata); 30018c2ecf20Sopenharmony_ci xlgmac_config_tx_pbl_val(pdata); 30028c2ecf20Sopenharmony_ci xlgmac_config_rx_pbl_val(pdata); 30038c2ecf20Sopenharmony_ci xlgmac_config_rx_coalesce(pdata); 30048c2ecf20Sopenharmony_ci xlgmac_config_tx_coalesce(pdata); 30058c2ecf20Sopenharmony_ci xlgmac_config_rx_buffer_size(pdata); 30068c2ecf20Sopenharmony_ci xlgmac_config_tso_mode(pdata); 30078c2ecf20Sopenharmony_ci xlgmac_config_sph_mode(pdata); 30088c2ecf20Sopenharmony_ci xlgmac_config_rss(pdata); 30098c2ecf20Sopenharmony_ci desc_ops->tx_desc_init(pdata); 30108c2ecf20Sopenharmony_ci desc_ops->rx_desc_init(pdata); 30118c2ecf20Sopenharmony_ci xlgmac_enable_dma_interrupts(pdata); 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci /* Initialize MTL related features */ 30148c2ecf20Sopenharmony_ci xlgmac_config_mtl_mode(pdata); 30158c2ecf20Sopenharmony_ci xlgmac_config_queue_mapping(pdata); 30168c2ecf20Sopenharmony_ci xlgmac_config_tsf_mode(pdata, pdata->tx_sf_mode); 30178c2ecf20Sopenharmony_ci xlgmac_config_rsf_mode(pdata, pdata->rx_sf_mode); 30188c2ecf20Sopenharmony_ci xlgmac_config_tx_threshold(pdata, pdata->tx_threshold); 30198c2ecf20Sopenharmony_ci xlgmac_config_rx_threshold(pdata, pdata->rx_threshold); 30208c2ecf20Sopenharmony_ci xlgmac_config_tx_fifo_size(pdata); 30218c2ecf20Sopenharmony_ci xlgmac_config_rx_fifo_size(pdata); 30228c2ecf20Sopenharmony_ci xlgmac_config_flow_control_threshold(pdata); 30238c2ecf20Sopenharmony_ci xlgmac_config_rx_fep_enable(pdata); 30248c2ecf20Sopenharmony_ci xlgmac_config_rx_fup_enable(pdata); 30258c2ecf20Sopenharmony_ci xlgmac_enable_mtl_interrupts(pdata); 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci /* Initialize MAC related features */ 30288c2ecf20Sopenharmony_ci xlgmac_config_mac_address(pdata); 30298c2ecf20Sopenharmony_ci xlgmac_config_rx_mode(pdata); 30308c2ecf20Sopenharmony_ci xlgmac_config_jumbo_enable(pdata); 30318c2ecf20Sopenharmony_ci xlgmac_config_flow_control(pdata); 30328c2ecf20Sopenharmony_ci xlgmac_config_mac_speed(pdata); 30338c2ecf20Sopenharmony_ci xlgmac_config_checksum_offload(pdata); 30348c2ecf20Sopenharmony_ci xlgmac_config_vlan_support(pdata); 30358c2ecf20Sopenharmony_ci xlgmac_config_mmc(pdata); 30368c2ecf20Sopenharmony_ci xlgmac_enable_mac_interrupts(pdata); 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci return 0; 30398c2ecf20Sopenharmony_ci} 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_cistatic int xlgmac_hw_exit(struct xlgmac_pdata *pdata) 30428c2ecf20Sopenharmony_ci{ 30438c2ecf20Sopenharmony_ci unsigned int count = 2000; 30448c2ecf20Sopenharmony_ci u32 regval; 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci /* Issue a software reset */ 30478c2ecf20Sopenharmony_ci regval = readl(pdata->mac_regs + DMA_MR); 30488c2ecf20Sopenharmony_ci regval = XLGMAC_SET_REG_BITS(regval, DMA_MR_SWR_POS, 30498c2ecf20Sopenharmony_ci DMA_MR_SWR_LEN, 1); 30508c2ecf20Sopenharmony_ci writel(regval, pdata->mac_regs + DMA_MR); 30518c2ecf20Sopenharmony_ci usleep_range(10, 15); 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci /* Poll Until Poll Condition */ 30548c2ecf20Sopenharmony_ci while (--count && 30558c2ecf20Sopenharmony_ci XLGMAC_GET_REG_BITS(readl(pdata->mac_regs + DMA_MR), 30568c2ecf20Sopenharmony_ci DMA_MR_SWR_POS, DMA_MR_SWR_LEN)) 30578c2ecf20Sopenharmony_ci usleep_range(500, 600); 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci if (!count) 30608c2ecf20Sopenharmony_ci return -EBUSY; 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci return 0; 30638c2ecf20Sopenharmony_ci} 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_civoid xlgmac_init_hw_ops(struct xlgmac_hw_ops *hw_ops) 30668c2ecf20Sopenharmony_ci{ 30678c2ecf20Sopenharmony_ci hw_ops->init = xlgmac_hw_init; 30688c2ecf20Sopenharmony_ci hw_ops->exit = xlgmac_hw_exit; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci hw_ops->tx_complete = xlgmac_tx_complete; 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci hw_ops->enable_tx = xlgmac_enable_tx; 30738c2ecf20Sopenharmony_ci hw_ops->disable_tx = xlgmac_disable_tx; 30748c2ecf20Sopenharmony_ci hw_ops->enable_rx = xlgmac_enable_rx; 30758c2ecf20Sopenharmony_ci hw_ops->disable_rx = xlgmac_disable_rx; 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_ci hw_ops->dev_xmit = xlgmac_dev_xmit; 30788c2ecf20Sopenharmony_ci hw_ops->dev_read = xlgmac_dev_read; 30798c2ecf20Sopenharmony_ci hw_ops->enable_int = xlgmac_enable_int; 30808c2ecf20Sopenharmony_ci hw_ops->disable_int = xlgmac_disable_int; 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci hw_ops->set_mac_address = xlgmac_set_mac_address; 30838c2ecf20Sopenharmony_ci hw_ops->config_rx_mode = xlgmac_config_rx_mode; 30848c2ecf20Sopenharmony_ci hw_ops->enable_rx_csum = xlgmac_enable_rx_csum; 30858c2ecf20Sopenharmony_ci hw_ops->disable_rx_csum = xlgmac_disable_rx_csum; 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci /* For MII speed configuration */ 30888c2ecf20Sopenharmony_ci hw_ops->set_xlgmii_25000_speed = xlgmac_set_xlgmii_25000_speed; 30898c2ecf20Sopenharmony_ci hw_ops->set_xlgmii_40000_speed = xlgmac_set_xlgmii_40000_speed; 30908c2ecf20Sopenharmony_ci hw_ops->set_xlgmii_50000_speed = xlgmac_set_xlgmii_50000_speed; 30918c2ecf20Sopenharmony_ci hw_ops->set_xlgmii_100000_speed = xlgmac_set_xlgmii_100000_speed; 30928c2ecf20Sopenharmony_ci 30938c2ecf20Sopenharmony_ci /* For descriptor related operation */ 30948c2ecf20Sopenharmony_ci hw_ops->tx_desc_init = xlgmac_tx_desc_init; 30958c2ecf20Sopenharmony_ci hw_ops->rx_desc_init = xlgmac_rx_desc_init; 30968c2ecf20Sopenharmony_ci hw_ops->tx_desc_reset = xlgmac_tx_desc_reset; 30978c2ecf20Sopenharmony_ci hw_ops->rx_desc_reset = xlgmac_rx_desc_reset; 30988c2ecf20Sopenharmony_ci hw_ops->is_last_desc = xlgmac_is_last_desc; 30998c2ecf20Sopenharmony_ci hw_ops->is_context_desc = xlgmac_is_context_desc; 31008c2ecf20Sopenharmony_ci hw_ops->tx_start_xmit = xlgmac_tx_start_xmit; 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci /* For Flow Control */ 31038c2ecf20Sopenharmony_ci hw_ops->config_tx_flow_control = xlgmac_config_tx_flow_control; 31048c2ecf20Sopenharmony_ci hw_ops->config_rx_flow_control = xlgmac_config_rx_flow_control; 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci /* For Vlan related config */ 31078c2ecf20Sopenharmony_ci hw_ops->enable_rx_vlan_stripping = xlgmac_enable_rx_vlan_stripping; 31088c2ecf20Sopenharmony_ci hw_ops->disable_rx_vlan_stripping = xlgmac_disable_rx_vlan_stripping; 31098c2ecf20Sopenharmony_ci hw_ops->enable_rx_vlan_filtering = xlgmac_enable_rx_vlan_filtering; 31108c2ecf20Sopenharmony_ci hw_ops->disable_rx_vlan_filtering = xlgmac_disable_rx_vlan_filtering; 31118c2ecf20Sopenharmony_ci hw_ops->update_vlan_hash_table = xlgmac_update_vlan_hash_table; 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci /* For RX coalescing */ 31148c2ecf20Sopenharmony_ci hw_ops->config_rx_coalesce = xlgmac_config_rx_coalesce; 31158c2ecf20Sopenharmony_ci hw_ops->config_tx_coalesce = xlgmac_config_tx_coalesce; 31168c2ecf20Sopenharmony_ci hw_ops->usec_to_riwt = xlgmac_usec_to_riwt; 31178c2ecf20Sopenharmony_ci hw_ops->riwt_to_usec = xlgmac_riwt_to_usec; 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci /* For RX and TX threshold config */ 31208c2ecf20Sopenharmony_ci hw_ops->config_rx_threshold = xlgmac_config_rx_threshold; 31218c2ecf20Sopenharmony_ci hw_ops->config_tx_threshold = xlgmac_config_tx_threshold; 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci /* For RX and TX Store and Forward Mode config */ 31248c2ecf20Sopenharmony_ci hw_ops->config_rsf_mode = xlgmac_config_rsf_mode; 31258c2ecf20Sopenharmony_ci hw_ops->config_tsf_mode = xlgmac_config_tsf_mode; 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci /* For TX DMA Operating on Second Frame config */ 31288c2ecf20Sopenharmony_ci hw_ops->config_osp_mode = xlgmac_config_osp_mode; 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci /* For RX and TX PBL config */ 31318c2ecf20Sopenharmony_ci hw_ops->config_rx_pbl_val = xlgmac_config_rx_pbl_val; 31328c2ecf20Sopenharmony_ci hw_ops->get_rx_pbl_val = xlgmac_get_rx_pbl_val; 31338c2ecf20Sopenharmony_ci hw_ops->config_tx_pbl_val = xlgmac_config_tx_pbl_val; 31348c2ecf20Sopenharmony_ci hw_ops->get_tx_pbl_val = xlgmac_get_tx_pbl_val; 31358c2ecf20Sopenharmony_ci hw_ops->config_pblx8 = xlgmac_config_pblx8; 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci /* For MMC statistics support */ 31388c2ecf20Sopenharmony_ci hw_ops->tx_mmc_int = xlgmac_tx_mmc_int; 31398c2ecf20Sopenharmony_ci hw_ops->rx_mmc_int = xlgmac_rx_mmc_int; 31408c2ecf20Sopenharmony_ci hw_ops->read_mmc_stats = xlgmac_read_mmc_stats; 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci /* For Receive Side Scaling */ 31438c2ecf20Sopenharmony_ci hw_ops->enable_rss = xlgmac_enable_rss; 31448c2ecf20Sopenharmony_ci hw_ops->disable_rss = xlgmac_disable_rss; 31458c2ecf20Sopenharmony_ci hw_ops->set_rss_hash_key = xlgmac_set_rss_hash_key; 31468c2ecf20Sopenharmony_ci hw_ops->set_rss_lookup_table = xlgmac_set_rss_lookup_table; 31478c2ecf20Sopenharmony_ci} 3148