// SPDX-License-Identifier: GPL-2.0 /* Copyright(c) 2022 - 2024 Mucse Corporation. */ #include #include #include #include "rnpgbe.h" #include "rnpgbe_phy.h" #include "rnpgbe_mbx.h" #include "rnpgbe_ethtool.h" #include "rnpgbe_sriov.h" #define RNP_N500_PKT_LEN_ERR (2) #define RNP_N500_HDR_LEN_ERR (1) #define RNP_N500_MAX_VF 8 #define RNP_N500_RSS_TBL_NUM 128 #define RNP_N500_RSS_TC_TBL_NUM 8 #define RNP_N500_MAX_TX_QUEUES 8 #define RNP_N500_MAX_RX_QUEUES 8 #define NCSI_RAR_NUM (2) #define NCSI_MC_NUM (5) /* we reseve 2 rar for ncsi */ #define RNP_N500_RAR_ENTRIES (32 - NCSI_RAR_NUM) #define NCSI_RAR_IDX_START (32 - NCSI_RAR_NUM) #define RNP_N500_MC_TBL_SIZE 128 #define RNP_N500_VFT_TBL_SIZE 128 #ifndef RNP_N500_MSIX_VECTORS #define RNP_N500_MSIX_VECTORS 26 #endif #define RNP500_MAX_LAYER2_FILTERS 16 #define RNP500_MAX_TUPLE5_FILTERS 128 enum n500_priv_bits { n500_mac_loopback = 0, n500_padding_enable = 8, }; static const char rnp500_priv_flags_strings[][ETH_GSTRING_LEN] = { #define RNP500_MAC_LOOPBACK BIT(0) #define RNP500_TX_SOLF_PADDING BIT(1) #define RNP500_PADDING_DEBUG BIT(2) #define RNP500_SIMULATE_DOWN BIT(3) #define RNP500_ULTRA_SHORT BIT(4) #define RNP500_DOUBLE_VLAN BIT(5) #define RNP500_PAUSE_OWN BIT(6) #define RNP500_STAGS_ENABLE BIT(7) #define RNP500_JUMBO_ENABLE BIT(8) #define RNP500_TX_PADDING BIT(9) #define RNP500_REC_HDR_LEN_ERR BIT(10) #define RNP500_DOUBLE_VLAN_RECEIVE BIT(11) #define RNP500_RX_SKIP_EN BIT(12) #define RNP500_TCP_SYNC_PRIO BIT(13) #define RNP500_REMAP_PRIO BIT(14) #define RNP500_8023_PRIO BIT(15) #define RNP500_SRIOV_VLAN_MODE BIT(16) #define RNP500_LLDP_EN BIT(17) #define RNP500_FORCE_CLOSE BIT(18) "mac_loopback", "soft_tx_padding_off", "padding_debug", "simulate_link_down", "ultra_short_packet", "double_vlan", "pause_use_own_address", "stags_enable", "jumbo_enable", "mac_tx_padding_off", "mask_len_err", "double_vlan_receive", "rx_skip_en", "tcp_sync_prio", "remap_prio", "8023_prio", "sriov_vlan_mode", "lldp_en", "link_down_on_close", }; #define RNP500_PRIV_FLAGS_STR_LEN ARRAY_SIZE(rnp500_priv_flags_strings) /* setup queue speed limit to max_rate */ static void rnpgbe_dma_set_tx_maxrate_n500(struct rnpgbe_dma_info *dma, u16 queue, u32 max_rate) { } /* setup mac with vf_num to veb table */ static void rnpgbe_dma_set_veb_mac_n500(struct rnpgbe_dma_info *dma, u8 *mac, u32 vfnum, u32 ring) { /* n500 only has 1 port veb table */ u32 maclow, machi, ring_vfnum; int port; maclow = (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5]; machi = (mac[0] << 8) | mac[1]; ring_vfnum = ring | ((0x80 | vfnum) << 8); for (port = 0; port < 1; port++) { dma_wr32(dma, RNP500_DMA_PORT_VBE_MAC_LO_TBL(port, vfnum), maclow); dma_wr32(dma, RNP500_DMA_PORT_VBE_MAC_HI_TBL(port, vfnum), machi); dma_wr32(dma, RNP500_DMA_PORT_VEB_VF_RING_TBL(port, vfnum), ring_vfnum); } } /* setup vlan with vf_num to veb table */ static void rnpgbe_dma_set_veb_vlan_n500(struct rnpgbe_dma_info *dma, u16 vlan, u32 vfnum) { int port; /* each vf can support only one vlan */ for (port = 0; port < 1; port++) dma_wr32(dma, RNP500_DMA_PORT_VEB_VID_TBL(port, vfnum), vlan); } static void rnpgbe_dma_set_veb_vlan_mask_n500(struct rnpgbe_dma_info *dma, u16 vlan, u16 mask, int entry) { /* bit 19:12 is mask bit 11:0 is vid */ dma_wr32(dma, RNP500_DMA_PORT_VEB_VID_TBL(0, entry), (mask << 12) | vlan); } static void rnpgbe_dma_clr_veb_all_n500(struct rnpgbe_dma_info *dma) { int port = 0, i; for (i = 0; i < RNP500_VEB_TBL_CNTS; i++) { dma_wr32(dma, RNP500_DMA_PORT_VBE_MAC_LO_TBL(port, i), 0); dma_wr32(dma, RNP500_DMA_PORT_VBE_MAC_HI_TBL(port, i), 0); dma_wr32(dma, RNP500_DMA_PORT_VEB_VID_TBL(port, i), 0); dma_wr32(dma, RNP500_DMA_PORT_VEB_VF_RING_TBL(port, i), 0); } } static struct rnpgbe_dma_operations dma_ops_n500 = { .set_tx_maxrate = &rnpgbe_dma_set_tx_maxrate_n500, .set_veb_mac = &rnpgbe_dma_set_veb_mac_n500, .set_veb_vlan = &rnpgbe_dma_set_veb_vlan_n500, .set_veb_vlan_mask = &rnpgbe_dma_set_veb_vlan_mask_n500, .clr_veb_all = &rnpgbe_dma_clr_veb_all_n500, }; /** * rnpgbe_eth_set_rar_n500 - Set Rx address register * @eth: pointer to eth structure * @index: Receive address register to write * @addr: Address to put into receive address register * @enable_addr: set flag that address is active * * Puts an ethernet address into a receive address register. **/ static s32 rnpgbe_eth_set_rar_n500(struct rnpgbe_eth_info *eth, u32 index, u8 *addr, bool enable_addr) { u32 mcstctrl; u32 rar_low, rar_high = 0; u32 rar_entries = eth->num_rar_entries; /* Make sure we are using a valid rar index range */ if (index >= rar_entries) { rnpgbe_err("RAR index %d is out of range.\n", index); return RNP_ERR_INVALID_ARGUMENT; } eth_dbg(eth, " RAR[%d] <= %pM. vmdq:%d enable:0x%x\n", index, addr); /* HW expects these in big endian so we reverse the byte * order from network order (big endian) to little endian */ rar_low = ((u32)addr[5] | ((u32)addr[4] << 8) | ((u32)addr[3] << 16) | ((u32)addr[2] << 24)); /* Some parts put the VMDq setting in the extra RAH bits, * so save everything except the lower 16 bits that hold part * of the address and the address valid bit. */ rar_high = eth_rd32(eth, RNP500_ETH_RAR_RH(index)); rar_high &= ~(0x0000FFFF | RNP500_RAH_AV); rar_high |= ((u32)addr[1] | ((u32)addr[0] << 8)); if (enable_addr) rar_high |= RNP500_RAH_AV; eth_wr32(eth, RNP500_ETH_RAR_RL(index), rar_low); eth_wr32(eth, RNP500_ETH_RAR_RH(index), rar_high); /* open unicast filter */ /* we now not use unicast */ /* but we must open this since dest-mac filter | unicast table */ /* all packets up if close unicast table */ mcstctrl = eth_rd32(eth, RNP500_ETH_DMAC_MCSTCTRL); mcstctrl |= RNP500_MCSTCTRL_UNICASE_TBL_EN; eth_wr32(eth, RNP500_ETH_DMAC_MCSTCTRL, mcstctrl); return 0; } /** * rnpgbe_eth_clear_rar_n500 - Remove Rx address register * @eth: pointer to eth structure * @index: Receive address register to write * * Clears an ethernet address from a receive address register. **/ static s32 rnpgbe_eth_clear_rar_n500(struct rnpgbe_eth_info *eth, u32 index) { u32 rar_high; u32 rar_entries = eth->num_rar_entries; /* Make sure we are using a valid rar index range */ if (index >= rar_entries) { eth_dbg(eth, "RAR index %d is out of range.\n", index); return RNP_ERR_INVALID_ARGUMENT; } /* Some parts put the VMDq setting in the extra RAH bits, * so save everything except the lower 16 bits that hold part * of the address and the address valid bit. */ rar_high = eth_rd32(eth, RNP500_ETH_RAR_RH(index)); rar_high &= ~(0x0000FFFF | RNP500_RAH_AV); eth_wr32(eth, RNP500_ETH_RAR_RL(index), 0); eth_wr32(eth, RNP500_ETH_RAR_RH(index), rar_high); /* clear VMDq pool/queue selection for this RAR */ eth->ops.clear_vmdq(eth, index, RNP_CLEAR_VMDQ_ALL); return 0; } /** * rnpgbe_eth_set_vmdq_n500 - Associate a VMDq pool index with a rx address * @eth: pointer to eth struct * @rar: receive address register index to associate with a VMDq index * @vmdq: VMDq pool index * only mac->vf **/ static s32 rnpgbe_eth_set_vmdq_n500(struct rnpgbe_eth_info *eth, u32 rar, u32 vmdq) { u32 rar_entries = eth->num_rar_entries; /* Make sure we are using a valid rar index range */ if (rar >= rar_entries) { eth_dbg(eth, "RAR index %d is out of range.\n", rar); return RNP_ERR_INVALID_ARGUMENT; } eth_wr32(eth, RNP500_VM_DMAC_MPSAR_RING(rar), vmdq); return 0; } /** * rnpgbe_eth_clear_vmdq_n500 - Disassociate a VMDq pool index from a rx address * @eth: pointer to eth struct * @rar: receive address register index to disassociate * @vmdq: VMDq pool index to remove from the rar **/ static s32 rnpgbe_eth_clear_vmdq_n500(struct rnpgbe_eth_info *eth, u32 rar, u32 vmdq) { u32 rar_entries = eth->num_rar_entries; /* Make sure we are using a valid rar index range */ if (rar >= rar_entries) { eth_dbg(eth, "RAR index %d is out of range.\n", rar); return RNP_ERR_INVALID_ARGUMENT; } eth_wr32(eth, RNP500_VM_DMAC_MPSAR_RING(rar), 0); return 0; } static s32 rnp500_mta_vector(struct rnpgbe_eth_info *eth, u8 *mc_addr) { u32 vector = 0; switch (eth->mc_filter_type) { case 0: /* use bits [36:47] of the address */ vector = ((mc_addr[4] << 8) | (((u16)mc_addr[5]))); break; case 1: /* use bits [35:46] of the address */ vector = ((mc_addr[4] << 7) | (((u16)mc_addr[5]) >> 1)); break; case 2: /* use bits [34:45] of the address */ vector = ((mc_addr[4] << 6) | (((u16)mc_addr[5]) >> 2)); break; case 3: /* use bits [32:43] of the address */ vector = ((mc_addr[4] << 5) | (((u16)mc_addr[5]) >> 3)); break; case 4: /* use bits [32:43] of the address */ vector = ((mc_addr[0] << 8) | (((u16)mc_addr[1]))); vector = (vector >> 4); break; case 5: /* use bits [32:43] of the address */ vector = ((mc_addr[0] << 8) | (((u16)mc_addr[1]))); vector = (vector >> 3); break; case 6: /* use bits [32:43] of the address */ vector = ((mc_addr[0] << 8) | (((u16)mc_addr[1]))); vector = (vector >> 2); break; case 7: /* use bits [32:43] of the address */ vector = ((mc_addr[0] << 8) | (((u16)mc_addr[1]))); break; default: /* Invalid mc_filter_type */ hw_dbg(hw, "MC filter type param set incorrectly\n"); break; } /* vector can only be 12-bits or boundary will be exceeded */ vector &= 0xFFF; return vector; } static void rnp500_set_mta(struct rnpgbe_hw *hw, u8 *mc_addr) { u32 vector; u32 vector_bit; u32 vector_reg; struct rnpgbe_eth_info *eth = &hw->eth; hw->addr_ctrl.mta_in_use++; vector = rnp500_mta_vector(eth, mc_addr); /* The MTA is a register array of 128 32-bit registers. It is treated * like an array of 4096 bits. We want to set bit * BitArray[vector_value]. So we figure out what register the bit is * in, read it, OR in the new bit, then write back the new value. The * register is determined by the upper 7 bits of the vector value and * the bit within that register are determined by the lower 5 bits of * the value. */ vector_reg = (vector >> 5) & 0x7F; vector_bit = vector & 0x1F; hw_dbg(hw, "\t\t%pM: MTA-BIT:%4d, MTA_REG[%d][%d] <= 1\n", mc_addr, vector, vector_reg, vector_bit); eth->mta_shadow[vector_reg] |= (1 << vector_bit); } static void rnp500_set_vf_mta(struct rnpgbe_hw *hw, u16 vector) { /* vf/pf use the same multicast table */ u32 vector_bit; u32 vector_reg; struct rnpgbe_eth_info *eth = &hw->eth; hw->addr_ctrl.mta_in_use++; vector_reg = (vector >> 5) & 0x7F; vector_bit = vector & 0x1F; hw_dbg(hw, "\t\t vf M: MTA-BIT:%4d, MTA_REG[%d][%d] <= 1\n", vector, vector_reg, vector_bit); eth->mta_shadow[vector_reg] |= (1 << vector_bit); } static u8 *rnpgbe_addr_list_itr(struct rnpgbe_hw __maybe_unused *hw, u8 **mc_addr_ptr) { struct netdev_hw_addr *mc_ptr; u8 *addr = *mc_addr_ptr; mc_ptr = container_of(addr, struct netdev_hw_addr, addr[0]); if (mc_ptr->list.next) { struct netdev_hw_addr *ha; ha = list_entry(mc_ptr->list.next, struct netdev_hw_addr, list); *mc_addr_ptr = ha->addr; } else { *mc_addr_ptr = NULL; } return addr; } /** * rnpgbe_eth_update_mc_addr_list_n500 - Updates MAC list of multicast addresses * @eth: pointer to hardware structure * @netdev: pointer to net device structure * @sriov_on: sriov status * * The given list replaces any existing list. Clears the MC addrs from receive * address registers and the multicast table. Uses unused receive address * registers for the first multicast addresses, and hashes the rest into the * multicast table. **/ static s32 rnpgbe_eth_update_mc_addr_list_n500(struct rnpgbe_eth_info *eth, struct net_device *netdev, bool sriov_on) { struct rnpgbe_hw *hw = (struct rnpgbe_hw *)eth->back; struct netdev_hw_addr *ha; u32 i; u32 v; int addr_count = 0; u8 *addr_list = NULL; int ret; u8 ncsi_mc_addr[6]; struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)hw->back; /* Set the new number of MC addresses that we are being requested to * use. */ hw->addr_ctrl.num_mc_addrs = netdev_mc_count(netdev); hw->addr_ctrl.mta_in_use = 0; /* Clear mta_shadow */ eth_dbg(eth, " Clearing MTA(multicast table)\n"); memset(ð->mta_shadow, 0, sizeof(eth->mta_shadow)); /* Update mta shadow */ eth_dbg(eth, " Updating MTA..\n"); addr_count = netdev_mc_count(netdev); ha = list_first_entry(&netdev->mc.list, struct netdev_hw_addr, list); addr_list = ha->addr; for (i = 0; i < addr_count; i++) { eth_dbg(eth, " Adding the multicast addresses:\n"); rnp500_set_mta(hw, rnpgbe_addr_list_itr(hw, &addr_list)); } if (!sriov_on) goto skip_sriov; /* sriov mode should set for vf multicast */ for (i = 0; i < adapter->num_vfs; i++) { struct vf_data_storage *vfinfo; int j; if (!adapter->vfinfo) continue; vfinfo = &adapter->vfinfo[i]; for (j = 0; j < vfinfo->num_vf_mc_hashes; j++) rnp500_set_vf_mta(hw, vfinfo->vf_mc_hashes[j]); } skip_sriov: /* update ncsi multicast address */ for (i = NCSI_RAR_NUM; i < NCSI_MC_NUM; i++) { ret = hw->ops.get_ncsi_mac(hw, ncsi_mc_addr, i); if (!ret) rnp500_set_mta(hw, ncsi_mc_addr); } /* Enable mta */ for (i = 0; i < hw->eth.mcft_size; i++) { if (hw->addr_ctrl.mta_in_use) { eth_wr32(eth, RNP500_ETH_MUTICAST_HASH_TABLE(i), eth->mta_shadow[i]); } } if (hw->addr_ctrl.mta_in_use > 0) { v = eth_rd32(eth, RNP500_ETH_DMAC_MCSTCTRL); eth_wr32(eth, RNP500_ETH_DMAC_MCSTCTRL, v | RNP500_MCSTCTRL_MULTICASE_TBL_EN | eth->mc_filter_type); } eth_dbg(eth, " update MTA Done. mta_in_use:%d\n", hw->addr_ctrl.mta_in_use); return hw->addr_ctrl.mta_in_use; } /* clean all mc addr */ static void rnpgbe_eth_clr_mc_addr_n500(struct rnpgbe_eth_info *eth) { int i; for (i = 0; i < eth->mcft_size; i++) eth_wr32(eth, RNP500_ETH_MUTICAST_HASH_TABLE(i), 0); } /** * rnpgbe_eth_set_rss_hfunc_n500 - Remove Rx address register * @eth: pointer to eth structure * @hfunc: hash function type * * update rss key to eth regs **/ static int rnpgbe_eth_set_rss_hfunc_n500(struct rnpgbe_eth_info *eth, int hfunc) { u32 data; data = eth_rd32(eth, RNP500_ETH_RSS_CONTROL); data &= ~(BIT(14) | BIT(15)); if (hfunc == rss_func_top) data |= 0; else if (hfunc == rss_func_xor) data |= BIT(14); else if (hfunc == rss_func_order) data |= BIT(15); else return -EINVAL; /* update to hardware */ eth_wr32(eth, RNP500_ETH_RSS_CONTROL, data); return 0; } /** * rnpgbe_eth_update_rss_key_n500 - Remove Rx address register * @eth: pointer to eth structure * @sriov_flag: sriov status * * update rss key to eth regs **/ static void rnpgbe_eth_update_rss_key_n500(struct rnpgbe_eth_info *eth, bool sriov_flag) { struct rnpgbe_hw *hw = (struct rnpgbe_hw *)eth->back; int i; u8 *key_temp; int key_len = RNP_RSS_KEY_SIZE; u8 *key = hw->rss_key; u32 data; u32 iov_en = (sriov_flag) ? RNP500_IOV_ENABLED : 0; u32 *value; data = eth_rd32(eth, RNP500_ETH_RSS_CONTROL); key_temp = kmalloc(key_len, GFP_KERNEL); /* reoder the key */ for (i = 0; i < key_len; i++) *(key_temp + key_len - i - 1) = *(key + i); value = (u32 *)key_temp; for (i = 0; i < key_len; i = i + 4) eth_wr32(eth, RNP500_ETH_RSS_KEY + i, *(value + i / 4)); kfree(key_temp); data |= (RNP500_ETH_ENABLE_RSS_ONLY | iov_en); eth_wr32(eth, RNP500_ETH_RSS_CONTROL, data); } /** * rnpgbe_eth_update_rss_table_n500 - Remove Rx address register * @eth: pointer to eth structure * * update rss table to eth regs **/ static void rnpgbe_eth_update_rss_table_n500(struct rnpgbe_eth_info *eth) { struct rnpgbe_hw *hw = (struct rnpgbe_hw *)eth->back; u32 reta_entries = hw->rss_indir_tbl_num; u32 tc_entries = hw->rss_tc_tbl_num; int i; for (i = 0; i < tc_entries; i++) eth_wr32(eth, RNP500_ETH_TC_IPH_OFFSET_TABLE(i), hw->rss_tc_tbl[i]); for (i = 0; i < reta_entries; i++) eth_wr32(eth, RNP500_ETH_RSS_INDIR_TBL(i), hw->rss_indir_tbl[i]); /* if we update rss table ,we should update deault ring same with rss[0] */ eth_wr32(eth, RNP500_ETH_DEFAULT_RX_RING, hw->rss_indir_tbl[0]); } /** * rnpgbe_eth_set_vfta_n500 - Set VLAN filter table * @eth: pointer to eth structure * @vlan: VLAN id to write to VLAN filter * @vlan_on: boolean flag to turn on/off VLAN in VFVF * * Turn on/off specified VLAN in the VLAN filter table. **/ static s32 rnpgbe_eth_set_vfta_n500(struct rnpgbe_eth_info *eth, u32 vlan, bool vlan_on) { s32 regindex; u32 bitindex; u32 vfta; u32 targetbit; bool vfta_changed = false; /* todo in vf mode vlvf regester can be set according to vind*/ if (vlan > 4095) return RNP_ERR_PARAM; /* The VFTA is a bitstring made up of 128 32-bit registers * that enable the particular VLAN id, much like the MTA: * bits[11-5]: which register * bits[4-0]: which bit in the register */ regindex = (vlan >> 5) & 0x7F; bitindex = vlan & 0x1F; targetbit = (1 << bitindex); vfta = eth_rd32(eth, RNP500_VFTA(regindex)); if (vlan_on) { if (!(vfta & targetbit)) { vfta |= targetbit; vfta_changed = true; } } else { if ((vfta & targetbit)) { vfta &= ~targetbit; vfta_changed = true; } } if (vfta_changed) eth_wr32(eth, RNP500_VFTA(regindex), vfta); return 0; } static void rnpgbe_eth_clr_vfta_n500(struct rnpgbe_eth_info *eth) { u32 offset; for (offset = 0; offset < eth->vft_size; offset++) eth_wr32(eth, RNP500_VFTA(offset), 0); } static void rnpgbe_eth_set_doulbe_vlan_n500(struct rnpgbe_eth_info *eth, bool on) { if (on) eth_wr32(eth, RNP500_ETH_VLAN_RM_TYPE, 1); else eth_wr32(eth, RNP500_ETH_VLAN_RM_TYPE, 0); } static void rnpgbe_eth_set_outer_vlan_type_n500(struct rnpgbe_eth_info *eth, int type) { u32 data = 0x88a8; switch (type) { case outer_vlan_type_88a8: data = 0x88a8; break; case outer_vlan_type_9100: data = 0x9100; break; case outer_vlan_type_9200: data = 0x9200; break; } eth_wr32(eth, RNP500_ETH_WRAP_FIELD_TYPE, data); eth_wr32(eth, RNP500_ETH_TX_VLAN_TYPE, data); } /** * rnpgbe_eth_set_vlan_filter_n500 - Set VLAN filter table * @eth: pointer to eth structure * @status: on |off * Turn on/off VLAN filter table. **/ static void rnpgbe_eth_set_vlan_filter_n500(struct rnpgbe_eth_info *eth, bool status) { #define ETH_VLAN_FILTER_BIT (30) u32 value = eth_rd32(eth, RNP500_ETH_VLAN_FILTER_ENABLE); /* clear bit first */ value &= (~(0x01 << ETH_VLAN_FILTER_BIT)); if (status) value |= (0x01 << ETH_VLAN_FILTER_BIT); eth_wr32(eth, RNP500_ETH_VLAN_FILTER_ENABLE, value); } static u16 rnpgbe_layer2_pritologic_n500(u16 hw_id) { return hw_id; } static void rnpgbe_eth_set_layer2_n500(struct rnpgbe_eth_info *eth, union rnpgbe_atr_input *input, u16 pri_id, u8 queue, bool prio_flag) { u16 hw_id; hw_id = rnpgbe_layer2_pritologic_n500(pri_id); /* enable layer2 */ eth_wr32(eth, RNP500_ETH_LAYER2_ETQF(hw_id), (0x1 << 31) | (ntohs(input->layer2_formate.proto))); /* setup action */ if (queue == RNP_FDIR_DROP_QUEUE) { eth_wr32(eth, RNP500_ETH_LAYER2_ETQS(hw_id), (0x1 << 31)); } else { /* setup ring_number */ if (prio_flag) { eth_wr32(eth, RNP500_ETH_LAYER2_ETQS(hw_id), (0x1 << 30) | (queue << 20) | (0x1 << 28)); } else { eth_wr32(eth, RNP500_ETH_LAYER2_ETQS(hw_id), (0x1 << 30) | (queue << 20)); } } } static void rnpgbe_eth_clr_layer2_n500(struct rnpgbe_eth_info *eth, u16 pri_id) { u16 hw_id; hw_id = rnpgbe_layer2_pritologic_n500(pri_id); eth_wr32(eth, RNP500_ETH_LAYER2_ETQF(hw_id), 0); } static void rnpgbe_eth_clr_all_layer2_n500(struct rnpgbe_eth_info *eth) { int i; #define RNP500_MAX_LAYER2_FILTERS 16 for (i = 0; i < RNP500_MAX_LAYER2_FILTERS; i++) eth_wr32(eth, RNP500_ETH_LAYER2_ETQF(i), 0); } static u16 rnpgbe_tuple5_pritologic_n500(u16 hw_id) { return hw_id; } static void rnpgbe_eth_set_tuple5_n500(struct rnpgbe_eth_info *eth, union rnpgbe_atr_input *input, u16 pri_id, u8 queue, bool prio_flag) { #define RNP500_SRC_IP_MASK BIT(0) #define RNP500_DST_IP_MASK BIT(1) #define RNP500_SRC_PORT_MASK BIT(2) #define RNP500_DST_PORT_MASK BIT(3) #define RNP500_L4_PROTO_MASK BIT(4) u32 port = 0; u8 mask_temp = 0; u8 l4_proto_type = 0; u16 hw_id; hw_id = rnpgbe_tuple5_pritologic_n500(pri_id); if (input->formatted.src_ip[0] != 0) { eth_wr32(eth, RNP500_ETH_TUPLE5_SAQF(hw_id), htonl(input->formatted.src_ip[0])); } else { mask_temp |= RNP500_SRC_IP_MASK; } if (input->formatted.dst_ip[0] != 0) { eth_wr32(eth, RNP500_ETH_TUPLE5_DAQF(hw_id), htonl(input->formatted.dst_ip[0])); } else { mask_temp |= RNP500_DST_IP_MASK; } if (input->formatted.src_port != 0) port |= (htons(input->formatted.src_port)); else mask_temp |= RNP500_SRC_PORT_MASK; if (input->formatted.dst_port != 0) port |= (htons(input->formatted.dst_port) << 16); else mask_temp |= RNP500_DST_PORT_MASK; if (port != 0) eth_wr32(eth, RNP500_ETH_TUPLE5_SDPQF(hw_id), port); switch (input->formatted.flow_type) { case RNP_ATR_FLOW_TYPE_TCPV4: l4_proto_type = IPPROTO_TCP; break; case RNP_ATR_FLOW_TYPE_UDPV4: l4_proto_type = IPPROTO_UDP; break; case RNP_ATR_FLOW_TYPE_SCTPV4: l4_proto_type = IPPROTO_SCTP; break; case RNP_ATR_FLOW_TYPE_IPV4: l4_proto_type = input->formatted.inner_mac[0]; break; default: l4_proto_type = 0; } if (l4_proto_type == 0) mask_temp |= RNP500_L4_PROTO_MASK; /* setup ftqf */ /* always set 0x3 */ eth_wr32(eth, RNP500_ETH_TUPLE5_FTQF(hw_id), (1 << 31) | (mask_temp << 25) | (l4_proto_type << 16) | 0x3); /* setup action */ if (queue == RNP_FDIR_DROP_QUEUE) { eth_wr32(eth, RNP500_ETH_TUPLE5_POLICY(hw_id), (0x1 << 31)); } else { /* setup ring_number */ if (prio_flag) { eth_wr32(eth, RNP500_ETH_TUPLE5_POLICY(hw_id), ((0x1 << 30) | (queue << 20) | (0x1 << 28))); } else { eth_wr32(eth, RNP500_ETH_TUPLE5_POLICY(hw_id), ((0x1 << 30) | (queue << 20))); } } } static void rnpgbe_eth_clr_tuple5_n500(struct rnpgbe_eth_info *eth, u16 pri_id) { u16 hw_id; hw_id = rnpgbe_tuple5_pritologic_n500(pri_id); eth_wr32(eth, RNP500_ETH_TUPLE5_FTQF(hw_id), 0); } static void rnpgbe_eth_clr_all_tuple5_n500(struct rnpgbe_eth_info *eth) { int i; for (i = 0; i < RNP500_MAX_TUPLE5_FILTERS; i++) eth_wr32(eth, RNP500_ETH_TUPLE5_FTQF(i), 0); } static void rnpgbe_eth_set_tcp_sync_n500(struct rnpgbe_eth_info *eth, int queue, bool flag, bool prio) { if (flag) { eth_wr32(eth, RNP500_ETH_SYNQF, (0x1 << 30) | (queue << 20)); if (prio) eth_wr32(eth, RNP500_ETH_SYNQF_PRIORITY, BIT(31) | 0x1); else eth_wr32(eth, RNP500_ETH_SYNQF_PRIORITY, BIT(31)); } else { eth_wr32(eth, RNP500_ETH_SYNQF, 0); eth_wr32(eth, RNP500_ETH_SYNQF_PRIORITY, 0); } } static void rnpgbe_eth_set_rx_skip_n500(struct rnpgbe_eth_info *eth, int count, bool flag) { if (flag) { eth_wr32(eth, RNP500_ETH_PRIV_DATA_CONTROL_REG, PRIV_DATA_EN | count); } else { eth_wr32(eth, RNP500_ETH_PRIV_DATA_CONTROL_REG, 0); } } static void rnpgbe_eth_set_min_max_packets_n500(struct rnpgbe_eth_info *eth, int min, int max) { eth_wr32(eth, RNP500_ETH_DEFAULT_RX_MIN_LEN, min); eth_wr32(eth, RNP500_ETH_DEFAULT_RX_MAX_LEN, max); } static void rnpgbe_eth_set_vlan_strip_n500(struct rnpgbe_eth_info *eth, u16 queue, bool enable) { u32 reg = RNP500_ETH_VLAN_VME_REG(queue / 32); u32 offset = queue % 32; u32 data = eth_rd32(eth, reg); if (enable) data |= (1 << offset); else data &= ~(1 << offset); eth_wr32(eth, reg, data); } static void rnpgbe_eth_set_rx_hash_n500(struct rnpgbe_eth_info *eth, bool status, bool sriov_flag) { u32 iov_en = (sriov_flag) ? RNP500_IOV_ENABLED : 0; u32 data; data = eth_rd32(eth, RNP500_ETH_RSS_CONTROL); data &= ~RNP500_ETH_RSS_MASK; if (status) { data |= RNP500_ETH_ENABLE_RSS_ONLY; eth_wr32(eth, RNP500_ETH_RSS_CONTROL, data | iov_en); } else { eth_wr32(eth, RNP500_ETH_RSS_CONTROL, data | iov_en); } } static void rnpgbe_eth_set_rx_n500(struct rnpgbe_eth_info *eth, bool status) { if (status) { eth_wr32(eth, RNP500_ETH_EXCEPT_DROP_PROC, 0); eth_wr32(eth, RNP500_ETH_TX_MUX_DROP, 0); } else { eth_wr32(eth, RNP500_ETH_EXCEPT_DROP_PROC, 1); eth_wr32(eth, RNP500_ETH_TX_MUX_DROP, 1); } } static void rnpgbe_eth_fcs_n500(struct rnpgbe_eth_info *eth, bool status) { if (status) eth_wr32(eth, RNP500_ETH_FCS_EN, 1); else eth_wr32(eth, RNP500_ETH_FCS_EN, 0); } static void rnpgbe_eth_set_vf_vlan_mode_n500(struct rnpgbe_eth_info *eth, u16 vlan, int vf, bool enable) { u32 value = vlan; if (enable) value |= BIT(31); eth_wr32(eth, RNP500_VLVF(vf), value); /* n500 1 vf only can setup 1 vlan */ eth_wr32(eth, RNP500_VLVF_TABLE(vf), vf); } static s32 rnpgbe_eth_set_fc_mode_n500(struct rnpgbe_eth_info *eth) { struct rnpgbe_hw *hw = (struct rnpgbe_hw *)eth->back; s32 ret_val = 0; int i = 0; /* n500 has only 1 traffic class */ if ((hw->fc.current_mode & rnpgbe_fc_tx_pause) && hw->fc.high_water[i]) { if (!hw->fc.low_water[i] || hw->fc.low_water[i] >= hw->fc.high_water[i]) { hw_dbg(hw, "Invalid water mark configuration\n"); ret_val = RNP_ERR_INVALID_LINK_SETTINGS; goto out; } } if ((hw->fc.current_mode & rnpgbe_fc_tx_pause)) { if (hw->fc.high_water[i]) { eth_wr32(eth, RNP500_ETH_HIGH_WATER(i), hw->fc.high_water[i]); } if (hw->fc.low_water[i]) { eth_wr32(eth, RNP500_ETH_LOW_WATER(i), hw->fc.low_water[i]); } } out: return ret_val; } static struct rnpgbe_eth_operations eth_ops_n500 = { .set_rar = &rnpgbe_eth_set_rar_n500, .clear_rar = &rnpgbe_eth_clear_rar_n500, .set_vmdq = &rnpgbe_eth_set_vmdq_n500, .clear_vmdq = &rnpgbe_eth_clear_vmdq_n500, .update_mc_addr_list = &rnpgbe_eth_update_mc_addr_list_n500, .clr_mc_addr = &rnpgbe_eth_clr_mc_addr_n500, .set_rss_hfunc = &rnpgbe_eth_set_rss_hfunc_n500, .set_rss_key = &rnpgbe_eth_update_rss_key_n500, .set_rss_table = &rnpgbe_eth_update_rss_table_n500, .set_rx_hash = &rnpgbe_eth_set_rx_hash_n500, .set_layer2_remapping = &rnpgbe_eth_set_layer2_n500, .clr_layer2_remapping = &rnpgbe_eth_clr_layer2_n500, .clr_all_layer2_remapping = &rnpgbe_eth_clr_all_layer2_n500, .set_tuple5_remapping = &rnpgbe_eth_set_tuple5_n500, .clr_tuple5_remapping = &rnpgbe_eth_clr_tuple5_n500, .clr_all_tuple5_remapping = &rnpgbe_eth_clr_all_tuple5_n500, .set_tcp_sync_remapping = &rnpgbe_eth_set_tcp_sync_n500, .set_rx_skip = &rnpgbe_eth_set_rx_skip_n500, .set_min_max_packet = &rnpgbe_eth_set_min_max_packets_n500, .set_vlan_strip = &rnpgbe_eth_set_vlan_strip_n500, .set_vfta = &rnpgbe_eth_set_vfta_n500, .clr_vfta = &rnpgbe_eth_clr_vfta_n500, .set_vlan_filter = &rnpgbe_eth_set_vlan_filter_n500, .set_outer_vlan_type = &rnpgbe_eth_set_outer_vlan_type_n500, .set_double_vlan = &rnpgbe_eth_set_doulbe_vlan_n500, .set_fc_mode = &rnpgbe_eth_set_fc_mode_n500, .set_rx = &rnpgbe_eth_set_rx_n500, .set_fcs = &rnpgbe_eth_fcs_n500, .set_vf_vlan_mode = &rnpgbe_eth_set_vf_vlan_mode_n500, }; /** * rnpgbe_init_hw_ops_n500 - Generic hardware initialization * @hw: pointer to hardware structure * * Initialize the hardware by resetting the hardware, filling the bus info * structure and media type, clears all on chip counters, initializes receive * address registers, multicast table, VLAN filter table, calls routine to set * up link and flow control settings, and leaves transmit and receive units * disabled and uninitialized **/ static s32 rnpgbe_init_hw_ops_n500(struct rnpgbe_hw *hw) { s32 status = 0; /* Reset the hardware */ status = hw->ops.reset_hw(hw); /* Start the HW */ if (status == 0) status = hw->ops.start_hw(hw); return status; } static s32 rnpgbe_get_permtion_mac_addr_n500(struct rnpgbe_hw *hw, u8 *mac_addr) { if (rnpgbe_fw_get_macaddr(hw, hw->pfvfnum, mac_addr, hw->nr_lane)) eth_random_addr(mac_addr); /* should check valid mac */ if (!is_valid_ether_addr(mac_addr)) eth_random_addr(mac_addr); hw->mac.mac_flags |= RNP_FLAGS_INIT_MAC_ADDRESS; return 0; } static s32 rnpgbe_reset_hw_ops_n500(struct rnpgbe_hw *hw) { int i; struct rnpgbe_dma_info *dma = &hw->dma; struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_mac_info *mac = &hw->mac; /* Call adapter stop to disable tx/rx and clear interrupts */ dma_wr32(dma, RNP_DMA_AXI_EN, 0); rnpgbe_mbx_fw_reset_phy(hw); /* tcam not reset */ eth->ops.clr_all_tuple5_remapping(eth); /* Store the permanent mac address */ if (!(hw->mac.mac_flags & RNP_FLAGS_INIT_MAC_ADDRESS)) { rnpgbe_get_permtion_mac_addr_n500(hw, hw->mac.perm_addr); memcpy(hw->mac.addr, hw->mac.perm_addr, ETH_ALEN); } hw->ops.init_rx_addrs(hw); /* n500 should do this */ eth_wr32(eth, RNP500_ETH_ERR_MASK_VECTOR, RNP_N500_PKT_LEN_ERR | RNP_N500_HDR_LEN_ERR); wr32(hw, RNP_DMA_RX_DATA_PROG_FULL_THRESH, 0xa); /* reset all ring msix table to 0 */ for (i = 0; i < 12; i++) rnpgbe_wr_reg(hw->ring_msix_base + RING_VECTOR(i), 0); { u32 value = 0; value |= RNP_MODE_NO_SA_INSER << RNP_SARC_OFFSET; value &= (~RNP_TWOKPE_MASK); value &= (~RNP_SFTERR_MASK); value |= (RNP_CST_MASK); value |= RNP_TC_MASK; value &= (~RNP_WD_MASK); value &= (~RNP_JD_MASK); value &= (~RNP_BE_MASK); value |= (RNP_JE_MASK); value |= (RNP_IFG_96 << RNP_IFG_OFFSET); value &= (~RNP_DCRS_MASK); value &= (~RNP_PS_MASK); value &= (~RNP_FES_MASK); value &= (~RNP_DO_MASK); value &= (~RNP_LM_MASK); value |= RNP_DM_MASK; value |= RNP_IPC_MASK; /* open rx checksum */ value &= (~RNP_DR_MASK); value &= (~RNP_LUD_MASK); value |= (RNP_BL_MODE << RNP_BL_OFFSET); value &= (~RNP_DC_MASK); value |= RNP_TE_MASK; value |= (RNP_PRELEN_MODE); /* not setup this if in ncsi mode */ if (!hw->ncsi_en) mac_wr32(mac, GMAC_CONTROL, value); } /* if ncsi on, sync hw status */ if (hw->ncsi_en) rnpgbe_mbx_phy_pause_get(hw, &hw->fc.requested_mode); else rnpgbe_mbx_phy_pause_set(hw, hw->fc.requested_mode); rnpgbe_mbx_get_lane_stat(hw); return 0; } static s32 rnpgbe_start_hw_ops_n500(struct rnpgbe_hw *hw) { s32 ret_val = 0; struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_dma_info *dma = &hw->dma; /* ETH Registers */ eth_wr32(eth, RNP500_ETH_ERR_MASK_VECTOR, RNP_N500_PKT_LEN_ERR | RNP_N500_HDR_LEN_ERR); eth_wr32(eth, RNP500_ETH_BYPASS, 0); eth_wr32(eth, RNP500_ETH_DEFAULT_RX_RING, 0); /* DMA common Registers */ dma_wr32(dma, RNP_DMA_CONFIG, DMA_VEB_BYPASS); /* enable-dma-axi */ dma_wr32(dma, RNP_DMA_AXI_EN, (RX_AXI_RW_EN | TX_AXI_RW_EN)); { int value = dma_rd32(dma, RNP_DMA_DUMY); value |= RC_CONTROL_HW; dma_wr32(dma, RNP_DMA_DUMY, value); } return ret_val; } /* set n500 min/max packet according to new_mtu * we support mtu + 14 + 4 * 3 as max packet LENGTH_ERROR */ static void rnpgbe_set_mtu_hw_ops_n500(struct rnpgbe_hw *hw, int new_mtu) { struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)hw->back; int min; int max = new_mtu + ETH_HLEN + ETH_FCS_LEN * 2; #define ULTRA_SHORT 33 #define DEFAULT_SHORT 60 if ((adapter->priv_flags & RNP_PRIV_FLAG_ULTRA_SHORT) || (adapter->priv_flags & RNP_PRIV_FLAG_RX_ALL)) min = ULTRA_SHORT; else min = DEFAULT_SHORT; /* we receive jumbo fram only in jumbo enable or rx all mode */ if ((adapter->priv_flags & RNP_PRIV_FLAG_JUMBO) || (adapter->priv_flags & RNP_PRIV_FLAG_RX_ALL)) max = hw->max_length; hw->min_length_current = min; hw->max_length_current = max; eth->ops.set_min_max_packet(eth, min, max); } /* setup n500 vlan filter status */ static void rnpgbe_set_vlan_filter_en_hw_ops_n500(struct rnpgbe_hw *hw, bool status) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.set_vlan_filter(eth, status); } /* set vlan to n500 vlan filter table & veb */ /* pf setup call */ static void rnpgbe_set_vlan_filter_hw_ops_n500(struct rnpgbe_hw *hw, u16 vid, bool enable, bool sriov_flag) { struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_dma_info *dma = &hw->dma; u16 ncsi_vid; int i; int ret; /* use the last vfnum */ u32 vfnum = hw->max_vfs - 1; /* setup n500 eth vlan table */ eth->ops.set_vfta(eth, vid, enable); /* setup veb */ if (sriov_flag) { if (hw->feature_flags & RNP_VEB_VLAN_MASK_EN) { /* we update veb int other location */ } else { if (enable) dma->ops.set_veb_vlan(dma, vid, vfnum); else dma->ops.set_veb_vlan(dma, 0, vfnum); } } /* always setup nsci vid */ for (i = 0; i < 2; i++) { ret = hw->ops.get_ncsi_vlan(hw, &ncsi_vid, i); if (!ret) eth->ops.set_vfta(eth, ncsi_vid, 1); } } static int rnpgbe_set_veb_vlan_mask_hw_ops_n500(struct rnpgbe_hw *hw, u16 vid, int vf, bool enable) { struct list_head *pos; struct vf_vebvlans *entry; struct rnpgbe_dma_info *dma = &hw->dma; bool find = false; int err = 0; /* 1 try to find is this vid is in vlan mask table */ list_for_each(pos, &hw->vf_vas.l) { entry = list_entry(pos, struct vf_vebvlans, l); if (entry->vid == vid) { find = true; break; } } if (find) { /* this vid is used before */ if (enable) { entry->mask |= (1 << vf); } else { entry->mask &= (~(1 << vf)); /* if mask is zero free this */ if (!entry) { entry->vid = -1; entry->free = true; } } } else { /* it is a new vid */ /* 2 try to get new entries */ list_for_each(pos, &hw->vf_vas.l) { entry = list_entry(pos, struct vf_vebvlans, l); if (entry->free) { find = true; break; } } if (find) { /* use this entry */ entry->free = false; entry->vid = vid; entry->mask |= (1 << vf); } else { err = -1; goto err_out; } } /* 3 update new vlan mask to hw */ dma->ops.set_veb_vlan_mask(dma, entry->vid, entry->mask, entry->veb_entry); err_out: return err; } static void rnpgbe_set_vf_vlan_filter_hw_ops_n500(struct rnpgbe_hw *hw, u16 vid, int vf, bool enable, bool veb_only) { struct rnpgbe_dma_info *dma = &hw->dma; if (!veb_only) { // call set vfta without veb setup hw->ops.set_vlan_filter(hw, vid, enable, false); } else { if (enable) dma->ops.set_veb_vlan(dma, vid, vf); else dma->ops.set_veb_vlan(dma, 0, vf); } } static void rnpgbe_clr_vlan_veb_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_dma_info *dma = &hw->dma; u32 vfnum = hw->vfnum; dma->ops.set_veb_vlan(dma, 0, vfnum); } /* setup n500 vlan strip status */ static void rnpgbe_set_vlan_strip_hw_ops_n500(struct rnpgbe_hw *hw, u16 queue, bool strip) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.set_vlan_strip(eth, queue, strip); } /* update new n500 mac */ static void rnpgbe_set_mac_hw_ops_n500(struct rnpgbe_hw *hw, u8 *mac, bool sriov_flag) { struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_dma_info *dma = &hw->dma; struct rnpgbe_mac_info *mac_info = &hw->mac; /* use this queue index to setup veb */ /* vfnum is the last vfnum */ int queue = hw->veb_ring; int vfnum = hw->vfnum; eth->ops.set_rar(eth, 0, mac, true); if (sriov_flag) { eth->ops.set_vmdq(eth, 0, queue / hw->sriov_ring_limit); dma->ops.set_veb_mac(dma, mac, vfnum, queue); } /* update pasue mac */ mac_info->ops.set_mac(mac_info, mac, 0); } /** * rnpgbe_write_uc_addr_list_n500 - write unicast addresses to RAR table * @hw: hardware structure * @netdev: network interface device structure * @sriov_flag: sriov on or not * * Writes unicast address list to the RAR table. * Returns: -ENOMEM on failure/insufficient address space * 0 on no addresses written * X on writing X addresses to the RAR table **/ static int rnpgbe_write_uc_addr_list_n500(struct rnpgbe_hw *hw, struct net_device *netdev, bool sriov_flag) { unsigned int rar_entries = hw->num_rar_entries - 1; u32 vfnum = hw->vfnum; struct rnpgbe_eth_info *eth = &hw->eth; int count = 0; int i = 0; u8 ncsi_addr[6]; int ret; /* In SR-IOV mode significantly less RAR entries are available */ if (sriov_flag) rar_entries = hw->max_pf_macvlans - 1; /* return ENOMEM indicating insufficient memory for addresses */ if (netdev_uc_count(netdev) > rar_entries) return -ENOMEM; if (!netdev_uc_empty(netdev)) { struct netdev_hw_addr *ha; hw_dbg(hw, "%s: rar_entries:%d, uc_count:%d\n", __func__, hw->num_rar_entries, netdev_uc_count(netdev)); /* return error if we do not support writing to RAR table */ if (!eth->ops.set_rar) return -ENOMEM; netdev_for_each_uc_addr(ha, netdev) { if (!rar_entries) break; eth->ops.set_rar(eth, rar_entries, ha->addr, RNP500_RAH_AV); if (sriov_flag) eth->ops.set_vmdq(eth, rar_entries, vfnum); rar_entries--; count++; } } /* should update ncsi rar address */ for (i = 0; i < NCSI_RAR_NUM; i++) { ret = hw->ops.get_ncsi_mac(hw, ncsi_addr, i); if (!ret) { eth->ops.set_rar(eth, NCSI_RAR_IDX_START + i, ncsi_addr, RNP500_RAH_AV); } } /* write the addresses in reverse order to avoid write combining */ hw_dbg(hw, "%s: Clearing RAR[1 - %d]\n", __func__, rar_entries); for (; rar_entries > 0; rar_entries--) eth->ops.clear_rar(eth, rar_entries); return count; } static void rnpgbe_set_rx_mode_hw_ops_n500(struct rnpgbe_hw *hw, struct net_device *netdev, bool sriov_flag) { struct rnpgbe_adapter *adapter = netdev_priv(netdev); u32 fctrl; netdev_features_t features = netdev->features; int count; struct rnpgbe_eth_info *eth = &hw->eth; /* broadcast always bypass */ fctrl = eth_rd32(eth, RNP500_ETH_DMAC_FCTRL) | RNP500_FCTRL_BPE; /* clear the bits we are changing the status of */ fctrl &= ~(RNP500_FCTRL_UPE | RNP500_FCTRL_MPE); /* promisc mode */ if (netdev->flags & IFF_PROMISC) { hw->addr_ctrl.user_set_promisc = true; fctrl |= (RNP500_FCTRL_UPE | RNP500_FCTRL_MPE); /* disable hardware filter vlans in promisc mode */ features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; features &= ~NETIF_F_HW_VLAN_CTAG_RX; } else { if (netdev->flags & IFF_ALLMULTI) { fctrl |= RNP500_FCTRL_MPE; } else { /* Write addresses to the MTA, if the attempt fails * then we should just turn on promiscuous mode so * that we can at least receive multicast traffic */ /* we always update vf multicast info */ count = eth->ops.update_mc_addr_list(eth, netdev, true); if (count < 0) fctrl |= RNP500_FCTRL_MPE; } hw->addr_ctrl.user_set_promisc = false; } /* Write addresses to available RAR registers, if there is not * sufficient space to store all the addresses then enable * unicast promiscuous mode */ if (rnpgbe_write_uc_addr_list_n500(hw, netdev, sriov_flag) < 0) fctrl |= RNP500_FCTRL_UPE; eth_wr32(eth, RNP500_ETH_DMAC_FCTRL, fctrl); if (features & NETIF_F_HW_VLAN_CTAG_FILTER) eth->ops.set_vlan_filter(eth, true); else eth->ops.set_vlan_filter(eth, false); if (hw->addr_ctrl.user_set_promisc || adapter->priv_flags & RNP_PRIV_FLAG_REC_HDR_LEN_ERR) { /* set pkt_len_err and hdr_len_err default to 1 */ eth_wr32(eth, RNP500_ETH_ERR_MASK_VECTOR, PKT_LEN_ERR | HDR_LEN_ERR); } else { eth_wr32(eth, RNP500_ETH_ERR_MASK_VECTOR, 0); } /* update mtu */ hw->ops.set_mtu(hw, netdev->mtu); } /* setup an rar with vfnum */ static void rnpgbe_set_rar_with_vf_hw_ops_n500(struct rnpgbe_hw *hw, u8 *mac, int idx, u32 vfnum, bool enable) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.set_rar(eth, idx, mac, enable); /* should check error or not ?*/ eth->ops.set_vmdq(eth, idx, vfnum); } static void rnpgbe_clr_rar_hw_ops_n500(struct rnpgbe_hw *hw, int idx) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.clear_rar(eth, idx); } static void rnpgbe_clr_rar_all_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_eth_info *eth = &hw->eth; unsigned int rar_entries = hw->num_rar_entries - 1; int i; for (i = 0; i < rar_entries; i++) eth->ops.clear_rar(eth, rar_entries); } static void rnpgbe_set_fcs_mode_hw_ops_n500(struct rnpgbe_hw *hw, bool status) { struct rnpgbe_mac_info *mac = &hw->mac; struct rnpgbe_eth_info *eth = &hw->eth; mac->ops.set_mac_fcs(mac, status); eth->ops.set_fcs(eth, status); } static void rnpgbe_set_mac_rx_hw_ops_n500(struct rnpgbe_hw *hw, bool status) { struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_mac_info *mac = &hw->mac; if (status) { mac->ops.set_mac_rx(mac, status); eth->ops.set_rx(eth, status); } else { eth->ops.set_rx(eth, status); mac->ops.set_mac_rx(mac, status); } } static void rnpgbe_set_sriov_status_hw_ops_n500(struct rnpgbe_hw *hw, bool status) { struct rnpgbe_dma_info *dma = &hw->dma; struct rnpgbe_eth_info *eth = &hw->eth; u32 v, fctrl; fctrl = eth_rd32(eth, RNP500_ETH_DMAC_FCTRL); #define RNP500_DMAC_MASK (0x7f) fctrl &= ~RNP500_DMAC_MASK; if (status) { fctrl |= hw->veb_ring; eth_wr32(eth, RNP500_ETH_DMAC_FCTRL, fctrl); /* setup default ring */ dma_wr32(dma, RNP_DMA_CONFIG, dma_rd32(dma, RNP_DMA_CONFIG) & (~DMA_VEB_BYPASS)); v = eth_rd32(eth, RNP500_MRQC_IOV_EN); v |= RNP500_IOV_ENABLED; eth_wr32(eth, RNP500_MRQC_IOV_EN, v); } else { eth_wr32(eth, RNP500_ETH_DMAC_FCTRL, fctrl); v = eth_rd32(eth, RNP500_MRQC_IOV_EN); v &= ~(RNP500_IOV_ENABLED); eth_wr32(eth, RNP500_MRQC_IOV_EN, v); dma->ops.clr_veb_all(dma); } } static void rnpgbe_set_sriov_vf_mc_hw_ops_n500(struct rnpgbe_hw *hw, u16 mc_addr) { struct rnpgbe_eth_info *eth = &hw->eth; u32 vector_bit; u32 vector_reg; u32 mta_reg; /* pf/ vf share one mc table */ vector_reg = (mc_addr >> 5) & 0x7F; vector_bit = mc_addr & 0x1F; mta_reg = eth_rd32(eth, RNP500_ETH_MUTICAST_HASH_TABLE(vector_reg)); mta_reg |= (1 << vector_bit); eth_wr32(eth, RNP500_ETH_MUTICAST_HASH_TABLE(vector_reg), mta_reg); } static void rnpgbe_update_sriov_info_hw_ops_n500(struct rnpgbe_hw *hw) { /* update sriov info to hw */ } static void rnpgbe_set_pause_mode_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_mac_info *mac = &hw->mac; struct rnpgbe_eth_info *eth = &hw->eth; mac->ops.set_fc_mode(mac); eth->ops.set_fc_mode(eth); } static void rnpgbe_get_pause_mode_hw_ops_n500(struct rnpgbe_hw *hw) { // n500 can get pause mode in link event } static void rnpgbe_update_hw_info_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_dma_info *dma = &hw->dma; struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_mac_info *mac = &hw->mac; struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)hw->back; u32 data; /* 1 enable eth filter */ eth_wr32(eth, RNP500_HOST_FILTER_EN, 1); /* 2 open redir en */ eth_wr32(eth, RNP500_REDIR_EN, 1); /* 3 open sctp checksum and other checksum */ if (hw->feature_flags & RNP_NET_FEATURE_TX_CHECKSUM) eth_wr32(eth, RNP500_ETH_SCTP_CHECKSUM_EN, 1); /* 4 mark muticaset as broadcast */ dma_wr32(dma, RNP_VEB_MAC_MASK_LO, 0xffffffff); dma_wr32(dma, RNP_VEB_MAC_MASK_HI, 0xfeff); /* 5 setup ft padding and veb vlan mode */ data = dma_rd32(dma, RNP_DMA_CONFIG); /* force close padding in n500 */ CLR_BIT(8, data); #define N500_VLAN_POLL_EN BIT(3) if (hw->feature_flags & RNP_VEB_VLAN_MASK_EN) data |= N500_VLAN_POLL_EN; dma_wr32(dma, RNP_DMA_CONFIG, data); /* 6 setup vlan mode */ if (adapter->priv_flags & RNP_PRIV_FLAG_DOUBLE_VLAN) eth->ops.set_double_vlan(eth, true); else eth->ops.set_double_vlan(eth, false); /* 7 setup rss-hash mode */ eth->ops.set_rss_hfunc(eth, adapter->rss_func_mode); /* 8 setup outer-vlan type */ eth->ops.set_outer_vlan_type(eth, adapter->outer_vlan_type); /* 9 setup tcp sync remapping */ if (adapter->priv_flags & RNP_PRIV_FLAG_TCP_SYNC) { if (adapter->priv_flags & RNP_PRIV_FLAG_TCP_SYNC_PRIO) hw->ops.set_tcp_sync_remapping(hw, adapter->tcp_sync_queue, true, true); else hw->ops.set_tcp_sync_remapping(hw, adapter->tcp_sync_queue, true, false); } else { hw->ops.set_tcp_sync_remapping(hw, adapter->tcp_sync_queue, false, false); } /* 10 setup pause status */ data = mac_rd32(mac, GMAC_FLOW_CTRL); if (adapter->priv_flags & RNP_PRIV_FLAG_PAUSE_OWN) data |= GMAC_FLOW_CTRL_UP; else data &= (~GMAC_FLOW_CTRL_UP); mac_wr32(mac, GMAC_FLOW_CTRL, data); /* 11 open tx double vlan according to stags */ eth_wr32(eth, RNP500_ETH_TX_VLAN_CONTROL_EANBLE, 1); /* 12 test */ eth_wr32(eth, RNP500_ETH_WHOLE_PKT_LEN_ERR_DROP, 1); /* 13 setup double vlan drop */ if (adapter->priv_flags & RNP_PRIV_FLAG_DOUBLE_VLAN_RECEIVE) eth_wr32(eth, RNP500_ETH_DOUBLE_VLAN_DROP, 0); else eth_wr32(eth, RNP500_ETH_DOUBLE_VLAN_DROP, 1); /* 14 open error mask if in rx all mode */ if (adapter->priv_flags & RNP_PRIV_FLAG_RX_ALL) { eth_wr32(eth, RNP500_MAC_ERR_MASK, RUN_FRAME_ERROR | GAINT_FRAME_ERROR | CRC_ERROR | LENGTH_ERROR); eth_wr32(eth, RNP500_ETH_DOUBLE_VLAN_DROP, 0); #define FORWARD_ALL_CONTROL (0x2) mac_wr32(mac, GMAC_FRAME_FILTER, 0x00000001 | (FORWARD_ALL_CONTROL << 6)); } else { eth_wr32(eth, RNP500_MAC_ERR_MASK, RUN_FRAME_ERROR | GAINT_FRAME_ERROR); mac_wr32(mac, GMAC_FRAME_FILTER, 0x00000001); } /* 15 update water acoording to max length */ { #define FIFO_ALL (1024) int water_high = FIFO_ALL - ((hw->max_length_current + 15) >> 4); /* n500 only use one */ hw->fc.high_water[0] = water_high; hw->fc.low_water[0] = water_high; dma_wr32(dma, RNP500_DMA_RBUF_FIFO, ((hw->max_length_current + 15) >> 4) + 5); eth_wr32(eth, RNP500_ETH_EMAC_PARSE_PROGFULL_THRESH, ((hw->max_length_current + 15) >> 4) + 2); } /* 16 setup fcs mode */ if (adapter->priv_flags & RNP_PRIV_FLAG_RX_FCS) hw->ops.set_fcs_mode(hw, true); else hw->ops.set_fcs_mode(hw, false); /* 17 setup tso fifo */ dma_wr32(dma, RNP_DMA_PKT_FIFO_DATA_PROG_FULL_THRESH, 36); /* 18 setup priv skip */ if (adapter->priv_flags & RNP_PRIV_FLAG_RX_SKIP_EN) data = PRIV_DATA_EN | adapter->priv_skip_count; else data = 0; eth_wr32(eth, RNP500_ETH_PRIV_DATA_CONTROL_REG, data); /* 19 setup mac count read self clear */ data = mac_rd32(mac, RNP500_MAC_COUNT_CONTROL); #define READ_CLEAR BIT(2) data |= READ_CLEAR; mac_wr32(mac, RNP500_MAC_COUNT_CONTROL, data); /* 20 setup prio */ if (adapter->priv_flags & (RNP_PRIV_FLAG_8023_PRIO | RNP_PRIV_FLAG_REMAP_PRIO)) { eth_wr32(eth, RNP500_PRIORITY_1_MARK, RNP500_PRIORITY_1); eth_wr32(eth, RNP500_PRIORITY_0_MARK, RNP500_PRIORITY_0); eth_wr32(eth, RNP500_PRIORITY_EN, 1); if (adapter->priv_flags & RNP_PRIV_FLAG_8023_PRIO) eth_wr32(eth, RNP500_PRIORITY_EN_8023, 1); else eth_wr32(eth, RNP500_PRIORITY_EN_8023, 0); } else { eth_wr32(eth, RNP500_PRIORITY_EN, 0); } } static void rnpgbe_update_hw_rx_drop_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)hw->back; int i; struct rnpgbe_ring *ring; for (i = 0; i < adapter->num_rx_queues; i++) { ring = adapter->rx_ring[i]; if (adapter->rx_drop_status & BIT(i)) { ring_wr32(ring, PCI_DMA_REG_RX_DESC_TIMEOUT_TH, adapter->drop_time); } else { ring_wr32(ring, PCI_DMA_REG_RX_DESC_TIMEOUT_TH, 0); } } } static void rnpgbe_set_rx_hash_hw_ops_n500(struct rnpgbe_hw *hw, bool status, bool sriov_flag) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.set_rx_hash(eth, status, sriov_flag); } static s32 rnpgbe_init_rx_addrs_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_eth_info *eth = &hw->eth; u32 i; u32 rar_entries = eth->num_rar_entries; u32 v; hw_dbg(hw, "init_rx_addrs:rar_entries:%d, mac.addr:%pM\n", rar_entries, hw->mac.addr); /* If the current mac address is valid, assume it is a software override * to the permanent address. * Otherwise, use the permanent address from the eeprom. */ if (!is_valid_ether_addr(hw->mac.addr)) { /* Get the MAC address from the RAR0 for later reference */ memcpy(hw->mac.addr, hw->mac.perm_addr, ETH_ALEN); hw_dbg(hw, " Keeping Current RAR0 Addr =%pM\n", hw->mac.addr); } else { /* Setup the receive address. */ hw_dbg(hw, "Overriding MAC Address in RAR[0]\n"); hw_dbg(hw, " New MAC Addr =%pM\n", hw->mac.addr); eth->ops.set_rar(eth, 0, hw->mac.addr, true); /* clear VMDq pool/queue selection for RAR 0 */ eth->ops.clear_vmdq(eth, 0, RNP_CLEAR_VMDQ_ALL); } hw->addr_ctrl.overflow_promisc = 0; hw->addr_ctrl.rar_used_count = 1; /* Zero out the other receive addresses. */ hw_dbg(hw, "Clearing RAR[1-%d]\n", rar_entries - 1); /* if not enable ncsi clean it */ if (!hw->ncsi_en) { for (i = 1; i < rar_entries; i++) eth->ops.clear_rar(eth, i); } /* Clear the MTA */ hw->addr_ctrl.mta_in_use = 0; v = eth_rd32(eth, RNP500_ETH_DMAC_MCSTCTRL); v &= (~0x3); v |= eth->mc_filter_type; eth_wr32(eth, RNP500_ETH_DMAC_MCSTCTRL, v); hw_dbg(hw, " Clearing MTA\n"); if (!hw->ncsi_en) eth->ops.clr_mc_addr(eth); return 0; } /* clean vlan filter tables */ static void rnpgbe_clr_vfta_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.clr_vfta(eth); } static void rnpgbe_set_txvlan_mode_hw_ops_n500(struct rnpgbe_hw *hw, bool cvlan) { } static int rnpgbe_set_rss_hfunc_hw_ops_n500(struct rnpgbe_hw *hw, u8 hfunc) { struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)hw->back; switch (hfunc) { case ETH_RSS_HASH_TOP: adapter->rss_func_mode = rss_func_top; break; case ETH_RSS_HASH_XOR: adapter->rss_func_mode = rss_func_xor; break; default: return -EINVAL; } eth->ops.set_rss_hfunc(eth, adapter->rss_func_mode); return 0; } static void rnpgbe_set_rss_key_hw_ops_n500(struct rnpgbe_hw *hw, bool sriov_flag) { struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)hw->back; int key_len = RNP_RSS_KEY_SIZE; memcpy(hw->rss_key, adapter->rss_key, key_len); eth->ops.set_rss_key(eth, sriov_flag); } static void rnpgbe_set_rss_table_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.set_rss_table(eth); } static void rnpgbe_set_mbx_link_event_hw_ops_n500(struct rnpgbe_hw *hw, int enable) { rnpgbe_mbx_link_event_enable(hw, enable); } static void rnpgbe_set_mbx_ifup_hw_ops_n500(struct rnpgbe_hw *hw, int enable) { rnpgbe_mbx_ifup_down(hw, enable); } /** * rnpgbe_check_mac_link_hw_ops_n500 - Determine link and speed status * @hw: pointer to hardware structure * @speed: pointer to link speed * @link_up: true when link is up * @duplex: full or half * @link_up_wait_to_complete: bool used to wait for link up or not * * Reads the links register to determine if link is up and the current speed **/ static s32 rnpgbe_check_mac_link_hw_ops_n500(struct rnpgbe_hw *hw, rnpgbe_link_speed *speed, bool *link_up, bool *duplex, bool link_up_wait_to_complete) { struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)hw->back; if (hw->speed == 10) *speed = RNP_LINK_SPEED_10_FULL; else if (hw->speed == 100) *speed = RNP_LINK_SPEED_100_FULL; else if (hw->speed == 1000) *speed = RNP_LINK_SPEED_1GB_FULL; else if (hw->speed == 10000) *speed = RNP_LINK_SPEED_10GB_FULL; else if (hw->speed == 25000) *speed = RNP_LINK_SPEED_25GB_FULL; else if (hw->speed == 40000) *speed = RNP_LINK_SPEED_40GB_FULL; else *speed = RNP_LINK_SPEED_UNKNOWN; *link_up = hw->link; if (adapter->priv_flags & RNP_PRIV_FLGA_TEST_TX_HANG) *link_up = 0; *duplex = hw->duplex; return 0; } static s32 rnpgbe_setup_mac_link_hw_ops_n500(struct rnpgbe_hw *hw, u32 adv, u32 autoneg, u32 speed, u32 duplex) { rnpgbe_mbx_phy_link_set(hw, adv, autoneg, speed, duplex, hw->tp_mdix_ctrl); return 0; } static void rnpgbe_clean_link_hw_ops_n500(struct rnpgbe_hw *hw) { hw->link = 0; } static void rnpgbe_set_layer2_hw_ops_n500(struct rnpgbe_hw *hw, union rnpgbe_atr_input *input, u16 pri_id, u8 queue, bool prio_flag) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.set_layer2_remapping(eth, input, pri_id, queue, prio_flag); } static void rnpgbe_clr_layer2_hw_ops_n500(struct rnpgbe_hw *hw, u16 pri_id) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.clr_layer2_remapping(eth, pri_id); } static void rnpgbe_clr_all_layer2_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.clr_all_layer2_remapping(eth); } static void rnpgbe_clr_all_tuple5_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.clr_all_tuple5_remapping(eth); } static void rnpgbe_set_tcp_sync_hw_ops_n500(struct rnpgbe_hw *hw, int queue, bool flag, bool prio) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.set_tcp_sync_remapping(eth, queue, flag, prio); } static void rnpgbe_set_rx_skip_hw_ops_n500(struct rnpgbe_hw *hw, int count, bool flag) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.set_rx_skip(eth, count, flag); } static void rnpgbe_set_outer_vlan_type_hw_ops_n500(struct rnpgbe_hw *hw, int type) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.set_outer_vlan_type(eth, type); } static s32 rnpgbe_phy_read_reg_hw_ops_n500(struct rnpgbe_hw *hw, u32 reg_addr, u32 device_type, u16 *phy_data) { struct rnpgbe_mac_info *mac = &hw->mac; s32 status = 0; u32 data = 0; status = mac->ops.mdio_read(mac, reg_addr, &data); *phy_data = data & 0xffff; return status; } static s32 rnpgbe_phy_write_reg_hw_ops_n500(struct rnpgbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data) { struct rnpgbe_mac_info *mac = &hw->mac; s32 status = 0; status = mac->ops.mdio_write(mac, reg_addr, (u32)phy_data); return status; } static void rnpgbe_setup_wol_hw_ops_n500(struct rnpgbe_hw *hw, u32 mode) { struct rnpgbe_mac_info *mac = &hw->mac; mac->ops.pmt(mac, mode, !!hw->ncsi_en); } static void rnpgbe_setup_eee_hw_ops_n500(struct rnpgbe_hw *hw, int ls, int tw, u32 local_eee) { struct rnpgbe_mac_info *mac = &hw->mac; /* update eee timer to mac */ mac->ops.set_eee_timer(mac, ls, tw); /* update local eee to firmware */ rnpgbe_mbx_phy_eee_set(hw, tw, local_eee); } static void rnpgbe_set_eee_mode_hw_ops_n500(struct rnpgbe_hw *hw, bool en_tx_lpi_clockgating) { struct rnpgbe_mac_info *mac = &hw->mac; mac->ops.set_eee_mode(mac, en_tx_lpi_clockgating); } static void rnpgbe_reset_eee_mode_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_mac_info *mac = &hw->mac; mac->ops.reset_eee_mode(mac); } static void rnpgbe_set_eee_pls_hw_ops_n500(struct rnpgbe_hw *hw, int link) { struct rnpgbe_mac_info *mac = &hw->mac; mac->ops.set_eee_pls(mac, link); } static u32 rnpgbe_get_lpi_status_hw_ops_n500(struct rnpgbe_hw *hw) { struct rnpgbe_mac_info *mac = &hw->mac; return mac->ops.get_lpi_status(mac); } static int rnpgbe_get_ncsi_mac_hw_ops_n500(struct rnpgbe_hw *hw, u8 *addr, int idx) { #define NCSI_MAC_H(i) (0x48 + (i) * 0x8) #define NCSI_MAC_L(i) (0x4C + (i) * 0x8) struct rnpgbe_mac_info *mac = &hw->mac; u32 rar_h, rar_l; rar_h = mac_rd32(mac, NCSI_MAC_H(idx)); rar_l = mac_rd32(mac, NCSI_MAC_L(idx)); if ((rar_h & 0x0000ffff) != 0x0000ffff || rar_l != 0xffffffff) { *(addr + 3) = (rar_l & 0xff000000) >> 24; *(addr + 2) = (rar_l & 0xff0000) >> 16; *(addr + 1) = (rar_l & 0xff00) >> 8; *(addr + 0) = (rar_l & 0xff) >> 0; *(addr + 5) = (rar_h & 0xff00) >> 8; *(addr + 4) = (rar_h & 0xff) >> 0; return 0; } else { return -1; } } static int rnpgbe_get_ncsi_vlan_hw_ops_n500(struct rnpgbe_hw *hw, u16 *vlan, int idx) { #define NCSI_VLAN(i) (0x80 + (i) * 0x10) struct rnpgbe_mac_info *mac = &hw->mac; u32 vid; vid = mac_rd32(mac, NCSI_VLAN(idx)); if (vid & 0x80000000) { *vlan = (u16)(vid & 0x0000ffff); return 0; } else { return -1; } } static void rnpgbe_set_lldp_hw_ops_n500(struct rnpgbe_hw *hw, bool enable) { rnpgbe_mbx_lldp_set(hw, enable); } static void rnpgbe_get_lldp_hw_ops_n500(struct rnpgbe_hw *hw) { } static void rnpgbe_set_eee_timer_hw_ops_n500(struct rnpgbe_hw *hw, int ls, int tw) { struct rnpgbe_mac_info *mac = &hw->mac; mac->ops.set_eee_timer(mac, ls, tw); } static void rnpgbe_set_vf_vlan_mode_hw_ops_n500(struct rnpgbe_hw *hw, u16 vlan, int vf, bool enable) { struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)hw->back; if (adapter->priv_flags & RNP_PRIV_FLAG_SRIOV_VLAN_MODE) eth->ops.set_vf_vlan_mode(eth, vlan, vf, enable); } static void rnpgbe_driver_status_hw_ops_n500(struct rnpgbe_hw *hw, bool enable, int mode) { switch (mode) { case rnpgbe_driver_insmod: rnpgbe_mbx_ifinsmod(hw, enable); break; case rnpgbe_driver_suspuse: rnpgbe_mbx_ifsuspuse(hw, enable); break; case rnpgbe_driver_force_control_mac: rnpgbe_mbx_ifforce_control_mac(hw, enable); break; } } static void rnpgbe_set_tuple5_hw_ops_n500(struct rnpgbe_hw *hw, union rnpgbe_atr_input *input, u16 pri_id, u8 queue, bool prio_flag) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.set_tuple5_remapping(eth, input, pri_id, queue, prio_flag); } static void rnpgbe_clr_tuple5_hw_ops_n500(struct rnpgbe_hw *hw, u16 pri_id) { struct rnpgbe_eth_info *eth = &hw->eth; eth->ops.clr_tuple5_remapping(eth, pri_id); } static void rnpgbe_update_hw_status_hw_ops_n500(struct rnpgbe_hw *hw, struct rnpgbe_hw_stats *hw_stats, struct net_device_stats *net_stats) { struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)hw->back; struct rnpgbe_dma_info *dma = &hw->dma; struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_mac_info *mac = &hw->mac; int i; net_stats->rx_errors += eth_rd32(eth, RNP500_RX_MAC_GFCS_ERR_NUM) + eth_rd32(eth, RNP500_RX_MAC_LEN_ERR_NUM) + eth_rd32(eth, RNP500_RX_MAC_SFCS_ERR_NUM) + eth_rd32(eth, RNP500_RX_MAC_GLEN_ERR_NUM) + eth_rd32(eth, RNP500_RX_MAC_SLEN_ERR_NUM); net_stats->collisions = eth_rd32(eth, RNP500_RX_MAC_LCS_ERR_NUM); net_stats->rx_over_errors = eth_rd32(eth, RNP500_RX_MAC_CUT_NUM); net_stats->rx_crc_errors = eth_rd32(eth, RNP500_RX_MAC_GFCS_ERR_NUM); hw_stats->invalid_droped_packets = eth_rd32(eth, RNP500_RX_DROP_PKT_NUM); hw_stats->rx_capabity_lost = eth_rd32(eth, RNP500_RXTRANS_DROP) + eth_rd32(eth, RNP500_RXTRANS_CUT_ERR_PKTS); hw_stats->filter_dropped_packets = eth_rd32(eth, RNP500_DECAP_PKT_DROP1_NUM); hw_stats->host_l2_match_drop = eth_rd32(eth, RNP500_ETH_HOST_L2_DROP_PKTS); hw_stats->redir_input_match_drop = eth_rd32(eth, RNP500_ETH_REDIR_INPUT_MATCH_DROP_PKTS); hw_stats->redir_etype_match_drop = eth_rd32(eth, RNP500_ETH_ETYPE_DROP_PKTS); hw_stats->redir_tcp_syn_match_drop = eth_rd32(eth, RNP500_ETH_TCP_SYN_DROP_PKTS); hw_stats->redir_tuple5_match_drop = eth_rd32(eth, RNP500_ETH_REDIR_TUPLE5_DROP_PKTS); hw_stats->tx_multicast = eth_rd32(eth, RNP500_TX_MULTI_NUM); hw_stats->tx_broadcast = eth_rd32(eth, RNP500_TX_BROADCAST_NUM); hw_stats->mac_rx_broadcast = 0; hw_stats->mac_rx_multicast = 0; for (i = 0; i < adapter->num_tx_queues; i++) { struct rnpgbe_ring *tx_ring = adapter->tx_ring[i]; int idx = tx_ring->rnpgbe_queue_idx; /* we should use the true idex */ hw_stats->mac_rx_multicast += dma_rd32(dma, RNP500_VEB_VFMPRC(idx)); hw_stats->mac_rx_broadcast += dma_rd32(dma, RNP500_VEB_VFBPRC(idx)); } hw_stats->dma_rx_drop_cnt_0 = dma_rd32(dma, RNP500_RX_TIMEOUT_DROP(0)); hw_stats->dma_rx_drop_cnt_1 = dma_rd32(dma, RNP500_RX_TIMEOUT_DROP(1)); hw_stats->dma_rx_drop_cnt_2 = dma_rd32(dma, RNP500_RX_TIMEOUT_DROP(2)); hw_stats->dma_rx_drop_cnt_3 = dma_rd32(dma, RNP500_RX_TIMEOUT_DROP(3)); hw_stats->dma_rx_drop_cnt_4 = dma_rd32(dma, RNP500_RX_TIMEOUT_DROP(4)); hw_stats->dma_rx_drop_cnt_5 = dma_rd32(dma, RNP500_RX_TIMEOUT_DROP(5)); hw_stats->dma_rx_drop_cnt_6 = dma_rd32(dma, RNP500_RX_TIMEOUT_DROP(6)); hw_stats->dma_rx_drop_cnt_7 = dma_rd32(dma, RNP500_RX_TIMEOUT_DROP(7)); net_stats->multicast = hw_stats->mac_rx_multicast; hw_stats->ultra_short_cnt += mac_rd32(mac, GMAC_MANAGEMENT_RX_UNDERSIZE); hw_stats->jumbo_cnt += mac_rd32(mac, RNP500_MAC_GLEN_ERR_NUM); } const struct rnpgbe_stats rnp500_gstrings_net_stats[] = { RNP_NETDEV_STAT(rx_packets), RNP_NETDEV_STAT(tx_packets), RNP_NETDEV_STAT(rx_bytes), RNP_NETDEV_STAT(tx_bytes), RNP_NETDEV_STAT(rx_errors), RNP_NETDEV_STAT(tx_errors), RNP_NETDEV_STAT(rx_dropped), RNP_NETDEV_STAT(tx_dropped), RNP_NETDEV_STAT(multicast), RNP_NETDEV_STAT(collisions), RNP_NETDEV_STAT(rx_over_errors), RNP_NETDEV_STAT(rx_crc_errors), RNP_NETDEV_STAT(rx_frame_errors), RNP_NETDEV_STAT(rx_fifo_errors), RNP_NETDEV_STAT(rx_missed_errors), RNP_NETDEV_STAT(tx_aborted_errors), RNP_NETDEV_STAT(tx_carrier_errors), RNP_NETDEV_STAT(tx_fifo_errors), RNP_NETDEV_STAT(tx_heartbeat_errors), }; #define RNP500_GLOBAL_STATS_LEN ARRAY_SIZE(rnp500_gstrings_net_stats) static struct rnpgbe_stats rnp500_hwstrings_stats[] = { RNP_HW_STAT("vlan_add_cnt", hw_stats.vlan_add_cnt), RNP_HW_STAT("vlan_strip_cnt", hw_stats.vlan_strip_cnt), /* === drop== */ RNP_HW_STAT("invalid_droped_packets", hw_stats.invalid_droped_packets), RNP_HW_STAT("rx_capabity_drop", hw_stats.rx_capabity_lost), RNP_HW_STAT("filter_dropped_packets", hw_stats.filter_dropped_packets), RNP_HW_STAT("host_l2_match_drop", hw_stats.host_l2_match_drop), RNP_HW_STAT("redir_input_match_drop", hw_stats.redir_input_match_drop), RNP_HW_STAT("redir_etype_match_drop", hw_stats.redir_etype_match_drop), RNP_HW_STAT("redir_tcp_syn_match_drop", hw_stats.redir_tcp_syn_match_drop), RNP_HW_STAT("redir_tuple5_match_drop", hw_stats.redir_tuple5_match_drop), RNP_HW_STAT("tx_multicast", hw_stats.tx_multicast), RNP_HW_STAT("tx_broadcast", hw_stats.tx_broadcast), RNP_HW_STAT("rx_csum_offload_errors", hw_csum_rx_error), RNP_HW_STAT("rx_csum_offload_good", hw_csum_rx_good), RNP_HW_STAT("rx_broadcast_count", hw_stats.mac_rx_broadcast), RNP_HW_STAT("rx_multicast_count", hw_stats.mac_rx_multicast), RNP_HW_STAT("ultra_short_packets", hw_stats.ultra_short_cnt), RNP_HW_STAT("jumbo_packets", hw_stats.jumbo_cnt), }; #define RNP500_HWSTRINGS_STATS_LEN ARRAY_SIZE(rnp500_hwstrings_stats) #define RNP500_STATS_LEN \ (RNP500_GLOBAL_STATS_LEN + RNP500_HWSTRINGS_STATS_LEN + \ RNP_QUEUE_STATS_LEN) static const char rnp500_gstrings_test[][ETH_GSTRING_LEN] = { "Register test (offline)", "Eeprom test (offline)", "Interrupt test (offline)", "Loopback test (offline)", "Link test (on/offline)" }; #define RNP500_TEST_LEN (sizeof(rnp500_gstrings_test) / ETH_GSTRING_LEN) static int rnp500_get_link_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd) { struct rnpgbe_adapter *adapter = netdev_priv(netdev); struct rnpgbe_hw *hw = &adapter->hw; rnpgbe_link_speed supported_link; rnpgbe_link_speed advertised_link; bool autoneg = hw->autoneg; ethtool_link_ksettings_zero_link_mode(cmd, supported); ethtool_link_ksettings_zero_link_mode(cmd, advertising); supported_link = hw->supported_link; advertised_link = hw->advertised_link; if (hw->is_sgmii) { if (supported_link & RNP_LINK_SPEED_1GB_FULL) ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Full); if (supported_link & RNP_LINK_SPEED_100_FULL) ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Full); if (supported_link & RNP_LINK_SPEED_10_FULL) ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Full); if (supported_link & RNP_LINK_SPEED_1GB_HALF) ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Half); if (supported_link & RNP_LINK_SPEED_100_HALF) ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Half); if (supported_link & RNP_LINK_SPEED_10_HALF) ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half); if (autoneg) { if (advertised_link & RNP_LINK_SPEED_1GB_FULL) ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full); if (advertised_link & RNP_LINK_SPEED_100_FULL) ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full); if (advertised_link & RNP_LINK_SPEED_10_FULL) ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full); if (advertised_link & RNP_LINK_SPEED_1GB_HALF) ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Half); if (advertised_link & RNP_LINK_SPEED_100_HALF) ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half); if (advertised_link & RNP_LINK_SPEED_10_HALF) ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half); } ethtool_link_ksettings_add_link_mode(cmd, supported, TP); ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); cmd->base.port = PORT_TP; cmd->base.phy_address = adapter->phy_addr; cmd->base.duplex = adapter->duplex; if (adapter->hw.link) cmd->base.eth_tp_mdix = hw->tp_mdx; else cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID; cmd->base.eth_tp_mdix_ctrl = hw->tp_mdix_ctrl; } else { if (supported_link & RNP_LINK_SPEED_1GB_FULL) { ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Full); } if (advertised_link & RNP_LINK_SPEED_1GB_FULL) ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full); ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); cmd->base.port = PORT_FIBRE; } ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); if (autoneg) { ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); cmd->base.autoneg = AUTONEG_ENABLE; } else { cmd->base.autoneg = AUTONEG_DISABLE; } ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause); if (hw->fc.requested_mode & PAUSE_AUTO) { ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); } else { if ((hw->fc.requested_mode & PAUSE_TX) && (hw->fc.requested_mode & PAUSE_RX)) ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); else if (hw->fc.requested_mode & PAUSE_TX) ethtool_link_ksettings_add_link_mode(cmd, advertising, Asym_Pause); else if (hw->fc.requested_mode & PAUSE_RX) ethtool_link_ksettings_add_link_mode(cmd, advertising, Asym_Pause); else ethtool_link_ksettings_add_link_mode(cmd, advertising, Asym_Pause); } if (adapter->hw.link) { cmd->base.speed = hw->speed; if (adapter->hw.duplex) cmd->base.duplex = DUPLEX_FULL; else cmd->base.duplex = DUPLEX_HALF; } else { cmd->base.speed = SPEED_UNKNOWN; cmd->base.duplex = DUPLEX_UNKNOWN; } return 0; } static int rnp500_set_link_ksettings(struct net_device *netdev, const struct ethtool_link_ksettings *cmd) { struct rnpgbe_adapter *adapter = netdev_priv(netdev); struct rnpgbe_hw *hw = &adapter->hw; u32 advertised, old; s32 err = 0; u32 speed = 0, autoneg = 0, duplex = 0; if (hw->phy_type == rnpgbe_media_type_copper || hw->phy.multispeed_fiber) { /* this function does not support duplex forcing, but can * limit the advertising of the adapter to the specified speed */ /* only allow one speed at a time if no */ if (!cmd->base.autoneg) { if (cmd->base.speed == SPEED_1000) return -EINVAL; /* maybe user set other speed than 100 or 10 */ if (cmd->base.speed != SPEED_100 && cmd->base.speed != SPEED_10) return -EINVAL; autoneg = 0; speed = cmd->base.speed; duplex = cmd->base.duplex; } else { autoneg = 1; } if (cmd->base.eth_tp_mdix_ctrl) { if (cmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_AUTO && cmd->base.autoneg != AUTONEG_ENABLE) { dev_err(&adapter->pdev->dev, "forcing MDI/MDI-X state is not supported when link speed and/or duplex are forced\n"); return -EINVAL; } } hw->autoneg = autoneg; hw->tp_mdix_ctrl = cmd->base.eth_tp_mdix_ctrl; old = hw->advertised_link; advertised = 0; if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 1000baseT_Full)) advertised |= RNP_LINK_SPEED_1GB_FULL; if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 100baseT_Full)) advertised |= RNP_LINK_SPEED_100_FULL; if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 10baseT_Full)) advertised |= RNP_LINK_SPEED_10_FULL; if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 100baseT_Half)) advertised |= RNP_LINK_SPEED_100_HALF; if (ethtool_link_ksettings_test_link_mode(cmd, advertising, 10baseT_Half)) advertised |= RNP_LINK_SPEED_10_HALF; /* if autoneg on, adv can not set 0 */ if (!advertised && (autoneg)) return -EINVAL; /* this sets the link speed and restarts auto-neg */ while (test_and_set_bit(__RNP_IN_SFP_INIT, &adapter->state)) usleep_range(1000, 2000); hw->mac.autotry_restart = true; err = hw->ops.setup_link(hw, advertised, autoneg, speed, duplex); if (err) { e_info(probe, "setup link failed with code %d\n", err); hw->ops.setup_link(hw, old, autoneg, speed, duplex); } else { hw->advertised_link = advertised; } clear_bit(__RNP_IN_SFP_INIT, &adapter->state); } else { if (cmd->base.duplex == DUPLEX_HALF) return -EINVAL; } return err; } static int rnp500_get_regs_len(struct net_device *netdev) { #define RNP500_REGS_LEN 1 return RNP500_REGS_LEN * sizeof(u32); } static void rnp500_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { struct rnpgbe_adapter *adapter = netdev_priv(netdev); struct rnpgbe_hw *hw = &adapter->hw; strscpy(drvinfo->driver, rnpgbe_driver_name, sizeof(drvinfo->driver)); strscpy(drvinfo->version, rnpgbe_driver_version, sizeof(drvinfo->version)); snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d.%d.%d 0x%08x", ((char *)&hw->fw_version)[3], ((char *)&hw->fw_version)[2], ((char *)&hw->fw_version)[1], ((char *)&hw->fw_version)[0], hw->bd_uid | (hw->sfc_boot ? 0x80000000 : 0) | (hw->pxe_en ? 0x40000000 : 0) | (hw->ncsi_en ? 0x20000000 : 0)); strscpy(drvinfo->bus_info, pci_name(adapter->pdev), sizeof(drvinfo->bus_info)); drvinfo->n_stats = RNP500_STATS_LEN; drvinfo->testinfo_len = RNP500_TEST_LEN; drvinfo->regdump_len = rnp500_get_regs_len(netdev); drvinfo->n_priv_flags = RNP500_PRIV_FLAGS_STR_LEN; } static int rnp500_get_eeprom_len(struct net_device *netdev) { return 0; } static int rnp500_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, u8 *bytes) { struct rnpgbe_adapter *adapter = netdev_priv(netdev); struct rnpgbe_hw *hw = &adapter->hw; u32 *eeprom_buff; int first_u32, last_u32, eeprom_len; int ret_val = 0; if (hw->hw_type == rnpgbe_hw_n210) return -EPERM; if (eeprom->len == 0) return -EINVAL; eeprom->magic = hw->vendor_id | (hw->device_id << 16); /* assign to u32 */ first_u32 = eeprom->offset >> 2; last_u32 = (eeprom->offset + eeprom->len - 1) >> 2; eeprom_len = last_u32 - first_u32 + 1; eeprom_buff = kmalloc_array(eeprom_len, sizeof(u32), GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 0x03), eeprom->len); kfree(eeprom_buff); return ret_val; return 0; } static int rnp500_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, u8 *bytes) { return 0; } static void rnp500_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct rnpgbe_adapter *adapter = netdev_priv(netdev); struct rnpgbe_hw *hw = &adapter->hw; if (hw->fc.requested_mode & PAUSE_AUTO) pause->autoneg = 1; else pause->autoneg = 0; if (hw->fc.current_mode == rnpgbe_fc_rx_pause) { pause->rx_pause = 1; } else if (hw->fc.current_mode == rnpgbe_fc_tx_pause) { pause->tx_pause = 1; } else if (hw->fc.current_mode == rnpgbe_fc_full) { pause->rx_pause = 1; pause->tx_pause = 1; } else { pause->rx_pause = 0; pause->tx_pause = 0; } } static int rnp500_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct rnpgbe_adapter *adapter = netdev_priv(netdev); struct rnpgbe_hw *hw = &adapter->hw; struct rnpgbe_fc_info fc = hw->fc; /* we not support change in dcb mode */ if (adapter->flags & RNP_FLAG_DCB_ENABLED) return -EINVAL; fc.disable_fc_autoneg = (pause->autoneg != AUTONEG_ENABLE); fc.requested_mode = 0; if (pause->autoneg) { fc.requested_mode |= PAUSE_AUTO; } else { if (pause->tx_pause) fc.requested_mode |= PAUSE_TX; if (pause->rx_pause) fc.requested_mode |= PAUSE_RX; } rnpgbe_mbx_phy_pause_set(hw, fc.requested_mode); hw->fc = fc; return 0; } static void rnp500_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) { struct rnpgbe_adapter *adapter = netdev_priv(netdev); struct rnpgbe_hw *hw = &adapter->hw; u32 *regs_buff = p; int i; memset(p, 0, RNP500_REGS_LEN * sizeof(u32)); for (i = 0; i < RNP500_REGS_LEN; i++) regs_buff[i] = rd32(hw, i * 4); } static void rnp500_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { char *p = (char *)data; int i; switch (stringset) { case ETH_SS_TEST: for (i = 0; i < RNP500_TEST_LEN; i++) { memcpy(data, rnp500_gstrings_test[i], ETH_GSTRING_LEN); data += ETH_GSTRING_LEN; } break; case ETH_SS_STATS: for (i = 0; i < RNP500_GLOBAL_STATS_LEN; i++) { memcpy(p, rnp500_gstrings_net_stats[i].stat_string, ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } for (i = 0; i < RNP500_HWSTRINGS_STATS_LEN; i++) { memcpy(p, rnp500_hwstrings_stats[i].stat_string, ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } for (i = 0; i < RNP_NUM_TX_QUEUES; i++) { /* ==== tx ======== */ sprintf(p, "---\n queue%u_tx_packets", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_bytes", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_restart", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_busy", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_done_old", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_clean_desc", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_poll_count", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_irq_more", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_hw_head", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_hw_tail", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_sw_next_to_clean", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_sw_next_to_use", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_send_bytes", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_send_bytes_to_hw", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_todo_update", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_send_done_bytes", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_added_vlan_packets", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_next_to_clean", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_irq_miss", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_equal_count", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_clean_times", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_tx_clean_count", i); p += ETH_GSTRING_LEN; /* ==== rx ======== */ sprintf(p, "queue%u_rx_packets", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_bytes", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_driver_drop_packets", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_rsc", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_rsc_flush", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_non_eop_descs", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_alloc_page_failed", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_alloc_buff_failed", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_alloc_page", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_csum_offload_errs", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_csum_offload_good", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_poll_again_count", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_rm_vlan_packets", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_hw_head", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_hw_tail", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_sw_next_to_use", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_sw_next_to_clean", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_next_to_clean", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_irq_miss", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_equal_count", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_clean_times", i); p += ETH_GSTRING_LEN; sprintf(p, "queue%u_rx_clean_count", i); p += ETH_GSTRING_LEN; } break; case ETH_SS_PRIV_FLAGS: memcpy(data, rnp500_priv_flags_strings, RNP500_PRIV_FLAGS_STR_LEN * ETH_GSTRING_LEN); break; } } static int rnp500_get_sset_count(struct net_device *netdev, int sset) { switch (sset) { case ETH_SS_TEST: return RNP500_TEST_LEN; case ETH_SS_STATS: return RNP500_STATS_LEN; case ETH_SS_PRIV_FLAGS: return RNP500_PRIV_FLAGS_STR_LEN; default: return -EOPNOTSUPP; } } static u32 rnp500_get_priv_flags(struct net_device *netdev) { struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)netdev_priv(netdev); u32 priv_flags = 0; if (adapter->priv_flags & RNP_PRIV_FLAG_MAC_LOOPBACK) priv_flags |= RNP500_MAC_LOOPBACK; if (adapter->priv_flags & RNP_PRIV_FLAG_PADDING_DEBUG) priv_flags |= RNP500_PADDING_DEBUG; if (adapter->priv_flags & RNP_PRIV_FLAG_SIMUATE_DOWN) priv_flags |= RNP500_SIMULATE_DOWN; if (adapter->priv_flags & RNP_PRIV_FLAG_ULTRA_SHORT) priv_flags |= RNP500_ULTRA_SHORT; if (adapter->priv_flags & RNP_PRIV_FLAG_DOUBLE_VLAN) priv_flags |= RNP500_DOUBLE_VLAN; if (adapter->priv_flags & RNP_PRIV_FLAG_PAUSE_OWN) priv_flags |= RNP500_PAUSE_OWN; if (adapter->flags2 & RNP_FLAG2_VLAN_STAGS_ENABLED) priv_flags |= RNP500_STAGS_ENABLE; if (adapter->priv_flags & RNP_PRIV_FLAG_JUMBO) priv_flags |= RNP500_JUMBO_ENABLE; if (adapter->priv_flags & RNP_PRIV_FLAG_TX_PADDING) priv_flags |= RNP500_TX_PADDING; if (adapter->priv_flags & RNP_PRIV_FLAG_SOFT_TX_PADDING) priv_flags |= RNP500_TX_SOLF_PADDING; if (adapter->priv_flags & RNP_PRIV_FLAG_REC_HDR_LEN_ERR) priv_flags |= RNP500_REC_HDR_LEN_ERR; if (adapter->priv_flags & RNP_PRIV_FLAG_DOUBLE_VLAN_RECEIVE) priv_flags |= RNP500_DOUBLE_VLAN_RECEIVE; if (adapter->priv_flags & RNP_PRIV_FLAG_RX_SKIP_EN) priv_flags |= RNP500_RX_SKIP_EN; if (adapter->priv_flags & RNP_PRIV_FLAG_TCP_SYNC_PRIO) priv_flags |= RNP500_TCP_SYNC_PRIO; if (adapter->priv_flags & RNP_PRIV_FLAG_REMAP_PRIO) priv_flags |= RNP500_REMAP_PRIO; if (adapter->priv_flags & RNP_PRIV_FLAG_8023_PRIO) priv_flags |= RNP500_8023_PRIO; if (adapter->priv_flags & RNP_PRIV_FLAG_SRIOV_VLAN_MODE) priv_flags |= RNP500_SRIOV_VLAN_MODE; if (adapter->priv_flags & RNP_PRIV_FLAG_LLDP) priv_flags |= RNP500_LLDP_EN; if (adapter->priv_flags & RNP_PRIV_FLAG_LINK_DOWN_ON_CLOSE) priv_flags |= RNP500_FORCE_CLOSE; return priv_flags; } static int rnp500_set_priv_flags(struct net_device *netdev, u32 priv_flags) { struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)netdev_priv(netdev); struct rnpgbe_hw *hw = &adapter->hw; struct rnpgbe_dma_info *dma = &hw->dma; struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_mac_info *mac = &hw->mac; u32 data_old; u32 data_new; data_old = dma_rd32(dma, RNP_DMA_CONFIG); data_new = data_old; if (priv_flags & RNP500_MAC_LOOPBACK) { SET_BIT(n500_mac_loopback, data_new); adapter->priv_flags |= RNP_PRIV_FLAG_MAC_LOOPBACK; } else if (adapter->priv_flags & RNP_PRIV_FLAG_MAC_LOOPBACK) { adapter->priv_flags &= (~RNP_PRIV_FLAG_MAC_LOOPBACK); CLR_BIT(n500_mac_loopback, data_new); } if (priv_flags & RNP500_PADDING_DEBUG) adapter->priv_flags |= RNP_PRIV_FLAG_PADDING_DEBUG; else if (adapter->priv_flags & RNP_PRIV_FLAG_PADDING_DEBUG) adapter->priv_flags &= (~RNP_PRIV_FLAG_PADDING_DEBUG); if (priv_flags & RNP500_SIMULATE_DOWN) { adapter->priv_flags |= RNP_PRIV_FLAG_SIMUATE_DOWN; /* set check link again */ adapter->flags |= RNP_FLAG_NEED_LINK_UPDATE; } else if (adapter->priv_flags & RNP_PRIV_FLAG_SIMUATE_DOWN) { adapter->priv_flags &= (~RNP_PRIV_FLAG_SIMUATE_DOWN); /* set check link again */ adapter->flags |= RNP_FLAG_NEED_LINK_UPDATE; } if (priv_flags & RNP500_ULTRA_SHORT) { int min = 33; adapter->priv_flags |= RNP_PRIV_FLAG_ULTRA_SHORT; eth_wr32(eth, RNP500_ETH_DEFAULT_RX_MIN_LEN, min); } else { int min = 60; adapter->priv_flags &= (~RNP_PRIV_FLAG_ULTRA_SHORT); eth_wr32(eth, RNP500_ETH_DEFAULT_RX_MIN_LEN, min); } if (priv_flags & RNP500_PAUSE_OWN) { u32 data; data = mac_rd32(mac, GMAC_FLOW_CTRL); data |= GMAC_FLOW_CTRL_UP; adapter->priv_flags |= RNP_PRIV_FLAG_PAUSE_OWN; mac_wr32(mac, GMAC_FLOW_CTRL, data); } else { u32 data; data = mac_rd32(mac, GMAC_FLOW_CTRL); data &= (~GMAC_FLOW_CTRL_UP); adapter->priv_flags &= (~RNP_PRIV_FLAG_PAUSE_OWN); mac_wr32(mac, GMAC_FLOW_CTRL, data); } if (priv_flags & RNP500_DOUBLE_VLAN) { adapter->priv_flags |= RNP_PRIV_FLAG_DOUBLE_VLAN; eth->ops.set_double_vlan(eth, true); } else { adapter->priv_flags &= (~RNP_PRIV_FLAG_DOUBLE_VLAN); eth->ops.set_double_vlan(eth, false); } if (priv_flags & RNP500_STAGS_ENABLE) { eth_wr32(eth, RNP500_ETH_TX_VLAN_CONTROL_EANBLE, 1); adapter->flags2 |= RNP_FLAG2_VLAN_STAGS_ENABLED; eth->ops.set_vfta(eth, adapter->stags_vid, true); } else { int true_remove = 1; int vid = adapter->stags_vid; eth_wr32(eth, RNP500_ETH_TX_VLAN_CONTROL_EANBLE, 0); adapter->flags2 &= (~RNP_FLAG2_VLAN_STAGS_ENABLED); if (vid) { if (test_bit(vid, adapter->active_vlans)) true_remove = 0; if (test_bit(vid, adapter->active_vlans_stags)) true_remove = 0; if (true_remove) hw->ops.set_vlan_filter(hw, vid, false, false); } } if (priv_flags & RNP500_JUMBO_ENABLE) { adapter->priv_flags |= RNP_PRIV_FLAG_JUMBO; hw->ops.set_mtu(hw, netdev->mtu); } else { adapter->priv_flags &= (~RNP_PRIV_FLAG_JUMBO); hw->ops.set_mtu(hw, netdev->mtu); } if (priv_flags & RNP500_TX_PADDING) adapter->priv_flags |= RNP_PRIV_FLAG_TX_PADDING; else adapter->priv_flags &= (~RNP_PRIV_FLAG_TX_PADDING); if (priv_flags & RNP500_TX_SOLF_PADDING) adapter->priv_flags |= RNP_PRIV_FLAG_SOFT_TX_PADDING; else adapter->priv_flags &= (~RNP_PRIV_FLAG_SOFT_TX_PADDING); if (priv_flags & RNP500_REC_HDR_LEN_ERR) { adapter->priv_flags |= RNP_PRIV_FLAG_REC_HDR_LEN_ERR; eth_wr32(eth, RNP500_ETH_ERR_MASK_VECTOR, PKT_LEN_ERR | HDR_LEN_ERR); } else if (adapter->priv_flags & RNP_PRIV_FLAG_REC_HDR_LEN_ERR) { adapter->priv_flags &= (~RNP_PRIV_FLAG_REC_HDR_LEN_ERR); eth_wr32(eth, RNP500_ETH_ERR_MASK_VECTOR, 0); } if (priv_flags & RNP500_DOUBLE_VLAN_RECEIVE) { adapter->priv_flags |= RNP_PRIV_FLAG_DOUBLE_VLAN_RECEIVE; if (!(adapter->priv_flags & RNP_PRIV_FLAG_RX_ALL)) eth_wr32(eth, RNP500_ETH_DOUBLE_VLAN_DROP, 0); } else { adapter->priv_flags &= (~RNP_PRIV_FLAG_DOUBLE_VLAN_RECEIVE); if (!(adapter->priv_flags & RNP_PRIV_FLAG_RX_ALL)) eth_wr32(eth, RNP500_ETH_DOUBLE_VLAN_DROP, 1); } if (priv_flags & RNP500_TCP_SYNC_PRIO) adapter->priv_flags |= RNP_PRIV_FLAG_TCP_SYNC_PRIO; else adapter->priv_flags &= (~RNP_PRIV_FLAG_TCP_SYNC_PRIO); if (priv_flags & RNP500_SRIOV_VLAN_MODE) { int i; adapter->priv_flags |= RNP_PRIV_FLAG_SRIOV_VLAN_MODE; if (!(adapter->flags & RNP_FLAG_SRIOV_INIT_DONE)) goto skip_setup_vf_vlan_n500; for (i = 0; i < adapter->num_vfs; i++) { if (!hw->ops.set_vf_vlan_mode) break; if (adapter->vfinfo[i].vf_vlan) hw->ops.set_vf_vlan_mode(hw, adapter->vfinfo[i].vf_vlan, i, true); if (adapter->vfinfo[i].pf_vlan) hw->ops.set_vf_vlan_mode(hw, adapter->vfinfo[i].pf_vlan, i, true); } } else if (adapter->priv_flags & RNP_PRIV_FLAG_SRIOV_VLAN_MODE) { int i; adapter->priv_flags &= (~RNP_PRIV_FLAG_SRIOV_VLAN_MODE); for (i = 0; i < hw->max_vfs; i++) { if (hw->ops.set_vf_vlan_mode) hw->ops.set_vf_vlan_mode(hw, 0, i, false); } } if (priv_flags & RNP500_LLDP_EN) { hw->ops.set_lldp(hw, true); adapter->priv_flags |= RNP_PRIV_FLAG_LLDP; } else if (adapter->priv_flags & RNP_PRIV_FLAG_LLDP) { adapter->priv_flags &= (~RNP_PRIV_FLAG_LLDP); hw->ops.set_lldp(hw, false); } if (priv_flags & RNP500_FORCE_CLOSE) adapter->priv_flags |= RNP_PRIV_FLAG_LINK_DOWN_ON_CLOSE; else adapter->priv_flags &= (~RNP_PRIV_FLAG_LINK_DOWN_ON_CLOSE); skip_setup_vf_vlan_n500: if (priv_flags & RNP500_8023_PRIO) { adapter->priv_flags |= RNP_PRIV_FLAG_8023_PRIO; eth_wr32(eth, RNP500_PRIORITY_EN_8023, 1); } else { adapter->priv_flags &= (~RNP_PRIV_FLAG_8023_PRIO); eth_wr32(eth, RNP500_PRIORITY_EN_8023, 0); } if (priv_flags & RNP500_REMAP_PRIO) adapter->priv_flags |= RNP_PRIV_FLAG_REMAP_PRIO; else adapter->priv_flags &= (~RNP_PRIV_FLAG_REMAP_PRIO); if (priv_flags & (RNP500_8023_PRIO | RNP500_REMAP_PRIO)) { eth_wr32(eth, RNP500_PRIORITY_1_MARK, RNP500_PRIORITY_1); eth_wr32(eth, RNP500_PRIORITY_0_MARK, RNP500_PRIORITY_0); eth_wr32(eth, RNP500_PRIORITY_EN, 1); } else { eth_wr32(eth, RNP500_PRIORITY_EN, 0); } if (adapter->priv_flags & RNP_PRIV_FLAG_TCP_SYNC) { if (adapter->priv_flags & RNP_PRIV_FLAG_TCP_SYNC_PRIO) { hw->ops.set_tcp_sync_remapping(hw, adapter->tcp_sync_queue, true, true); } else { hw->ops.set_tcp_sync_remapping(hw, adapter->tcp_sync_queue, true, false); } } if (data_old != data_new) dma_wr32(dma, RNP_DMA_CONFIG, data_new); /* if ft_padding changed */ if (CHK_BIT(n500_padding_enable, data_old) != CHK_BIT(n500_padding_enable, data_new)) { rnpgbe_msg_post_status(adapter, PF_FT_PADDING_STATUS); } return 0; } static void rnp500_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { struct rnpgbe_adapter *adapter = netdev_priv(netdev); struct net_device_stats *net_stats = &netdev->stats; struct rnpgbe_ring *ring; int i, j; char *p = NULL; rnpgbe_update_stats(adapter); for (i = 0; i < RNP500_GLOBAL_STATS_LEN; i++) { p = (char *)net_stats + rnp500_gstrings_net_stats[i].stat_offset; data[i] = (rnp500_gstrings_net_stats[i].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } for (j = 0; j < RNP500_HWSTRINGS_STATS_LEN; j++, i++) { p = (char *)adapter + rnp500_hwstrings_stats[j].stat_offset; data[i] = (rnp500_hwstrings_stats[j].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } BUG_ON(RNP_NUM_TX_QUEUES != RNP_NUM_RX_QUEUES); for (j = 0; j < RNP_NUM_TX_QUEUES; j++) { /* tx-ring */ ring = adapter->tx_ring[j]; if (!ring) { /* tx */ data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; /* rx */ data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; continue; } data[i++] = ring->stats.packets; data[i++] = ring->stats.bytes; data[i++] = ring->tx_stats.restart_queue; data[i++] = ring->tx_stats.tx_busy; data[i++] = ring->tx_stats.tx_done_old; data[i++] = ring->tx_stats.clean_desc; data[i++] = ring->tx_stats.poll_count; data[i++] = ring->tx_stats.irq_more_count; /* rnpgbe_tx_queue_ring_stat */ data[i++] = ring_rd32(ring, RNP_DMA_REG_TX_DESC_BUF_HEAD); data[i++] = ring_rd32(ring, RNP_DMA_REG_TX_DESC_BUF_TAIL); data[i++] = ring->next_to_clean; data[i++] = ring->next_to_use; data[i++] = ring->tx_stats.send_bytes; data[i++] = ring->tx_stats.send_bytes_to_hw; data[i++] = ring->tx_stats.todo_update; data[i++] = ring->tx_stats.send_done_bytes; data[i++] = ring->tx_stats.vlan_add; if (ring->tx_stats.tx_next_to_clean == -1) data[i++] = ring->count; else data[i++] = ring->tx_stats.tx_next_to_clean; data[i++] = ring->tx_stats.tx_irq_miss; data[i++] = ring->tx_stats.tx_equal_count; data[i++] = ring->tx_stats.tx_clean_times; data[i++] = ring->tx_stats.tx_clean_count; /* rx-ring */ ring = adapter->rx_ring[j]; if (!ring) { /* rx */ data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; data[i++] = 0; continue; } data[i++] = ring->stats.packets; data[i++] = ring->stats.bytes; data[i++] = ring->rx_stats.driver_drop_packets; data[i++] = ring->rx_stats.rsc_count; data[i++] = ring->rx_stats.rsc_flush; data[i++] = ring->rx_stats.non_eop_descs; data[i++] = ring->rx_stats.alloc_rx_page_failed; data[i++] = ring->rx_stats.alloc_rx_buff_failed; data[i++] = ring->rx_stats.alloc_rx_page; data[i++] = ring->rx_stats.csum_err; data[i++] = ring->rx_stats.csum_good; data[i++] = ring->rx_stats.poll_again_count; data[i++] = ring->rx_stats.vlan_remove; /* rnpgbe_rx_queue_ring_stat */ data[i++] = ring_rd32(ring, RNP_DMA_REG_RX_DESC_BUF_HEAD); data[i++] = ring_rd32(ring, RNP_DMA_REG_RX_DESC_BUF_TAIL); data[i++] = ring->next_to_use; data[i++] = ring->next_to_clean; if (ring->rx_stats.rx_next_to_clean == -1) data[i++] = ring->count; else data[i++] = ring->rx_stats.rx_next_to_clean; data[i++] = ring->rx_stats.rx_irq_miss; data[i++] = ring->rx_stats.rx_equal_count; data[i++] = ring->rx_stats.rx_clean_times; data[i++] = ring->rx_stats.rx_clean_count; } } /* n500 ethtool_ops ops here */ static const struct ethtool_ops rnp500_ethtool_ops = { .get_link_ksettings = rnp500_get_link_ksettings, .set_link_ksettings = rnp500_set_link_ksettings, .get_drvinfo = rnp500_get_drvinfo, .get_regs_len = rnp500_get_regs_len, .get_regs = rnp500_get_regs, .get_wol = rnpgbe_get_wol, .set_wol = rnpgbe_set_wol, .get_link = ethtool_op_get_link, .get_eeprom_len = rnp500_get_eeprom_len, .get_eeprom = rnp500_get_eeprom, .set_eeprom = rnp500_set_eeprom, .get_ringparam = rnpgbe_get_ringparam, .set_ringparam = rnpgbe_set_ringparam, .get_pauseparam = rnp500_get_pauseparam, .set_pauseparam = rnp500_set_pauseparam, .get_msglevel = rnpgbe_get_msglevel, .set_msglevel = rnpgbe_set_msglevel, .self_test = rnpgbe_diag_test, .get_strings = rnp500_get_strings, .set_phys_id = rnpgbe_set_phys_id, .get_sset_count = rnp500_get_sset_count, .get_priv_flags = rnp500_get_priv_flags, .set_priv_flags = rnp500_set_priv_flags, .get_ethtool_stats = rnp500_get_ethtool_stats, .get_coalesce = rnpgbe_get_coalesce, .set_coalesce = rnpgbe_set_coalesce, .supported_coalesce_params = ETHTOOL_COALESCE_USECS, .get_rxnfc = rnpgbe_get_rxnfc, .set_rxnfc = rnpgbe_set_rxnfc, .get_eee = rnpgbe_get_eee, .set_eee = rnpgbe_set_eee, .get_channels = rnpgbe_get_channels, .set_channels = rnpgbe_set_channels, .get_module_eeprom = rnpgbe_get_module_eeprom, .get_ts_info = rnpgbe_get_ts_info, .get_rxfh_indir_size = rnpgbe_rss_indir_size, .get_rxfh_key_size = rnpgbe_get_rxfh_key_size, .get_rxfh = rnpgbe_get_rxfh, .set_rxfh = rnpgbe_set_rxfh, .get_dump_flag = rnpgbe_get_dump_flag, .get_dump_data = rnpgbe_get_dump_data, .set_dump = rnpgbe_set_dump, .flash_device = rnpgbe_flash_device, }; static void rnpgbe_set_ethtool_hw_ops_n500(struct net_device *netdev) { netdev->ethtool_ops = &rnp500_ethtool_ops; } static struct rnpgbe_hw_operations hw_ops_n500 = { .init_hw = &rnpgbe_init_hw_ops_n500, .reset_hw = &rnpgbe_reset_hw_ops_n500, .start_hw = &rnpgbe_start_hw_ops_n500, .set_mtu = &rnpgbe_set_mtu_hw_ops_n500, .set_vlan_filter_en = &rnpgbe_set_vlan_filter_en_hw_ops_n500, .set_vlan_filter = &rnpgbe_set_vlan_filter_hw_ops_n500, .set_veb_vlan_mask = &rnpgbe_set_veb_vlan_mask_hw_ops_n500, .set_vf_vlan_filter = &rnpgbe_set_vf_vlan_filter_hw_ops_n500, .clr_vfta = &rnpgbe_clr_vfta_hw_ops_n500, .set_vlan_strip = &rnpgbe_set_vlan_strip_hw_ops_n500, .set_mac = &rnpgbe_set_mac_hw_ops_n500, .set_rx_mode = &rnpgbe_set_rx_mode_hw_ops_n500, .set_rar_with_vf = &rnpgbe_set_rar_with_vf_hw_ops_n500, .clr_rar = &rnpgbe_clr_rar_hw_ops_n500, .clr_rar_all = &rnpgbe_clr_rar_all_hw_ops_n500, .clr_vlan_veb = &rnpgbe_clr_vlan_veb_hw_ops_n500, .set_txvlan_mode = &rnpgbe_set_txvlan_mode_hw_ops_n500, .set_fcs_mode = &rnpgbe_set_fcs_mode_hw_ops_n500, .set_mac_rx = &rnpgbe_set_mac_rx_hw_ops_n500, .update_sriov_info = &rnpgbe_update_sriov_info_hw_ops_n500, .set_sriov_status = &rnpgbe_set_sriov_status_hw_ops_n500, .set_sriov_vf_mc = &rnpgbe_set_sriov_vf_mc_hw_ops_n500, .set_pause_mode = &rnpgbe_set_pause_mode_hw_ops_n500, .get_pause_mode = &rnpgbe_get_pause_mode_hw_ops_n500, .update_hw_info = &rnpgbe_update_hw_info_hw_ops_n500, .set_rx_hash = &rnpgbe_set_rx_hash_hw_ops_n500, .set_rss_hfunc = &rnpgbe_set_rss_hfunc_hw_ops_n500, .set_rss_key = &rnpgbe_set_rss_key_hw_ops_n500, .set_rss_table = &rnpgbe_set_rss_table_hw_ops_n500, .set_mbx_link_event = &rnpgbe_set_mbx_link_event_hw_ops_n500, .set_mbx_ifup = &rnpgbe_set_mbx_ifup_hw_ops_n500, .check_link = &rnpgbe_check_mac_link_hw_ops_n500, .setup_link = &rnpgbe_setup_mac_link_hw_ops_n500, .clean_link = &rnpgbe_clean_link_hw_ops_n500, .init_rx_addrs = &rnpgbe_init_rx_addrs_hw_ops_n500, .set_layer2_remapping = &rnpgbe_set_layer2_hw_ops_n500, .clr_layer2_remapping = &rnpgbe_clr_layer2_hw_ops_n500, .clr_all_layer2_remapping = &rnpgbe_clr_all_layer2_hw_ops_n500, .set_tuple5_remapping = &rnpgbe_set_tuple5_hw_ops_n500, .clr_tuple5_remapping = &rnpgbe_clr_tuple5_hw_ops_n500, .clr_all_tuple5_remapping = &rnpgbe_clr_all_tuple5_hw_ops_n500, .set_tcp_sync_remapping = &rnpgbe_set_tcp_sync_hw_ops_n500, .set_rx_skip = &rnpgbe_set_rx_skip_hw_ops_n500, .set_outer_vlan_type = &rnpgbe_set_outer_vlan_type_hw_ops_n500, .update_hw_status = &rnpgbe_update_hw_status_hw_ops_n500, .update_rx_drop = &rnpgbe_update_hw_rx_drop_hw_ops_n500, .setup_ethtool = &rnpgbe_set_ethtool_hw_ops_n500, .phy_read_reg = &rnpgbe_phy_read_reg_hw_ops_n500, .phy_write_reg = &rnpgbe_phy_write_reg_hw_ops_n500, .setup_wol = &rnpgbe_setup_wol_hw_ops_n500, .set_vf_vlan_mode = &rnpgbe_set_vf_vlan_mode_hw_ops_n500, .driver_status = &rnpgbe_driver_status_hw_ops_n500, .setup_eee = &rnpgbe_setup_eee_hw_ops_n500, .set_eee_mode = &rnpgbe_set_eee_mode_hw_ops_n500, .reset_eee_mode = &rnpgbe_reset_eee_mode_hw_ops_n500, .set_eee_timer = &rnpgbe_set_eee_timer_hw_ops_n500, .set_eee_pls = &rnpgbe_set_eee_pls_hw_ops_n500, .get_lpi_status = &rnpgbe_get_lpi_status_hw_ops_n500, .get_ncsi_mac = &rnpgbe_get_ncsi_mac_hw_ops_n500, .get_ncsi_vlan = &rnpgbe_get_ncsi_vlan_hw_ops_n500, .set_lldp = &rnpgbe_set_lldp_hw_ops_n500, .get_lldp = &rnpgbe_get_lldp_hw_ops_n500, }; static void rnpgbe_mac_set_rx_n500(struct rnpgbe_mac_info *mac, bool status) { u32 value = mac_rd32(mac, GMAC_CONTROL); if (status) value |= GMAC_CONTROL_TE | GMAC_CONTROL_RE; else value &= ~(GMAC_CONTROL_RE); mac_wr32(mac, GMAC_CONTROL, value); value = mac_rd32(mac, GMAC_FRAME_FILTER); mac_wr32(mac, GMAC_FRAME_FILTER, value | 1); } static void rnpgbe_mac_set_speed_n500(struct rnpgbe_mac_info *mac, bool link, u32 speed, bool duplex) { #define SPEED_MASK (RNP_DM_MASK | RNP_FES_MASK | RNP_PS_MASK | RNP_LUD_MASK) u32 value = mac_rd32(mac, GMAC_CONTROL); value &= (~SPEED_MASK); if (link) value |= RNP_LUD_MASK; if (duplex) value |= RNP_DM_MASK; switch (speed) { case RNP_LINK_SPEED_100_FULL: value |= RNP_PS_MASK; value |= RNP_FES_MASK; break; case RNP_LINK_SPEED_10_FULL: value |= RNP_PS_MASK; break; } mac_wr32(mac, GMAC_CONTROL, value); } static void rnpgbe_mac_fcs_n500(struct rnpgbe_mac_info *mac, bool status) { #define RNP500_CST_MASK BIT(25) u32 value = mac_rd32(mac, GMAC_CONTROL); if (status) value &= (~RNP500_CST_MASK); else value |= (RNP500_CST_MASK); mac_wr32(mac, GMAC_CONTROL, value); } /** * rnpgbe_mac_fc_mode_n500 - Enable flow control * @mac: pointer to hardware structure * * Enable flow control according to the current settings. **/ static s32 rnpgbe_mac_fc_mode_n500(struct rnpgbe_mac_info *mac) { struct rnpgbe_hw *hw = (struct rnpgbe_hw *)mac->back; s32 ret_val = 0; unsigned int flow = GMAC_FLOW_CTRL_UP; flow = mac_rd32(mac, GMAC_FLOW_CTRL); flow &= GMAC_FLOW_CTRL_UP; /* Validate the water mark configuration for packet buffer 0. Zero * water marks indicate that the packet buffer was not configured * and the watermarks for packet buffer 0 should always be configured. */ if (!hw->fc.pause_time) { ret_val = RNP_ERR_INVALID_LINK_SETTINGS; goto out; } switch (hw->fc.current_mode) { case rnpgbe_fc_none: /* Flow control is disabled by software override or autoneg. * The code below will actually disable it in the HW. */ break; case rnpgbe_fc_rx_pause: /* Rx Flow control is enabled and Tx Flow control is * disabled by software override. Since there really * isn't a way to advertise that we are capable of RX * Pause ONLY, we will advertise that we support both * symmetric and asymmetric Rx PAUSE. Later, we will * disable the adapter's ability to send PAUSE frames. */ flow |= GMAC_FLOW_CTRL_RFE; break; case rnpgbe_fc_tx_pause: /* Tx Flow control is enabled, and Rx Flow control is * disabled by software override. */ flow |= GMAC_FLOW_CTRL_TFE; break; case rnpgbe_fc_full: /* Flow control (both Rx and Tx) is enabled by SW override. */ flow |= GMAC_FLOW_CTRL_RFE; flow |= GMAC_FLOW_CTRL_TFE; break; default: hw_dbg(hw, "Flow control param set incorrectly\n"); ret_val = RNP_ERR_CONFIG; goto out; } flow |= (hw->fc.pause_time << GMAC_FLOW_CTRL_PT_SHIFT); mac_wr32(mac, GMAC_FLOW_CTRL, flow); out: return ret_val; } static bool poll_free_mdio(u8 __iomem *addr, u32 mask, int count) { unsigned int value; int con = 0; do { value = rnpgbe_rd_reg(addr); usleep_range(10, 100); con++; } while ((value & mask) && (con < count)); return !!(con >= count); } static int rnpgbe_mdio_read(struct rnpgbe_mac_info *mac, int phyreg) { #define MII_BUSY 0x00000001 #define MII_WRITE 0x00000002 #define MII_DATA_MASK GENMASK(15, 0) unsigned int mii_address = mac->mii.addr; unsigned int mii_data = mac->mii.data; u32 value = MII_BUSY; int data = 0; int phyaddr = mac->phy_addr; value |= (phyaddr << mac->mii.addr_shift) & mac->mii.addr_mask; value |= (phyreg << mac->mii.reg_shift) & mac->mii.reg_mask; value |= (mac->clk_csr << mac->mii.clk_csr_shift) & mac->mii.clk_csr_mask; if (poll_free_mdio(mac->mac_addr + mii_address, MII_BUSY, 100)) return -EBUSY; mac_wr32(mac, mii_data, data); mac_wr32(mac, mii_address, value); if (poll_free_mdio(mac->mac_addr + mii_address, MII_BUSY, 100)) return -EBUSY; /* Read the data from the MII data register */ data = (int)mac_rd32(mac, mii_data) & MII_DATA_MASK; return data; } static void rnpgbe_mac_check_link_n500(struct rnpgbe_mac_info *mac, rnpgbe_link_speed *speed, bool *link_up, bool link_up_wait_to_complete) { struct rnpgbe_hw *hw = (struct rnpgbe_hw *)mac->back; u32 data; #define AUTONEGOTATION_COMPLETE (0x20) #define LINK_IS_UP (0x04) #define TEST_PHY (AUTONEGOTATION_COMPLETE | LINK_IS_UP) data = rnpgbe_mdio_read(mac, 1); if ((data & TEST_PHY) == TEST_PHY) { data = rnpgbe_mdio_read(mac, 0); #define DUPLEX_MODE (0x100) if (data & DUPLEX_MODE) { if (data & 0x40) { *speed = RNP_LINK_SPEED_1GB_FULL; hw->speed = SPEED_1000; } else if (data & 0x2000) { *speed = RNP_LINK_SPEED_100_FULL; hw->speed = SPEED_100; } else { *speed = RNP_LINK_SPEED_10_FULL; hw->speed = SPEED_10; } } else { if (data & 0x40) { *speed = RNP_LINK_SPEED_1GB_HALF; hw->speed = SPEED_1000; } else if (data & 0x2000) { *speed = RNP_LINK_SPEED_100_HALF; hw->speed = SPEED_100; } else { *speed = RNP_LINK_SPEED_10_HALF; hw->speed = SPEED_10; } } *link_up = true; hw->link = true; } else { *link_up = false; hw->link = false; *speed = RNP_LINK_SPEED_UNKNOWN; } } static void rnpgbe_mac_set_mac_n500(struct rnpgbe_mac_info *mac, u8 *addr, int index) { u32 rar_low, rar_high = 0; rar_low = ((u32)addr[0] | ((u32)addr[1] << 8) | ((u32)addr[2] << 16) | ((u32)addr[3] << 24)); rar_high = RNP_RAH_AV | ((u32)addr[4] | (u32)addr[5] << 8); mac_wr32(mac, RNP500_MAC_UNICAST_HIGH(index), rar_high); mac_wr32(mac, RNP500_MAC_UNICAST_LOW(index), rar_low); } static int rnpgbe_mac_mdio_read_n500(struct rnpgbe_mac_info *mac, u32 phyreg, u32 *regvalue) { unsigned int mii_address = mac->mii.addr; unsigned int mii_data = mac->mii.data; u32 value = MII_BUSY; int data = 0; int phyaddr = mac->phy_addr; value |= (phyaddr << mac->mii.addr_shift) & mac->mii.addr_mask; value |= (phyreg << mac->mii.reg_shift) & mac->mii.reg_mask; value |= (mac->clk_csr << mac->mii.clk_csr_shift) & mac->mii.clk_csr_mask; if (poll_free_mdio(mac->mac_addr + mii_address, MII_BUSY, 100)) return -EBUSY; mac_wr32(mac, mii_data, data); mac_wr32(mac, mii_address, value); if (poll_free_mdio(mac->mac_addr + mii_address, MII_BUSY, 100)) return -EBUSY; /* Read the data from the MII data register */ data = (int)mac_rd32(mac, mii_data) & MII_DATA_MASK; *regvalue = data; return data; } static int rnpgbe_mac_mdio_write_n500(struct rnpgbe_mac_info *mac, int phyreg, int phydata) { unsigned int mii_address = mac->mii.addr; unsigned int mii_data = mac->mii.data; u32 value = MII_BUSY; int data = phydata; int phyaddr = mac->phy_addr; value |= (phyaddr << mac->mii.addr_shift) & mac->mii.addr_mask; value |= (phyreg << mac->mii.reg_shift) & mac->mii.reg_mask; value |= (mac->clk_csr << mac->mii.clk_csr_shift) & mac->mii.clk_csr_mask; value |= MII_WRITE; /* Wait until any existing MII operation is complete */ if (poll_free_mdio(mac->mac_addr + mii_address, MII_BUSY, 100)) return -EBUSY; /* Set the MII address register to write */ mac_wr32(mac, mii_data, data); mac_wr32(mac, mii_address, value); /* Wait until any existing MII operation is complete */ return poll_free_mdio(mac->mac_addr + mii_address, MII_BUSY, 100); } static void rnpgbe_mac_pmt_n500(struct rnpgbe_mac_info *mac, u32 mode, bool ncsi_en) { unsigned int pmt = 0; if (mode & RNP_WUFC_MAG) { rnpgbe_dbg("GMAC: WOL Magic frame\n"); pmt |= magic_pkt_en; } if (mode & RNP_WUFC_EX) { rnpgbe_dbg("GMAC: WOL on global unicast\n"); pmt |= global_unicast | wake_up_frame_en; } /* only pmt down not ocp */ if (!ncsi_en) pmt |= power_down; mac_wr32(mac, GMAC_PMT, pmt); } static void rnpgbe_mac_set_eee_mode_n500(struct rnpgbe_mac_info *mac, bool en_tx_lpi_clockgating) { u32 value = 0; /* TODO - en_tx_lpi_clockgating treatment */ /* Enable the link status receive on RGMII, SGMII ore SMII * receive path and instruct the transmit to enter in LPI * state. */ value |= LPI_CTRL_STATUS_PLS; value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA; mac_wr32(mac, GMAC_LPI_CTRL_STATUS, value); } static void rnpgbe_mac_reset_eee_mode_n500(struct rnpgbe_mac_info *mac) { u32 value = 0; value |= LPI_CTRL_STATUS_PLS; value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA); mac_wr32(mac, GMAC_LPI_CTRL_STATUS, value); } static void rnpgbe_mac_set_eee_timer_n500(struct rnpgbe_mac_info *mac, int ls, int tw) { int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16); /* Program the timers in the LPI timer control register: * LS: minimum time (ms) for which the link * status from PHY should be ok before transmitting * the LPI pattern. * TW: minimum time (us) for which the core waits * after it has stopped transmitting the LPI pattern. */ mac_wr32(mac, GMAC_LPI_TIMER_CTRL, value); } static void rnpgbe_mac_set_eee_pls_n500(struct rnpgbe_mac_info *mac, int link) { u32 value = 0; value = mac_rd32(mac, GMAC_LPI_CTRL_STATUS); if (link) value |= LPI_CTRL_STATUS_PLS; else value &= ~LPI_CTRL_STATUS_PLS; mac_wr32(mac, GMAC_LPI_CTRL_STATUS, value); } static u32 rnpgbe_mac_get_lpi_status_n500(struct rnpgbe_mac_info *mac) { if (mac_rd32(mac, GMAC_INT_STATUS) & GMAC_INT_STATUS_LPIIS) return mac_rd32(mac, GMAC_LPI_CTRL_STATUS); else return 0; } static struct rnpgbe_mac_operations mac_ops_n500 = { .set_mac_rx = &rnpgbe_mac_set_rx_n500, .set_mac_speed = &rnpgbe_mac_set_speed_n500, .set_mac_fcs = &rnpgbe_mac_fcs_n500, .set_fc_mode = &rnpgbe_mac_fc_mode_n500, .check_link = &rnpgbe_mac_check_link_n500, .set_mac = &rnpgbe_mac_set_mac_n500, .mdio_write = &rnpgbe_mac_mdio_write_n500, .mdio_read = &rnpgbe_mac_mdio_read_n500, .pmt = &rnpgbe_mac_pmt_n500, .set_eee_mode = rnpgbe_mac_set_eee_mode_n500, .reset_eee_mode = rnpgbe_mac_reset_eee_mode_n500, .set_eee_timer = rnpgbe_mac_set_eee_timer_n500, .set_eee_pls = rnpgbe_mac_set_eee_pls_n500, .get_lpi_status = rnpgbe_mac_get_lpi_status_n500, }; static s32 rnpgbe_get_invariants_n500(struct rnpgbe_hw *hw) { struct rnpgbe_mac_info *mac = &hw->mac; struct rnpgbe_dma_info *dma = &hw->dma; struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_nic_info *nic = &hw->nic; struct rnpgbe_mbx_info *mbx = &hw->mbx; struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)hw->back; int i; nic->nic_base_addr = hw->hw_addr + RNP500_NIC_BASE; /* setup dma info */ dma->dma_base_addr = hw->hw_addr; dma->dma_ring_addr = hw->hw_addr + RNP500_RING_BASE; dma->max_tx_queues = RNP_N500_MAX_TX_QUEUES; dma->max_rx_queues = RNP_N500_MAX_RX_QUEUES; dma->back = hw; memcpy(&hw->dma.ops, &dma_ops_n500, sizeof(hw->dma.ops)); /* setup eth info */ memcpy(&hw->eth.ops, ð_ops_n500, sizeof(hw->eth.ops)); eth->eth_base_addr = hw->hw_addr + RNP500_ETH_BASE; eth->back = hw; eth->mc_filter_type = 4; eth->mcft_size = RNP_N500_MC_TBL_SIZE; eth->vft_size = RNP_N500_VFT_TBL_SIZE; eth->num_rar_entries = RNP_N500_RAR_ENTRIES + NCSI_RAR_NUM; eth->max_rx_queues = RNP_N500_MAX_RX_QUEUES; eth->max_tx_queues = RNP_N500_MAX_TX_QUEUES; /* setup mac info */ memcpy(&hw->mac.ops, &mac_ops_n500, sizeof(hw->mac.ops)); mac->mac_addr = hw->hw_addr + RNP500_MAC_BASE; mac->back = hw; mac->mac_type = mac_dwc_g; mac->mc_filter_type = 4; mac->mcft_size = 2; mac->vft_size = 1; mac->num_rar_entries = RNP_N500_RAR_ENTRIES; mac->max_rx_queues = RNP_N500_MAX_RX_QUEUES; mac->max_tx_queues = RNP_N500_MAX_TX_QUEUES; mac->max_msix_vectors = RNP_N500_MSIX_VECTORS; mac->mii.addr = GMAC_MII_ADDR; mac->mii.data = GMAC_MII_DATA; mac->mii.addr_shift = 11; mac->mii.addr_mask = 0x0000F800; mac->mii.reg_shift = 6; mac->mii.reg_mask = 0x000007C0; mac->mii.clk_csr_shift = 2; mac->mii.clk_csr_mask = GENMASK(5, 2); mac->clk_csr = 0x02; /* csr 25M */ mac->phy_addr = 0x11; if (!hw->axi_mhz) hw->usecstocount = 125; else hw->usecstocount = hw->axi_mhz; /* set up hw feature */ hw->feature_flags |= RNP_NET_FEATURE_SG | RNP_NET_FEATURE_TX_CHECKSUM | RNP_NET_FEATURE_RX_CHECKSUM | RNP_NET_FEATURE_TSO | RNP_NET_FEATURE_VLAN_FILTER | RNP_NET_FEATURE_VLAN_OFFLOAD | RNP_NET_FEATURE_RX_NTUPLE_FILTER | RNP_NET_FEATURE_RX_HASH | RNP_NET_FEATURE_USO | RNP_NET_FEATURE_RX_FCS | RNP_NET_FEATURE_STAG_FILTER | RNP_NET_FEATURE_STAG_OFFLOAD; /* maybe supported future*/ hw->feature_flags |= RNP_HW_FEATURE_EEE; /* setup some fdir resource */ hw->min_length = RNP_MIN_MTU; hw->max_length = RNP500_MAX_JUMBO_FRAME_SIZE; hw->max_msix_vectors = RNP_N500_MSIX_VECTORS; hw->num_rar_entries = RNP_N500_RAR_ENTRIES; hw->fdir_mode = fdir_mode_tuple5; hw->max_vfs = RNP_N500_MAX_VF; hw->max_vfs_noari = 1; hw->layer2_count = RNP500_MAX_LAYER2_FILTERS - 1; hw->tuple5_count = RNP500_MAX_TUPLE5_FILTERS - 1; /* n500 support magic wol */ hw->wol_supported = WAKE_MAGIC; hw->num_vebvlan_entries = 8; hw->default_rx_queue = 0; hw->rss_indir_tbl_num = RNP_N500_RSS_TBL_NUM; hw->rss_tc_tbl_num = RNP_N500_RSS_TC_TBL_NUM; /* vf use the last vfnum */ hw->vfnum = RNP_N500_MAX_VF - 1; hw->sriov_ring_limit = 1; hw->max_pf_macvlans = RNP_MAX_PF_MACVLANS_N500; hw->veb_ring = RNP_N500_MAX_RX_QUEUES - 1; memcpy(&hw->ops, &hw_ops_n500, sizeof(hw->ops)); hw->supported_link = RNP_LINK_SPEED_1GB_FULL; /* mbx setup */ mbx->vf2pf_mbox_vec_base = 0x28900; mbx->cpu2pf_mbox_vec = 0x28b00; mbx->pf_vf_shm_base = 0x29000; mbx->mbx_mem_size = 64; mbx->pf2vf_mbox_ctrl_base = 0x2a100; mbx->pf_vf_mbox_mask_lo = 0x2a200; mbx->pf_vf_mbox_mask_hi = 0; mbx->cpu_pf_shm_base = 0x2d000; mbx->pf2cpu_mbox_ctrl = 0x2e000; mbx->pf2cpu_mbox_mask = 0x2e200; mbx->cpu_vf_share_ram = 0x2b000; mbx->share_size = 512; adapter->priv_flags |= RNP_PRIV_FLAG_PAUSE_OWN; adapter->drop_time = 100; /*initialization default pause flow */ hw->fc.requested_mode = PAUSE_AUTO; hw->fc.pause_time = RNP_DEFAULT_FCPAUSE; hw->autoneg = 1; /* we start from auto mode */ hw->tp_mdix_ctrl = ETH_TP_MDI_AUTO; for (i = 0; i < RNP_MAX_TRAFFIC_CLASS; i++) { hw->fc.high_water[i] = RNP500_DEFAULT_HIGH_WATER; hw->fc.low_water[i] = RNP500_DEFAULT_LOW_WATER; } hw->eeprom.word_size = 10; return 0; } static s32 rnpgbe_get_invariants_n210(struct rnpgbe_hw *hw) { struct rnpgbe_mac_info *mac = &hw->mac; struct rnpgbe_dma_info *dma = &hw->dma; struct rnpgbe_eth_info *eth = &hw->eth; struct rnpgbe_nic_info *nic = &hw->nic; struct rnpgbe_mbx_info *mbx = &hw->mbx; struct rnpgbe_adapter *adapter = (struct rnpgbe_adapter *)hw->back; int i; nic->nic_base_addr = hw->hw_addr + RNP500_NIC_BASE; /* setup dma info */ dma->dma_base_addr = hw->hw_addr; dma->dma_ring_addr = hw->hw_addr + RNP500_RING_BASE; dma->max_tx_queues = RNP_N500_MAX_TX_QUEUES; dma->max_rx_queues = RNP_N500_MAX_RX_QUEUES; dma->back = hw; memcpy(&hw->dma.ops, &dma_ops_n500, sizeof(hw->dma.ops)); /* setup eth info */ memcpy(&hw->eth.ops, ð_ops_n500, sizeof(hw->eth.ops)); eth->eth_base_addr = hw->hw_addr + RNP500_ETH_BASE; eth->back = hw; eth->mc_filter_type = 4; eth->mcft_size = RNP_N500_MC_TBL_SIZE; eth->vft_size = RNP_N500_VFT_TBL_SIZE; eth->num_rar_entries = RNP_N500_RAR_ENTRIES + NCSI_RAR_NUM; eth->max_rx_queues = RNP_N500_MAX_RX_QUEUES; eth->max_tx_queues = RNP_N500_MAX_TX_QUEUES; /* setup mac info */ memcpy(&hw->mac.ops, &mac_ops_n500, sizeof(hw->mac.ops)); mac->mac_addr = hw->hw_addr + RNP500_MAC_BASE; mac->back = hw; mac->mac_type = mac_dwc_g; /* move this to eth todo */ mac->mc_filter_type = 4; mac->mcft_size = 2; mac->vft_size = 1; mac->num_rar_entries = RNP_N500_RAR_ENTRIES; mac->max_rx_queues = RNP_N500_MAX_RX_QUEUES; mac->max_tx_queues = RNP_N500_MAX_TX_QUEUES; mac->max_msix_vectors = RNP_N500_MSIX_VECTORS; mac->mii.addr = GMAC_MII_ADDR; mac->mii.data = GMAC_MII_DATA; mac->mii.addr_shift = 11; mac->mii.addr_mask = 0x0000F800; mac->mii.reg_shift = 6; mac->mii.reg_mask = 0x000007C0; mac->mii.clk_csr_shift = 2; mac->mii.clk_csr_mask = GENMASK(5, 2); mac->clk_csr = 0x02; /* csr 25M */ mac->phy_addr = 0x11; if (!hw->axi_mhz) hw->usecstocount = 62; else hw->usecstocount = hw->axi_mhz; /* set up hw feature */ hw->feature_flags |= RNP_NET_FEATURE_SG | RNP_NET_FEATURE_TX_CHECKSUM | RNP_NET_FEATURE_RX_CHECKSUM | RNP_NET_FEATURE_TSO | RNP_NET_FEATURE_VLAN_FILTER | RNP_NET_FEATURE_VLAN_OFFLOAD | RNP_NET_FEATURE_RX_NTUPLE_FILTER | RNP_NET_FEATURE_RX_HASH | RNP_NET_FEATURE_USO | RNP_NET_FEATURE_RX_FCS | RNP_NET_FEATURE_STAG_FILTER | RNP_NET_FEATURE_STAG_OFFLOAD; /* setup some fdir resource */ hw->min_length = RNP_MIN_MTU; hw->max_length = RNP500_MAX_JUMBO_FRAME_SIZE; hw->max_msix_vectors = RNP_N500_MSIX_VECTORS; hw->num_rar_entries = RNP_N500_RAR_ENTRIES; hw->fdir_mode = fdir_mode_tuple5; hw->max_vfs = RNP_N500_MAX_VF; hw->max_vfs_noari = 1; hw->layer2_count = RNP500_MAX_LAYER2_FILTERS - 1; hw->tuple5_count = RNP500_MAX_TUPLE5_FILTERS - 1; hw->wol_supported = WAKE_MAGIC; hw->num_vebvlan_entries = 8; hw->default_rx_queue = 0; hw->rss_indir_tbl_num = RNP_N500_RSS_TBL_NUM; hw->rss_tc_tbl_num = RNP_N500_RSS_TC_TBL_NUM; /* vf use the last vfnum */ hw->vfnum = RNP_N500_MAX_VF - 1; hw->sriov_ring_limit = 1; hw->max_pf_macvlans = RNP_MAX_PF_MACVLANS_N500; hw->veb_ring = RNP_N500_MAX_RX_QUEUES - 1; memcpy(&hw->ops, &hw_ops_n500, sizeof(hw->ops)); hw->supported_link = RNP_LINK_SPEED_1GB_FULL; mbx->vf2pf_mbox_vec_base = 0x29200; mbx->cpu2pf_mbox_vec = 0x29400; mbx->pf_vf_shm_base = 0x29900; mbx->mbx_mem_size = 64; mbx->pf2vf_mbox_ctrl_base = 0x2aa00; mbx->pf_vf_mbox_mask_lo = 0x2ab00; mbx->pf_vf_mbox_mask_hi = 0; mbx->cpu_pf_shm_base = 0x2d900; mbx->pf2cpu_mbox_ctrl = 0x2e900; mbx->pf2cpu_mbox_mask = 0x2eb00; mbx->cpu_vf_share_ram = 0x2b900; mbx->share_size = 512; adapter->priv_flags |= RNP_PRIV_FLAG_PAUSE_OWN; adapter->drop_time = 100; /*initialization default pause flow */ /* we start from auto */ hw->fc.requested_mode = PAUSE_AUTO; hw->fc.pause_time = RNP_DEFAULT_FCPAUSE; hw->autoneg = 1; hw->tp_mdix_ctrl = ETH_TP_MDI_AUTO; for (i = 0; i < RNP_MAX_TRAFFIC_CLASS; i++) { hw->fc.high_water[i] = RNP500_DEFAULT_HIGH_WATER; hw->fc.low_water[i] = RNP500_DEFAULT_LOW_WATER; } hw->eeprom.word_size = 10; return 0; } struct rnpgbe_info rnpgbe_n500_info = { .one_pf_with_two_dma = false, .total_queue_pair_cnts = RNP_N500_MAX_TX_QUEUES, .adapter_cnt = 1, .rss_type = rnpgbe_rss_n500, .hw_type = rnpgbe_hw_n500, .get_invariants = &rnpgbe_get_invariants_n500, .mac_ops = &mac_ops_n500, .eeprom_ops = NULL, .mbx_ops = &mbx_ops_generic, }; struct rnpgbe_info rnpgbe_n210_info = { .one_pf_with_two_dma = false, .total_queue_pair_cnts = RNP_N500_MAX_TX_QUEUES, .adapter_cnt = 1, .rss_type = rnpgbe_rss_n500, .hw_type = rnpgbe_hw_n210, .get_invariants = &rnpgbe_get_invariants_n210, .mac_ops = &mac_ops_n500, .eeprom_ops = NULL, .mbx_ops = &mbx_ops_generic, };