/*++ Copyright (c) 2021 Motorcomm, Inc. Motorcomm Confidential and Proprietary. This is Motorcomm NIC driver relevant files. Please don't copy, modify, distribute without commercial permission. --*/ #include "fuxi-gmac.h" #include "fuxi-gmac-reg.h" #include "fuxi-efuse.h" #if defined(UEFI) #include "nic_sw.h" #elif defined(_WIN64) || defined(_WIN32) #include "fuxi-mp.h" #elif defined(PXE) #include "fuxi_undi.h" #endif void fxgmac_release_phy(struct fxgmac_pdata* pdata); static void fxgmac_pwr_clock_ungate(struct fxgmac_pdata* pdata); static void fxgmac_pwr_clock_gate(struct fxgmac_pdata* pdata); static int fxgmac_tx_complete(struct fxgmac_dma_desc *dma_desc) { #ifdef LINUX #if (FXGMAC_DUMMY_TX_DEBUG) return 1; #endif #endif return !FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, TX_NORMAL_DESC3_OWN_POS, TX_NORMAL_DESC3_OWN_LEN); } static int fxgmac_disable_rx_csum(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_IPC_POS, MAC_CR_IPC_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); DPRINTK("fxgmac disable rx checksum.\n"); return 0; } static int fxgmac_enable_rx_csum(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_IPC_POS, MAC_CR_IPC_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); DPRINTK("fxgmac enable rx checksum.\n"); return 0; } static int fxgmac_set_mac_address(struct fxgmac_pdata *pdata, u8 *addr) { unsigned int mac_addr_hi, mac_addr_lo; mac_addr_hi = (addr[5] << 8) | (addr[4] << 0); mac_addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | (addr[0] << 0); writereg(pdata->pAdapter, mac_addr_hi, pdata->mac_regs + MAC_MACA0HR); writereg(pdata->pAdapter, mac_addr_lo, pdata->mac_regs + MAC_MACA0LR); return 0; } #if !defined(DPDK) static void fxgmac_set_mac_reg(struct fxgmac_pdata *pdata, struct netdev_hw_addr *ha, unsigned int *mac_reg) { unsigned int mac_addr_hi, mac_addr_lo; u8 *mac_addr; mac_addr_lo = 0; mac_addr_hi = 0; if (ha) { mac_addr = (u8 *)&mac_addr_lo; mac_addr[0] = ha->addr[0]; mac_addr[1] = ha->addr[1]; mac_addr[2] = ha->addr[2]; mac_addr[3] = ha->addr[3]; mac_addr = (u8 *)&mac_addr_hi; mac_addr[0] = ha->addr[4]; mac_addr[1] = ha->addr[5]; netif_dbg(pdata, drv, pdata->netdev, "adding mac address %pM at %#x\n", ha->addr, *mac_reg); mac_addr_hi = FXGMAC_SET_REG_BITS(mac_addr_hi, MAC_MACA1HR_AE_POS, MAC_MACA1HR_AE_LEN, 1); } writereg(pdata->pAdapter, mac_addr_hi, pdata->mac_regs + *mac_reg); *mac_reg += MAC_MACA_INC; writereg(pdata->pAdapter, mac_addr_lo, pdata->mac_regs + *mac_reg); *mac_reg += MAC_MACA_INC; } #endif static int fxgmac_enable_tx_vlan(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_VLANIR); /* Indicate that VLAN Tx CTAGs come from mac_vlan_incl register */ regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANIR_VLTI_POS, MAC_VLANIR_VLTI_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANIR_CSVL_POS, MAC_VLANIR_CSVL_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANIR_VLP_POS, MAC_VLANIR_VLP_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANIR_VLC_POS, MAC_VLANIR_VLC_LEN, 2); regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANIR_VLT_POS, MAC_VLANIR_VLT_LEN, pdata->vlan); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_VLANIR); regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_VLANTR); regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_VL_POS, MAC_VLANTR_VL_LEN, pdata->vlan); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_VLANTR); return 0; } static int fxgmac_disable_tx_vlan(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_VLANIR); /* Indicate that VLAN Tx CTAGs come from mac_vlan_incl register */ //Set VLAN Tag input enable regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANIR_CSVL_POS, MAC_VLANIR_CSVL_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANIR_VLTI_POS, MAC_VLANIR_VLTI_LEN, /*0*/1); //Set VLAN priority control disable regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANIR_VLP_POS, MAC_VLANIR_VLP_LEN, /*1*/0); regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANIR_VLC_POS, MAC_VLANIR_VLC_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_VLANIR); /* In order for the VLAN Hash Table filtering to be effective, * the VLAN tag identifier in the VLAN Tag Register must not * be zero. Set the VLAN tag identifier to "1" to enable the * VLAN Hash Table filtering. This implies that a VLAN tag of * 1 will always pass filtering. */ //2022-04-19 xiaojiang comment //If it enable the following code and enable vlan filter, then the MAC only receive the packet of VLAN ID "1" /*regval = readreg(pdata->mac_regs + MAC_VLANTR); regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_VL_POS, MAC_VLANTR_VL_LEN, 1); writereg(regval, pdata->mac_regs + MAC_VLANTR);*/ return 0; } static int fxgmac_enable_rx_vlan_stripping(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_VLANTR); /* Put the VLAN tag in the Rx descriptor */ regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_EVLRXS_POS, MAC_VLANTR_EVLRXS_LEN, 1); /* Don't check the VLAN type */ regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_DOVLTC_POS, MAC_VLANTR_DOVLTC_LEN, 1); /* Check only C-TAG (0x8100) packets */ regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_ERSVLM_POS, MAC_VLANTR_ERSVLM_LEN, 0); /* Don't consider an S-TAG (0x88A8) packet as a VLAN packet */ regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_ESVL_POS, MAC_VLANTR_ESVL_LEN, 0); /* Enable VLAN tag stripping */ regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_EVLS_POS, MAC_VLANTR_EVLS_LEN, 0x3); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_VLANTR); DPRINTK("fxgmac enable MAC rx vlan stripping.\n"); return 0; } static int fxgmac_disable_rx_vlan_stripping(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_VLANTR); regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_EVLS_POS, MAC_VLANTR_EVLS_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_VLANTR); DPRINTK("fxgmac disable MAC rx vlan stripping.\n"); return 0; } static int fxgmac_enable_rx_vlan_filtering(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PFR); /* Enable VLAN filtering */ regval = FXGMAC_SET_REG_BITS(regval, MAC_PFR_VTFE_POS, MAC_PFR_VTFE_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PFR); //2022-04-25 xiaojiang comment //FXGMAC_FILTER_SINGLE_VLAN_ENABLED is used for Linux driver //In Linux driver it uses VLAN Filter to filter packet, In windows driver it uses SW method to filter packet. #if FXGMAC_FILTER_SINGLE_VLAN_ENABLED regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_VLANTR); regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_VL_POS, MAC_VLANTR_VL_LEN, pdata->vlan); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_VLANTR); #else regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_VLANTR); /* Enable VLAN Hash Table filtering */ regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_VTHM_POS, MAC_VLANTR_VTHM_LEN, 1); /* Disable VLAN tag inverse matching */ regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_VTIM_POS, MAC_VLANTR_VTIM_LEN, 0); /* Only filter on the lower 12-bits of the VLAN tag */ regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_ETV_POS, MAC_VLANTR_ETV_LEN, 1); #endif return 0; } static int fxgmac_disable_rx_vlan_filtering(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PFR); /* Disable VLAN filtering */ regval = FXGMAC_SET_REG_BITS(regval, MAC_PFR_VTFE_POS, MAC_PFR_VTFE_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PFR); #if FXGMAC_FILTER_SINGLE_VLAN_ENABLED regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_VLANTR); regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANTR_VL_POS, MAC_VLANTR_VL_LEN, pdata->vlan); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_VLANTR); #endif return 0; } #if FXGMAC_FILTER_MULTIPLE_VLAN_ENABLED static u32 fxgmac_vid_crc32_le(__le16 vid_le) { unsigned char *data = (unsigned char *)&vid_le; unsigned char data_byte = 0; u32 crc = ~0; u32 temp = 0; int i, bits; bits = get_bitmask_order(VLAN_VID_MASK); for (i = 0; i < bits; i++) { if ((i % 8) == 0) data_byte = data[i / 8]; temp = ((crc & 1) ^ data_byte) & 1; crc >>= 1; data_byte >>= 1; if (temp) crc ^= CRC32_POLY_LE; } return crc; } #endif static int fxgmac_update_vlan_hash_table(struct fxgmac_pdata *pdata) { u16 vlan_hash_table = 0; u32 regval; //Linux also support multiple VLAN #if FXGMAC_FILTER_MULTIPLE_VLAN_ENABLED __le16 vid_le; u32 crc; u16 vid; /* Generate the VLAN Hash Table value */ for_each_set_bit(vid, pdata->active_vlans, VLAN_N_VID) { /* Get the CRC32 value of the VLAN ID */ vid_le = cpu_to_le16(vid); crc = bitrev32(~fxgmac_vid_crc32_le(vid_le)) >> 28; vlan_hash_table |= (1 << crc); } #endif regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_VLANHTR); /* Set the VLAN Hash Table filtering register */ regval = FXGMAC_SET_REG_BITS(regval, MAC_VLANHTR_VLHT_POS, MAC_VLANHTR_VLHT_LEN, vlan_hash_table); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_VLANHTR); DPRINTK("fxgmac_update_vlan_hash_tabl done,hash tbl=%08x.\n",vlan_hash_table); return 0; } static int fxgmac_set_promiscuous_mode(struct fxgmac_pdata *pdata, unsigned int enable) { unsigned int val = enable ? 1 : 0; u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PFR); if (FXGMAC_GET_REG_BITS(regval, MAC_PFR_PR_POS, MAC_PFR_PR_LEN) == val) { return 0; } netif_dbg(pdata, drv, pdata->netdev, ""STR_FORMAT" promiscuous mode\n", enable ? "entering" : "leaving"); regval = FXGMAC_SET_REG_BITS(regval, MAC_PFR_PR_POS, MAC_PFR_PR_LEN, val); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PFR); DbgPrintF(MP_TRACE, ""STR_FORMAT" - promiscuous mode=%d, reg=%x.", __FUNCTION__, enable, regval); DbgPrintF(MP_TRACE, ""STR_FORMAT" - note, vlan filter is called when set promiscuous mode=%d.", __FUNCTION__, enable); /* Hardware will still perform VLAN filtering in promiscuous mode */ if (enable) { fxgmac_disable_rx_vlan_filtering(pdata); } else { #ifdef LINUX if(pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER) #else if (0) #endif { fxgmac_enable_rx_vlan_filtering(pdata); } } DPRINTK("fxgmac set promisc mode=%d\n", enable); return 0; } static int fxgmac_enable_rx_broadcast(struct fxgmac_pdata *pdata, unsigned int enable) { unsigned int val = enable ? 0 : 1; //mac reg bit is disable,,so invert the val. u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PFR); if (FXGMAC_GET_REG_BITS(regval, MAC_PFR_DBF_POS, MAC_PFR_DBF_LEN) == val) { return 0; } regval = FXGMAC_SET_REG_BITS(regval, MAC_PFR_DBF_POS, MAC_PFR_DBF_LEN, val); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PFR); DbgPrintF(MP_TRACE, "%s - bcast en=%d, bit-val=%d, reg=%x.", __FUNCTION__, enable, val, regval); return 0; } static int fxgmac_set_all_multicast_mode(struct fxgmac_pdata *pdata, unsigned int enable) { unsigned int val = enable ? 1 : 0; u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PFR); if (FXGMAC_GET_REG_BITS(regval, MAC_PFR_PM_POS, MAC_PFR_PM_LEN) == val) { return 0; } netif_dbg(pdata, drv, pdata->netdev, ""STR_FORMAT" allmulti mode\n", enable ? "entering" : "leaving"); regval = FXGMAC_SET_REG_BITS(regval, MAC_PFR_PM_POS, MAC_PFR_PM_LEN, val); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PFR); DbgPrintF(MP_TRACE, ""STR_FORMAT" - Enable all Multicast=%d, regval=%#x.", __FUNCTION__, enable, regval); return 0; } static void fxgmac_set_mac_addn_addrs(struct fxgmac_pdata *pdata) { #ifndef DPDK #if FXGMAC_FILTER_MULTIPLE_MAC_ADDR_ENABLED struct net_device *netdev = pdata->netdev; struct netdev_hw_addr *ha; #endif unsigned int addn_macs; unsigned int mac_reg; mac_reg = MAC_MACA1HR; addn_macs = pdata->hw_feat.addn_mac; #if FXGMAC_FILTER_MULTIPLE_MAC_ADDR_ENABLED DPRINTK("xlgamc add mac addr callin\n"); if (netdev_uc_count(netdev) > addn_macs) { fxgmac_set_promiscuous_mode(pdata, 1); } else { netdev_for_each_uc_addr(ha, netdev) { fxgmac_set_mac_reg(pdata, ha, &mac_reg); addn_macs--; } if (netdev_mc_count(netdev) > addn_macs) { fxgmac_set_all_multicast_mode(pdata, 1); } else { netdev_for_each_mc_addr(ha, netdev) { fxgmac_set_mac_reg(pdata, ha, &mac_reg); addn_macs--; } } } #endif /* Clear remaining additional MAC address entries */ while (addn_macs--) { fxgmac_set_mac_reg(pdata, NULL, &mac_reg); } #else (void)pdata; #endif } #define GET_REG_AND_BIT_POS(reversalval, regOut, bitOut) \ do { \ regOut = (((reversalval) >> 5) & 0x7); \ bitOut = ((reversalval) & 0x1f); \ }while(0) static u32 fxgmac_crc32(unsigned char *Data, int Length) { u32 Crc = (u32)~0; /* Initial value. 0xFFFFFFFF */ while (--Length >= 0) { unsigned char Byte = *Data++; int Bit; for (Bit = 8; --Bit >= 0; Byte >>= 1) { if ((Crc ^ Byte) & 1) { Crc >>= 1; Crc ^= 0xedb88320; } else { Crc >>= 1; } } } return ~Crc; } /* * configure multicast hash table, reg 0x2010~202c * input: pmc_mac, pointer to mcast MAC. if it is null, then clean all registers. * b_add, 1 to set the bit; 0 to clear the bit. */ static void fxgmac_config_multicast_mac_hash_table(struct fxgmac_pdata *pdata, unsigned char *pmc_mac, int b_add) { unsigned int hash_reg, reg_bit; unsigned int j; u32 crc, reversal_crc, regval; if(!pmc_mac) { for(j = 0; j < FXGMAC_MAC_HASH_TABLE_SIZE; j++) { hash_reg = j; hash_reg = (MAC_HTR0 + hash_reg * MAC_HTR_INC); writereg(pdata->pAdapter, 0, pdata->mac_regs + hash_reg); //DBGPRINT(MP_TRACE, ("fxgmac_config_mcast_mac_hash_table, reg %04x=0x%x\n", FUXI_MAC_REGS_OFFSET + hash_reg, readreg(pdata->mac_regs + hash_reg))); } DBGPRINT(MP_TRACE, (">24), hash_reg, reg_bit); /* Set the MAC Hash Table registers */ hash_reg = (MAC_HTR0 + hash_reg * MAC_HTR_INC); regval = readreg(pdata->pAdapter, pdata->mac_regs + hash_reg); regval = FXGMAC_SET_REG_BITS(regval, reg_bit, 1, (b_add ? 1 : 0)); writereg(pdata->pAdapter, regval, pdata->mac_regs + hash_reg); #if 0 DBGPRINT(MP_TRACE, ("netdev; struct netdev_hw_addr *ha; #if 0 u32 hash_table[FXGMAC_MAC_HASH_TABLE_SIZE]; unsigned int hash_reg; unsigned int i; u32 crc; #endif netdev_for_each_mc_addr(ha, netdev) { fxgmac_config_multicast_mac_hash_table(pdata, ha->addr, 1); } #endif #if 0 //TODO hash_table_shift = 26 - (pdata->hw_feat.hash_table_size >> 7); hash_table_count = pdata->hw_feat.hash_table_size / 32; memset(hash_table, 0, sizeof(hash_table)); /* Build the MAC Hash Table register values */ netdev_for_each_uc_addr(ha, netdev) { crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)); crc >>= hash_table_shift; hash_table[crc >> 5] |= (1 << (crc & 0x1f)); } netdev_for_each_mc_addr(ha, netdev) { crc = bitrev32(~crc32_le(~0, ha->addr, ETH_ALEN)); crc >>= hash_table_shift; hash_table[crc >> 5] |= (1 << (crc & 0x1f)); } /* Set the MAC Hash Table registers */ hash_reg = MAC_HTR0; for (i = 0; i < hash_table_count; i++) { writereg(pdata->pAdapter, hash_table[i], pdata->mac_regs + hash_reg); hash_reg += MAC_HTR_INC; } //if(hash_table[i]) // DPRINTK("fxgmac_set_mac_hash_tabl[%d]=%08x.\n", i, hash_table[i]); #else pdata = pdata; #endif #else (void)pdata; #endif } static int fxgmac_add_mac_addresses(struct fxgmac_pdata *pdata) { if (pdata->hw_feat.hash_table_size) fxgmac_set_mac_hash_table(pdata); else fxgmac_set_mac_addn_addrs(pdata); return 0; } static void fxgmac_config_mac_address(struct fxgmac_pdata *pdata) { u32 regval; //KdBreakPoint(); fxgmac_set_mac_address(pdata, pdata->mac_addr); //fxgmac_set_mac_address(pdata, (u8*)"\x00\x55\x7b\xb5\x7d\xf7");// pdata->netdev->dev_addr); //fxgmac_set_mac_address(pdata, (u8*)"\xf7\x7d\xb5\x7b\x55\x00"); /* Filtering is done using perfect filtering and hash filtering */ if (pdata->hw_feat.hash_table_size) { regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PFR); regval = FXGMAC_SET_REG_BITS(regval, MAC_PFR_HPF_POS, MAC_PFR_HPF_LEN, 1); #if FUXI_MAC_HASH_TABLE regval = FXGMAC_SET_REG_BITS(regval, MAC_PFR_HUC_POS, MAC_PFR_HUC_LEN, 1); #endif regval = FXGMAC_SET_REG_BITS(regval, MAC_PFR_HMC_POS, MAC_PFR_HMC_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PFR); } } static int fxgmac_config_crc_check(struct fxgmac_pdata *pdata) { u32 regval, value; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_ECR); value = (pdata->crc_check) ? 0 : 1; regval = FXGMAC_SET_REG_BITS(regval, MAC_ECR_DCRCC_POS, MAC_ECR_DCRCC_LEN, value); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_ECR); return 0; } static int fxgmac_config_jumbo(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_JE_POS, MAC_CR_JE_LEN, pdata->jumbo); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); return 0; } static void fxgmac_config_checksum_offload(struct fxgmac_pdata *pdata) { #ifdef LINUX if (pdata->netdev->features & NETIF_F_RXCSUM) #else if (1) #endif fxgmac_enable_rx_csum(pdata); else fxgmac_disable_rx_csum(pdata); } static void fxgmac_config_vlan_support(struct fxgmac_pdata *pdata) { /*if (pdata->vlan_exist) fxgmac_enable_tx_vlan(pdata); else*/ fxgmac_disable_tx_vlan(pdata); // configure dynamical vlanID from TX Context. /* Set the current VLAN Hash Table register value */ fxgmac_update_vlan_hash_table(pdata); //2022-04-26 xiaojiang comment //Windows driver set vlan_filter disable, but in Linux driver it enable vlan_filter if (pdata->vlan_filter) //disable vlan rx filter by default fxgmac_enable_rx_vlan_filtering(pdata); else fxgmac_disable_rx_vlan_filtering(pdata); if (pdata->vlan_strip) //enable vlan rx strip by default fxgmac_enable_rx_vlan_stripping(pdata); else fxgmac_disable_rx_vlan_stripping(pdata); } static int fxgmac_config_rx_mode(struct fxgmac_pdata *pdata) { #ifdef LINUX struct net_device *netdev = pdata->netdev; #endif unsigned int pr_mode, am_mode; #ifdef LINUX pr_mode = ((netdev->flags & IFF_PROMISC) != 0); am_mode = ((netdev->flags & IFF_ALLMULTI) != 0); #else pr_mode = 1;// ((netdev->flags & IFF_PROMISC) != 0); //TODO am_mode = 1;// ((netdev->flags & IFF_ALLMULTI) != 0);//TODO #endif fxgmac_set_promiscuous_mode(pdata, pr_mode); fxgmac_set_all_multicast_mode(pdata, am_mode); fxgmac_add_mac_addresses(pdata); return 0; } static void fxgmac_prepare_tx_stop(struct fxgmac_pdata *pdata, struct fxgmac_channel *channel) { #ifdef LINUX unsigned int tx_dsr, tx_pos, tx_qidx; unsigned long tx_timeout; unsigned int tx_status; pdata = pdata; /* Calculate the status register to read and the position within */ if (channel->queue_index < DMA_DSRX_FIRST_QUEUE) { tx_dsr = DMA_DSR0; tx_pos = (channel->queue_index * DMA_DSR_Q_LEN) + DMA_DSR0_TPS_START; } else { tx_qidx = channel->queue_index - DMA_DSRX_FIRST_QUEUE; tx_dsr = DMA_DSR1 + ((tx_qidx / DMA_DSRX_QPR) * DMA_DSRX_INC); tx_pos = ((tx_qidx % DMA_DSRX_QPR) * DMA_DSR_Q_LEN) + DMA_DSRX_TPS_START; } //2022-04-19 xiaojiang comment //Windows os not have wait Tx Stop operation. /* The Tx engine cannot be stopped if it is actively processing * descriptors. Wait for the Tx engine to enter the stopped or * suspended state. Don't wait forever though... */ #if FXGMAC_TX_HANG_TIMER_EN tx_timeout = jiffies + msecs_to_jiffies(100); /* 100ms */ #else tx_timeout = jiffies + (FXGMAC_DMA_STOP_TIMEOUT * HZ); #endif while (time_before(jiffies, tx_timeout)) { tx_status = readreg(pdata->pAdapter, pdata->mac_regs + tx_dsr); tx_status = FXGMAC_GET_REG_BITS(tx_status, tx_pos, DMA_DSR_TPS_LEN); if ((tx_status == DMA_TPS_STOPPED) || (tx_status == DMA_TPS_SUSPENDED)) break; usleep_range_ex(pdata->pAdapter, 500, 1000); } if (!time_before(jiffies, tx_timeout)) netdev_info(pdata->netdev, "timed out waiting for Tx DMA channel %u to stop\n", channel->queue_index); #else pdata = pdata; channel = channel; #endif } static void fxgmac_enable_tx(struct fxgmac_pdata *pdata) { #ifndef DPDK struct fxgmac_channel *channel; #endif unsigned int i; u32 regval; #if FXGMAC_TX_HANG_TIMER_EN pdata->tx_hang_restart_queuing = 0; #endif /* Enable each Tx DMA channel */ #ifndef DPDK channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { #ifndef UBOOT //uboot unuse tx_ring if (!channel->tx_ring) break; #endif regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_TCR_ST_POS, DMA_CH_TCR_ST_LEN, 1); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); } #else PMD_INIT_FUNC_TRACE(); struct fxgmac_tx_queue *txq; struct rte_eth_dev *dev = pdata->expansion.eth_dev; for (i = 0; i < dev->data->nb_tx_queues; i++) { txq = dev->data->tx_queues[i]; /* Enable Tx DMA channel */ FXGMAC_DMA_IOWRITE_BITS(txq, DMA_CH_TCR, ST, 1); } #endif /* Enable each Tx queue */ for (i = 0; i < pdata->tx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_TXQEN_POS, MTL_Q_TQOMR_TXQEN_LEN, MTL_Q_ENABLED); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); } /* Enable MAC Tx */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_TE_POS, MAC_CR_TE_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); } static void fxgmac_disable_tx(struct fxgmac_pdata *pdata) { #ifndef DPDK struct fxgmac_channel *channel; #endif unsigned int i; u32 regval; /* Prepare for Tx DMA channel stop */ #ifndef DPDK channel = pdata->channel_head; if (channel != NULL) { for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->tx_ring) break; fxgmac_prepare_tx_stop(pdata, channel); #if FXGMAC_TX_HANG_TIMER_EN pdata->tx_hang_restart_queuing = 0; #endif } } #else PMD_INIT_FUNC_TRACE(); struct fxgmac_tx_queue *txq; struct rte_eth_dev *dev = pdata->expansion.eth_dev; for (i = 0; i < pdata->tx_q_count; i++) { txq = dev->data->tx_queues[i]; fxgmac_txq_prepare_tx_stop(pdata, i); } #endif /* Disable MAC Tx */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_TE_POS, MAC_CR_TE_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); /* Disable each Tx queue */ for (i = 0; i < pdata->tx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_TXQEN_POS, MTL_Q_TQOMR_TXQEN_LEN, 0); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); } /* Disable each Tx DMA channel */ #ifndef DPDK channel = pdata->channel_head; if (channel != NULL) { for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->tx_ring) break; regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_TCR_ST_POS, DMA_CH_TCR_ST_LEN, 0); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); } } #else for (i = 0; i < dev->data->nb_tx_queues; i++) { txq = dev->data->tx_queues[i]; FXGMAC_DMA_IOWRITE_BITS(txq, DMA_CH_TCR, ST, 0); } #endif } static void fxgmac_prepare_rx_stop(struct fxgmac_pdata *pdata, unsigned int queue) { unsigned int rx_status, prxq; #if defined(LINUX) || defined(DPDK) unsigned int rxqsts; unsigned long rx_timeout; #if defined(DPDK) unsigned long jiffies = rte_get_timer_cycles(); #endif /* The Rx engine cannot be stopped if it is actively processing * packets. Wait for the Rx queue to empty the Rx fifo. Don't * wait forever though... */ #if FXGMAC_TX_HANG_TIMER_EN rx_timeout = jiffies + msecs_to_jiffies(500); /* 500ms, larger is better */ #else rx_timeout = jiffies + (FXGMAC_DMA_STOP_TIMEOUT * HZ); #endif while (time_before(jiffies, rx_timeout)) { rx_status = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, queue, MTL_Q_RQDR)); prxq = FXGMAC_GET_REG_BITS(rx_status, MTL_Q_RQDR_PRXQ_POS, MTL_Q_RQDR_PRXQ_LEN); rxqsts = FXGMAC_GET_REG_BITS(rx_status, MTL_Q_RQDR_RXQSTS_POS, MTL_Q_RQDR_RXQSTS_LEN); if ((prxq == 0) && (rxqsts == 0)) break; usleep_range_ex(pdata->pAdapter, 500, 1000); } if (!time_before(jiffies, rx_timeout)) netdev_info(pdata->netdev, "timed out waiting for Rx queue %u to empty\n", queue); #else unsigned int busy = 100; do { rx_status = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, queue, MTL_Q_RQDR)); prxq = FXGMAC_GET_REG_BITS(rx_status, MTL_Q_RQDR_PRXQ_POS, MTL_Q_RQDR_PRXQ_LEN); busy--; usleep_range_ex(pdata->pAdapter, 500, 1000); } while ((prxq) && (busy)); if (0 == busy) { rx_status = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, queue, MTL_Q_RQDR)); DbgPrintF(MP_WARN, "warning !!!timed out waiting for Rx queue %u to empty\n", queue); } #endif } static void fxgmac_enable_rx(struct fxgmac_pdata *pdata) { #ifndef DPDK struct fxgmac_channel *channel; #endif unsigned int regval, i; /* Enable each Rx DMA channel */ #ifndef DPDK channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { #ifndef UBOOT //uboot unuse rx_ring if (!channel->rx_ring) break; #endif regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_RCR_SR_POS, DMA_CH_RCR_SR_LEN, 1); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); } #else PMD_INIT_FUNC_TRACE(); struct fxgmac_rx_queue *rxq; struct rte_eth_dev *dev = pdata->expansion.eth_dev; //struct fxgmac_pdata *pdata = pdata->dev->data->dev_private; for (i = 0; i < dev->data->nb_rx_queues; i++) { rxq = dev->data->rx_queues[i]; /* Enable Rx DMA channel */ FXGMAC_DMA_IOWRITE_BITS(rxq, DMA_CH_RCR, SR, 1); } #endif /* Enable each Rx queue */ regval = 0; for (i = 0; i < pdata->rx_q_count; i++) regval |= (0x02 << (i << 1)); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_RQC0R); #ifndef DPDK /* Enable MAC Rx */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_CST_POS, MAC_CR_CST_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_ACS_POS, MAC_CR_ACS_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_RE_POS, MAC_CR_RE_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); #else /* Enable MAC Rx */ FXGMAC_IOWRITE_BITS(pdata, MAC_ECR, DCRCC, 1); /* Frame is forwarded after stripping CRC to application*/ if (pdata->expansion.crc_strip_enable) { FXGMAC_IOWRITE_BITS(pdata, MAC_CR, CST, 1); FXGMAC_IOWRITE_BITS(pdata, MAC_CR, ACS, 1); } FXGMAC_IOWRITE_BITS(pdata, MAC_CR, RE, 1); #endif } static void fxgmac_enable_channel_rx(struct fxgmac_pdata* pdata, unsigned int queue) { struct fxgmac_channel* channel; unsigned int regval; /* Enable Rx DMA channel */ channel = pdata->channel_head + queue; if (!channel->rx_ring) return; regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_RCR_SR_POS, DMA_CH_RCR_SR_LEN, 1); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); /* Enable Rx queue */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_RQC0R); regval |= (0x02 << (queue << 1)); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_RQC0R); /* Enable MAC Rx */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); if (!(regval&((0x01<< MAC_CR_CST_POS)|(0x01 << MAC_CR_ACS_POS)|(0x01<< MAC_CR_RE_POS)))) { regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_CST_POS, MAC_CR_CST_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_ACS_POS, MAC_CR_ACS_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_RE_POS, MAC_CR_RE_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); } } static void fxgmac_disable_rx(struct fxgmac_pdata *pdata) { #ifndef DPDK struct fxgmac_channel *channel; #endif unsigned int i; u32 regval; /* Disable MAC Rx */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_CST_POS, MAC_CR_CST_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_ACS_POS, MAC_CR_ACS_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_RE_POS, MAC_CR_RE_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); /* Prepare for Rx DMA channel stop */ #ifndef DPDK for (i = 0; i < pdata->rx_q_count; i++) fxgmac_prepare_rx_stop(pdata, i); #else PMD_INIT_FUNC_TRACE(); struct fxgmac_rx_queue *rxq; struct rte_eth_dev *dev = pdata->expansion.eth_dev; for (i = 0; i < dev->data->nb_rx_queues; i++) { rxq = dev->data->rx_queues[i]; fxgmac_prepare_rx_stop(pdata, i); } #endif /* Disable each Rx queue */ writereg(pdata->pAdapter, 0, pdata->mac_regs + MAC_RQC0R); /* Disable each Rx DMA channel */ #ifndef DPDK channel = pdata->channel_head; if (channel != NULL) { for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->rx_ring) break; regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_RCR_SR_POS, DMA_CH_RCR_SR_LEN, 0); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); } } #else for (i = 0; i < dev->data->nb_rx_queues; i++) { rxq = dev->data->rx_queues[i]; FXGMAC_DMA_IOWRITE_BITS(rxq, DMA_CH_RCR, SR, 0); } #endif } #ifdef LINUX static void fxgmac_tx_start_xmit(struct fxgmac_channel *channel, struct fxgmac_ring *ring) { struct fxgmac_pdata *pdata = channel->pdata; struct fxgmac_desc_data *desc_data; /* Make sure everything is written before the register write */ wmb(); /* Issue a poll command to Tx DMA by writing address * of next immediate free descriptor */ desc_data = FXGMAC_GET_DESC_DATA(ring, ring->cur); //DPRINTK("tx_start_xmit: dump before wr reg,descs-%08x,%08x,%08x,%08x\n",desc_data->dma_desc->desc0,desc_data->dma_desc->desc1,desc_data->dma_desc->desc2,desc_data->dma_desc->desc3); #if !(FXGMAC_DUMMY_TX_DEBUG) writereg(pdata->pAdapter, lower_32_bits(desc_data->dma_desc_addr), FXGMAC_DMA_REG(channel, DMA_CH_TDTR_LO)); #else DPRINTK("dummy tx, fxgmac_tx_start_xmit, tail reg=0x%lx,val=%08x\n", FXGMAC_DMA_REG(channel, DMA_CH_TDTR_LO) - pdata->mac_regs, (u32)lower_32_bits(desc_data->dma_desc_addr)); #endif if(netif_msg_tx_done(pdata)) DPRINTK("tx_start_xmit: dump before wr reg,dma base=0x%016llx,reg=0x%08x, tx timer usecs=%u,tx_timer_active=%u\n", desc_data->dma_desc_addr, readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_TDTR_LO)), pdata->tx_usecs, channel->tx_timer_active); ring->tx.xmit_more = 0; } #endif #ifdef LINUX static void fxgmac_dev_xmit(struct fxgmac_channel *channel) { struct fxgmac_pdata *pdata = channel->pdata; struct fxgmac_ring *ring = channel->tx_ring; unsigned int tso_context, vlan_context; struct fxgmac_desc_data *desc_data; struct fxgmac_dma_desc *dma_desc; struct fxgmac_pkt_info *pkt_info; unsigned int csum, tso, vlan; int start_index = ring->cur; int cur_index = ring->cur; int i; if(netif_msg_tx_done(pdata)) DPRINTK("dev_xmit callin, desc cur=%d\n", cur_index); pkt_info = &ring->pkt_info; csum = FXGMAC_GET_REG_BITS(pkt_info->attributes, TX_PACKET_ATTRIBUTES_CSUM_ENABLE_POS, TX_PACKET_ATTRIBUTES_CSUM_ENABLE_LEN); tso = FXGMAC_GET_REG_BITS(pkt_info->attributes, TX_PACKET_ATTRIBUTES_TSO_ENABLE_POS, TX_PACKET_ATTRIBUTES_TSO_ENABLE_LEN); vlan = FXGMAC_GET_REG_BITS(pkt_info->attributes, TX_PACKET_ATTRIBUTES_VLAN_CTAG_POS, TX_PACKET_ATTRIBUTES_VLAN_CTAG_LEN); if (tso && (pkt_info->mss != ring->tx.cur_mss)) tso_context = 1; else tso_context = 0; //if(tso && (netif_msg_tx_done(pdata))) if((tso_context) && (netif_msg_tx_done(pdata))) { //tso is initialized to start... DPRINTK("fxgmac_dev_xmit,tso_%s tso=0x%x,pkt_mss=%d,cur_mss=%d\n",(pkt_info->mss)?"start":"stop", tso, pkt_info->mss, ring->tx.cur_mss); } if (vlan && (pkt_info->vlan_ctag != ring->tx.cur_vlan_ctag)) vlan_context = 1; else vlan_context = 0; if(vlan && (netif_msg_tx_done(pdata))) DPRINTK("fxgmac_dev_xmi:pkt vlan=%d, ring vlan=%d, vlan_context=%d\n", pkt_info->vlan_ctag, ring->tx.cur_vlan_ctag, vlan_context); desc_data = FXGMAC_GET_DESC_DATA(ring, cur_index); dma_desc = desc_data->dma_desc; /* Create a context descriptor if this is a TSO pkt_info */ if (tso_context || vlan_context) { if (tso_context) { #if 0 netif_dbg(pdata, tx_queued, pdata->netdev, "TSO context descriptor, mss=%u\n", pkt_info->mss); #else if (netif_msg_tx_done(pdata)) DPRINTK("xlgamc dev xmit,construct tso context descriptor, mss=%u\n", pkt_info->mss); #endif /* Set the MSS size */ dma_desc->desc2 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc2, TX_CONTEXT_DESC2_MSS_POS, TX_CONTEXT_DESC2_MSS_LEN, pkt_info->mss); /* Mark it as a CONTEXT descriptor */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_CONTEXT_DESC3_CTXT_POS, TX_CONTEXT_DESC3_CTXT_LEN, 1); /* Indicate this descriptor contains the MSS */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_CONTEXT_DESC3_TCMSSV_POS, TX_CONTEXT_DESC3_TCMSSV_LEN, 1); ring->tx.cur_mss = pkt_info->mss; } if (vlan_context) { netif_dbg(pdata, tx_queued, pdata->netdev, "VLAN context descriptor, ctag=%u\n", pkt_info->vlan_ctag); /* Mark it as a CONTEXT descriptor */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_CONTEXT_DESC3_CTXT_POS, TX_CONTEXT_DESC3_CTXT_LEN, 1); /* Set the VLAN tag */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_CONTEXT_DESC3_VT_POS, TX_CONTEXT_DESC3_VT_LEN, pkt_info->vlan_ctag); /* Indicate this descriptor contains the VLAN tag */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_CONTEXT_DESC3_VLTV_POS, TX_CONTEXT_DESC3_VLTV_LEN, 1); ring->tx.cur_vlan_ctag = pkt_info->vlan_ctag; } //cur_index++; cur_index = FXGMAC_GET_ENTRY(cur_index, ring->dma_desc_count); desc_data = FXGMAC_GET_DESC_DATA(ring, cur_index); dma_desc = desc_data->dma_desc; } /* Update buffer address (for TSO this is the header) */ dma_desc->desc0 = cpu_to_le32(lower_32_bits(desc_data->skb_dma)); dma_desc->desc1 = cpu_to_le32(upper_32_bits(desc_data->skb_dma)); /* Update the buffer length */ dma_desc->desc2 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc2, TX_NORMAL_DESC2_HL_B1L_POS, TX_NORMAL_DESC2_HL_B1L_LEN, desc_data->skb_dma_len); /* VLAN tag insertion check */ if (vlan) { dma_desc->desc2 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc2, TX_NORMAL_DESC2_VTIR_POS, TX_NORMAL_DESC2_VTIR_LEN, TX_NORMAL_DESC2_VLAN_INSERT); pdata->stats.tx_vlan_packets++; } /* Timestamp enablement check */ if (FXGMAC_GET_REG_BITS(pkt_info->attributes, TX_PACKET_ATTRIBUTES_PTP_POS, TX_PACKET_ATTRIBUTES_PTP_LEN)) dma_desc->desc2 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc2, TX_NORMAL_DESC2_TTSE_POS, TX_NORMAL_DESC2_TTSE_LEN, 1); /* Mark it as First Descriptor */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_FD_POS, TX_NORMAL_DESC3_FD_LEN, 1); /* Mark it as a NORMAL descriptor */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_CTXT_POS, TX_NORMAL_DESC3_CTXT_LEN, 0); /* Set OWN bit if not the first descriptor */ if (cur_index != start_index) dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_OWN_POS, TX_NORMAL_DESC3_OWN_LEN, 1); if (tso) { /* Enable TSO */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_TSE_POS, TX_NORMAL_DESC3_TSE_LEN, 1); dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_TCPPL_POS, TX_NORMAL_DESC3_TCPPL_LEN, pkt_info->tcp_payload_len); dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_TCPHDRLEN_POS, TX_NORMAL_DESC3_TCPHDRLEN_LEN, pkt_info->tcp_header_len / 4); pdata->stats.tx_tso_packets++; } else { /* Enable CRC and Pad Insertion */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_CPC_POS, TX_NORMAL_DESC3_CPC_LEN, 0); /* Enable HW CSUM */ if (csum) dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_CIC_POS, TX_NORMAL_DESC3_CIC_LEN, 0x3); /* Set the total length to be transmitted */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_FL_POS, TX_NORMAL_DESC3_FL_LEN, pkt_info->length); } if(netif_msg_tx_done(pdata)) DPRINTK("dev_xmit before more descs, desc cur=%d, start=%d, desc=%#x,%#x,%#x,%#x\n", cur_index, start_index, dma_desc->desc0, dma_desc->desc1, dma_desc->desc2, dma_desc->desc3); if (start_index <= cur_index) i = cur_index - start_index + 1; else i = ring->dma_desc_count - start_index + cur_index; for (; i < pkt_info->desc_count; i++) { cur_index = FXGMAC_GET_ENTRY(cur_index, ring->dma_desc_count); desc_data = FXGMAC_GET_DESC_DATA(ring, cur_index); dma_desc = desc_data->dma_desc; /* Update buffer address */ dma_desc->desc0 = cpu_to_le32(lower_32_bits(desc_data->skb_dma)); dma_desc->desc1 = cpu_to_le32(upper_32_bits(desc_data->skb_dma)); /* Update the buffer length */ dma_desc->desc2 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc2, TX_NORMAL_DESC2_HL_B1L_POS, TX_NORMAL_DESC2_HL_B1L_LEN, desc_data->skb_dma_len); /* Set OWN bit */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_OWN_POS, TX_NORMAL_DESC3_OWN_LEN, 1); /* Mark it as NORMAL descriptor */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_CTXT_POS, TX_NORMAL_DESC3_CTXT_LEN, 0); /* Enable HW CSUM */ if (csum) dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_CIC_POS, TX_NORMAL_DESC3_CIC_LEN, 0x3); } /* Set LAST bit for the last descriptor */ dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_LD_POS, TX_NORMAL_DESC3_LD_LEN, 1); dma_desc->desc2 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc2, TX_NORMAL_DESC2_IC_POS, TX_NORMAL_DESC2_IC_LEN, 1); /* Save the Tx info to report back during cleanup */ desc_data->tx.packets = pkt_info->tx_packets; desc_data->tx.bytes = pkt_info->tx_bytes; if(netif_msg_tx_done(pdata)) DPRINTK("dev_xmit last descs, desc cur=%d, desc=%#x,%#x,%#x,%#x\n", cur_index, dma_desc->desc0, dma_desc->desc1, dma_desc->desc2, dma_desc->desc3); /* In case the Tx DMA engine is running, make sure everything * is written to the descriptor(s) before setting the OWN bit * for the first descriptor */ dma_wmb(); /* Set OWN bit for the first descriptor */ desc_data = FXGMAC_GET_DESC_DATA(ring, start_index); dma_desc = desc_data->dma_desc; dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, TX_NORMAL_DESC3_OWN_POS, TX_NORMAL_DESC3_OWN_LEN, 1); if(netif_msg_tx_done(pdata)) DPRINTK("dev_xmit first descs, start=%d, desc=%#x,%#x,%#x,%#x\n", start_index, dma_desc->desc0, dma_desc->desc1, dma_desc->desc2, dma_desc->desc3); if (netif_msg_tx_queued(pdata)) fxgmac_dump_tx_desc(pdata, ring, start_index, pkt_info->desc_count, 1); #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) ) if(netif_msg_tx_done(pdata)) DPRINTK("dev_xmit about to call tx_start_xmit, ring xmit_more=%d,txq_stopped=%x\n",ring->tx.xmit_more, netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev, channel->queue_index))); #else /* ( LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,165) )*/ if(netif_msg_tx_done(pdata)) DPRINTK("dev_xmit about to call tx_start_xmit, pkt xmit_more=%d,txq_stopped=%x\n",pkt_info->skb->xmit_more, netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev, channel->queue_index))); #endif /* Make sure ownership is written to the descriptor */ smp_wmb(); //ring->cur = cur_index + 1; ring->cur = FXGMAC_GET_ENTRY(cur_index, ring->dma_desc_count); #if 0 #if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) ) if (!ring->tx.xmit_more || netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev, channel->queue_index))) #elif ( LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,1) ) if (!pkt_info->skb->xmit_more || netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev, channel->queue_index))) #else if (netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev, channel->queue_index))) #endif { fxgmac_tx_start_xmit(channel, ring); } else ring->tx.xmit_more = 1; #endif fxgmac_tx_start_xmit(channel, ring); /* yzhang for reduce debug output */ if(netif_msg_tx_done(pdata)){ DPRINTK("dev_xmit callout %s: descriptors %u to %u written\n", channel->name, start_index & (ring->dma_desc_count - 1), (ring->cur - 1) & (ring->dma_desc_count - 1)); } } #endif #ifdef LINUX static void fxgmac_get_rx_tstamp(struct fxgmac_pkt_info *pkt_info, struct fxgmac_dma_desc *dma_desc) { //u32 tsa, tsd; u64 nsec; #if 0 tsa = FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_CONTEXT_DESC3_TSA_POS, RX_CONTEXT_DESC3_TSA_LEN); tsd = FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_CONTEXT_DESC3_TSD_POS, RX_CONTEXT_DESC3_TSD_LEN); if (tsa && !tsd) { #endif nsec = le32_to_cpu(dma_desc->desc1); nsec <<= 32; nsec |= le32_to_cpu(dma_desc->desc0); if (nsec != 0xffffffffffffffffULL) { pkt_info->rx_tstamp = nsec; pkt_info->attributes = FXGMAC_SET_REG_BITS( pkt_info->attributes, RX_PACKET_ATTRIBUTES_RX_TSTAMP_POS, RX_PACKET_ATTRIBUTES_RX_TSTAMP_LEN, 1); } //} } #endif static void fxgmac_tx_desc_reset(struct fxgmac_desc_data *desc_data) { struct fxgmac_dma_desc *dma_desc = desc_data->dma_desc; /* Reset the Tx descriptor * Set buffer 1 (lo) address to zero * Set buffer 1 (hi) address to zero * Reset all other control bits (IC, TTSE, B2L & B1L) * Reset all other control bits (OWN, CTXT, FD, LD, CPC, CIC, etc) */ dma_desc->desc0 = 0; dma_desc->desc1 = 0; dma_desc->desc2 = 0; dma_desc->desc3 = 0; /* Make sure ownership is written to the descriptor */ dma_wmb(); } static void fxgmac_tx_desc_init(struct fxgmac_channel *channel) { struct fxgmac_ring *ring = channel->tx_ring; struct fxgmac_desc_data *desc_data; int start_index = ring->cur; unsigned int i; start_index = start_index; //DEBUGPRINT(INIT, "["STR_FORMAT","STR_FORMAT",%d]:dma_desc_count=%d,0x%x\n",__FILE__, __func__,__LINE__,ring->dma_desc_count,channel->tx_ring); /* Initialize all descriptors */ for (i = 0; i < ring->dma_desc_count; i++) { desc_data = FXGMAC_GET_DESC_DATA(ring, i); /* Initialize Tx descriptor */ fxgmac_tx_desc_reset(desc_data); } ///* Update the total number of Tx descriptors */ //writereg(ring->dma_desc_count - 1, FXGMAC_DMA_REG(channel, DMA_CH_TDRLR)); writereg(channel->pdata->pAdapter, channel->pdata->tx_desc_count - 1, FXGMAC_DMA_REG(channel, DMA_CH_TDRLR)); /* Update the starting address of descriptor ring */ #if defined(LINUX) desc_data = FXGMAC_GET_DESC_DATA(ring, start_index); writereg(channel->pdata->pAdapter, upper_32_bits(desc_data->dma_desc_addr), FXGMAC_DMA_REG(channel, DMA_CH_TDLR_HI)); writereg(channel->pdata->pAdapter, lower_32_bits(desc_data->dma_desc_addr), FXGMAC_DMA_REG(channel, DMA_CH_TDLR_LO)); #elif defined(UEFI) writereg(channel->pdata->pAdapter, GetPhyAddrHigh(((PADAPTER)channel->pdata->pAdapter)->TbdPhyAddr),//adpt->TbdPhyAddr FXGMAC_DMA_REG(channel, DMA_CH_TDLR_HI)); writereg(channel->pdata->pAdapter, GetPhyAddrLow(((PADAPTER)channel->pdata->pAdapter)->TbdPhyAddr), FXGMAC_DMA_REG(channel, DMA_CH_TDLR_LO)); #elif defined(PXE) #elif defined(UBOOT) #elif defined(DPDK) #else //netadaptercx & ndis writereg(channel->pdata->pAdapter, NdisGetPhysicalAddressHigh(((PMP_ADAPTER)channel->pdata->pAdapter)->HwTbdBasePa), FXGMAC_DMA_REG(channel, DMA_CH_TDLR_HI)); writereg(channel->pdata->pAdapter, NdisGetPhysicalAddressLow(((PMP_ADAPTER)channel->pdata->pAdapter)->HwTbdBasePa), FXGMAC_DMA_REG(channel, DMA_CH_TDLR_LO)); #endif } static void fxgmac_rx_desc_reset(struct fxgmac_pdata *pdata, struct fxgmac_desc_data *desc_data, unsigned int index) { #ifdef LINUX struct fxgmac_dma_desc *dma_desc = desc_data->dma_desc; /* Reset the Rx descriptor * Set buffer 1 (lo) address to header dma address (lo) * Set buffer 1 (hi) address to header dma address (hi) * Set buffer 2 (lo) address to buffer dma address (lo) * Set buffer 2 (hi) address to buffer dma address (hi) and * set control bits OWN and INTE */ //hdr_dma = desc_data->rx.hdr.dma_base + desc_data->rx.hdr.dma_off; //buf_dma = desc_data->rx.buf.dma_base + desc_data->rx.buf.dma_off; dma_desc->desc0 = cpu_to_le32(lower_32_bits(desc_data->rx.buf.dma_base)); dma_desc->desc1 = cpu_to_le32(upper_32_bits(desc_data->rx.buf.dma_base)); dma_desc->desc2 = 0;//cpu_to_le32(lower_32_bits(buf_dma)); dma_desc->desc3 = 0;//cpu_to_le32(upper_32_bits(buf_dma)); dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, RX_NORMAL_DESC3_INTE_POS, RX_NORMAL_DESC3_INTE_LEN, 1); dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, RX_NORMAL_DESC3_BUF2V_POS, RX_NORMAL_DESC3_BUF2V_LEN, 0); dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, RX_NORMAL_DESC3_BUF1V_POS, RX_NORMAL_DESC3_BUF1V_LEN, 1); /* Since the Rx DMA engine is likely running, make sure everything * is written to the descriptor(s) before setting the OWN bit * for the descriptor */ dma_wmb(); dma_desc->desc3 = FXGMAC_SET_REG_BITS_LE( dma_desc->desc3, RX_NORMAL_DESC3_OWN_POS, RX_NORMAL_DESC3_OWN_LEN, 1); /* Make sure ownership is written to the descriptor */ dma_wmb(); #else pdata = pdata; desc_data = desc_data; index = index; #endif } static void fxgmac_rx_desc_init(struct fxgmac_channel *channel) { struct fxgmac_pdata *pdata = channel->pdata; struct fxgmac_ring *ring = channel->rx_ring; #ifdef LINUX unsigned int start_index = ring->cur; #endif struct fxgmac_desc_data *desc_data; unsigned int i; #if defined(UEFI) UINT64 HwRbdPa; #elif defined(_WIN64) || defined(_WIN32) unsigned int Qid; NDIS_PHYSICAL_ADDRESS HwRbdPa; #elif defined(PXE) #endif /* Initialize all descriptors */ for (i = 0; i < ring->dma_desc_count; i++) { desc_data = FXGMAC_GET_DESC_DATA(ring, i); /* Initialize Rx descriptor */ fxgmac_rx_desc_reset(pdata, desc_data, i); } #if defined(LINUX) /* Update the total number of Rx descriptors */ writereg(pdata->pAdapter, ring->dma_desc_count - 1, FXGMAC_DMA_REG(channel, DMA_CH_RDRLR)); /* Update the starting address of descriptor ring */ desc_data = FXGMAC_GET_DESC_DATA(ring, start_index); writereg(pdata->pAdapter, upper_32_bits(desc_data->dma_desc_addr), FXGMAC_DMA_REG(channel, DMA_CH_RDLR_HI)); writereg(pdata->pAdapter, lower_32_bits(desc_data->dma_desc_addr), FXGMAC_DMA_REG(channel, DMA_CH_RDLR_LO)); /* Update the Rx Descriptor Tail Pointer */ desc_data = FXGMAC_GET_DESC_DATA(ring, start_index + ring->dma_desc_count - 1); writereg(pdata->pAdapter, lower_32_bits(desc_data->dma_desc_addr), FXGMAC_DMA_REG(channel, DMA_CH_RDTR_LO)); #elif defined(UEFI) writereg(pdata->pAdapter, pdata->rx_desc_count - 1, FXGMAC_DMA_REG(channel, DMA_CH_RDRLR)); /* Update the starting address of descriptor ring */ writereg(pdata->pAdapter, GetPhyAddrHigh(((PADAPTER)channel->pdata->pAdapter)->RbdPhyAddr), FXGMAC_DMA_REG(channel, DMA_CH_RDLR_HI)); writereg(pdata->pAdapter, GetPhyAddrLow(((PADAPTER)channel->pdata->pAdapter)->RbdPhyAddr), FXGMAC_DMA_REG(channel, DMA_CH_RDLR_LO)); HwRbdPa = ((PADAPTER)channel->pdata->pAdapter)->RbdPhyAddr + (pdata->rx_desc_count - 1) * sizeof(struct fxgmac_dma_desc); /* Update the Rx Descriptor Tail Pointer */ writereg(pdata->pAdapter, GetPhyAddrLow(HwRbdPa), FXGMAC_DMA_REG(channel, DMA_CH_RDTR_LO)); #elif defined(PXE) #elif defined(UBOOT) #elif defined(DPDK) #else //netadaptercx & ndis Qid = (unsigned int)(channel - pdata->channel_head); DbgPrintF(MP_TRACE, ""STR_FORMAT": %d, Qid =%d\n", __FUNCTION__, __LINE__, Qid); writereg(channel->pdata->pAdapter, ((PMP_ADAPTER)channel->pdata->pAdapter)->RxQueue[Qid].NumHwRecvBuffers - 1, FXGMAC_DMA_REG(channel, DMA_CH_RDRLR)); /* Update the starting address of descriptor ring */ writereg(channel->pdata->pAdapter, NdisGetPhysicalAddressHigh(((PMP_ADAPTER)channel->pdata->pAdapter)->RxQueue[Qid].HwRbdBasePa), FXGMAC_DMA_REG(channel, DMA_CH_RDLR_HI)); writereg(channel->pdata->pAdapter, NdisGetPhysicalAddressLow(((PMP_ADAPTER)channel->pdata->pAdapter)->RxQueue[Qid].HwRbdBasePa), FXGMAC_DMA_REG(channel, DMA_CH_RDLR_LO)); #if defined(NIC_NET_ADAPETERCX) /* Update the Rx Descriptor Tail Pointer */ writereg(channel->pdata->pAdapter, NdisGetPhysicalAddressLow(((PMP_ADAPTER)channel->pdata->pAdapter)->RxQueue[Qid].HwRbdBasePa), FXGMAC_DMA_REG(channel, DMA_CH_RDTR_LO)); HwRbdPa.QuadPart = 0; #else HwRbdPa.QuadPart = ((PMP_ADAPTER)channel->pdata->pAdapter)->RxQueue[Qid].HwRbdBasePa.QuadPart + (((PMP_ADAPTER)channel->pdata->pAdapter)->RxQueue[Qid].NumHwRecvBuffers - 1) * sizeof(HW_RBD); /* Update the Rx Descriptor Tail Pointer */ writereg(channel->pdata->pAdapter, NdisGetPhysicalAddressLow(HwRbdPa), FXGMAC_DMA_REG(channel, DMA_CH_RDTR_LO)); #endif #endif } static int fxgmac_is_context_desc(struct fxgmac_dma_desc *dma_desc) { /* Rx and Tx share CTXT bit, so check TDES3.CTXT bit */ return FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, TX_NORMAL_DESC3_CTXT_POS, TX_NORMAL_DESC3_CTXT_LEN); } static int fxgmac_is_last_desc(struct fxgmac_dma_desc *dma_desc) { /* Rx and Tx share LD bit, so check TDES3.LD bit */ return FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, TX_NORMAL_DESC3_LD_POS, TX_NORMAL_DESC3_LD_LEN); } static int fxgmac_disable_tx_flow_control(struct fxgmac_pdata *pdata) { unsigned int max_q_count, q_count; unsigned int reg, regval; unsigned int i; /* Clear MTL flow control */ for (i = 0; i < pdata->rx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_EHFC_POS, MTL_Q_RQOMR_EHFC_LEN, 0); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); } /* Clear MAC flow control */ max_q_count = FXGMAC_MAX_FLOW_CONTROL_QUEUES; q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count); reg = MAC_Q0TFCR; for (i = 0; i < q_count; i++) { regval = readreg(pdata->pAdapter, pdata->mac_regs + reg); regval = FXGMAC_SET_REG_BITS(regval, MAC_Q0TFCR_TFE_POS, MAC_Q0TFCR_TFE_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + reg); reg += MAC_QTFCR_INC; } return 0; } static int fxgmac_enable_tx_flow_control(struct fxgmac_pdata *pdata) { unsigned int max_q_count, q_count; unsigned int reg, regval; unsigned int i; /* Set MTL flow control */ for (i = 0; i < pdata->rx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_EHFC_POS, MTL_Q_RQOMR_EHFC_LEN, 1); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); } /* Set MAC flow control */ max_q_count = FXGMAC_MAX_FLOW_CONTROL_QUEUES; q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count); reg = MAC_Q0TFCR; for (i = 0; i < q_count; i++) { regval = readreg(pdata->pAdapter, pdata->mac_regs + reg); /* Enable transmit flow control */ regval = FXGMAC_SET_REG_BITS(regval, MAC_Q0TFCR_TFE_POS, MAC_Q0TFCR_TFE_LEN, 1); /* Set pause time */ regval = FXGMAC_SET_REG_BITS(regval, MAC_Q0TFCR_PT_POS, MAC_Q0TFCR_PT_LEN, 0xffff); writereg(pdata->pAdapter, regval, pdata->mac_regs + reg); reg += MAC_QTFCR_INC; } return 0; } static int fxgmac_disable_rx_flow_control(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_RFCR); regval = FXGMAC_SET_REG_BITS(regval, MAC_RFCR_RFE_POS, MAC_RFCR_RFE_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_RFCR); return 0; } static int fxgmac_enable_rx_flow_control(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_RFCR); regval = FXGMAC_SET_REG_BITS(regval, MAC_RFCR_RFE_POS, MAC_RFCR_RFE_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_RFCR); return 0; } static int fxgmac_config_tx_flow_control(struct fxgmac_pdata *pdata) { if (pdata->tx_pause) fxgmac_enable_tx_flow_control(pdata); else fxgmac_disable_tx_flow_control(pdata); return 0; } static int fxgmac_config_rx_flow_control(struct fxgmac_pdata *pdata) { if (pdata->rx_pause) fxgmac_enable_rx_flow_control(pdata); else fxgmac_disable_rx_flow_control(pdata); return 0; } static int fxgmac_config_rx_coalesce(struct fxgmac_pdata *pdata) { #ifndef DPDK struct fxgmac_channel *channel; unsigned int i; u32 regval; channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->rx_ring) break; regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_RIWT)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_RIWT_RWT_POS, DMA_CH_RIWT_RWT_LEN, pdata->rx_riwt); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_RIWT)); } #else struct fxgmac_rx_queue *rxq; unsigned int i; for (i = 0; i < pdata->expansion.eth_dev->data->nb_rx_queues; i++) { rxq = pdata->expansion.eth_dev->data->rx_queues[i]; FXGMAC_DMA_IOWRITE_BITS(rxq, DMA_CH_RIWT, RWT, pdata->rx_riwt); } #endif return 0; } static void fxgmac_config_rx_fep_disable(struct fxgmac_pdata *pdata) { unsigned int i; u32 regval; for (i = 0; i < pdata->rx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_FEP_POS, MTL_Q_RQOMR_FEP_LEN, MTL_FEP_ENABLE);// 1:enable the rx queue forward packet with error status(crc error,gmii_er,watch dog timeout.or overflow) writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); } } static void fxgmac_config_rx_fup_enable(struct fxgmac_pdata *pdata) { unsigned int i; u32 regval; for (i = 0; i < pdata->rx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_FUP_POS, MTL_Q_RQOMR_FUP_LEN, 1); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); } } static int fxgmac_config_tx_coalesce(struct fxgmac_pdata *pdata) { pdata = pdata; return 0; } static void fxgmac_config_rx_buffer_size(struct fxgmac_pdata *pdata) { #ifndef DPDK struct fxgmac_channel *channel; unsigned int i; u32 regval; channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->rx_ring) break; regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_RCR_RBSZ_POS, DMA_CH_RCR_RBSZ_LEN, pdata->rx_buf_size); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); } #else struct fxgmac_rx_queue *rxq; unsigned int i; for (i = 0; i < pdata->expansion.eth_dev->data->nb_rx_queues; i++) { rxq = pdata->expansion.eth_dev->data->rx_queues[i]; rxq->buf_size = rte_pktmbuf_data_room_size(rxq->mb_pool) - RTE_PKTMBUF_HEADROOM; rxq->buf_size = (rxq->buf_size + FXGMAC_RX_BUF_ALIGN - 1) & ~(FXGMAC_RX_BUF_ALIGN - 1); if (rxq->buf_size > pdata->rx_buf_size) pdata->rx_buf_size = rxq->buf_size; FXGMAC_DMA_IOWRITE_BITS(rxq, DMA_CH_RCR, RBSZ, rxq->buf_size); } #endif } static void fxgmac_config_tso_mode(struct fxgmac_pdata *pdata) { #ifndef DPDK struct fxgmac_channel *channel; unsigned int i; u32 regval; channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->tx_ring) break; if (pdata->hw_feat.tso) { regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_TCR_TSE_POS, DMA_CH_TCR_TSE_LEN, 1); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); } } #else struct fxgmac_tx_queue *txq; unsigned int i; for (i = 0; i < pdata->expansion.eth_dev->data->nb_tx_queues; i++) { txq = pdata->expansion.eth_dev->data->tx_queues[i]; FXGMAC_DMA_IOWRITE_BITS(txq, DMA_CH_TCR, TSE, pdata->tx_pbl); } #endif } static void fxgmac_config_sph_mode(struct fxgmac_pdata *pdata) { unsigned int i; u32 regval; #ifndef DPDK struct fxgmac_channel *channel; channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->rx_ring) break; regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_CR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_CR_SPH_POS, DMA_CH_CR_SPH_LEN, 0); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_CR)); } #else struct fxgmac_rx_queue *rxq; for (i = 0; i < pdata->expansion.eth_dev->data->nb_rx_queues; i++) { rxq = pdata->expansion.eth_dev->data->rx_queues[i]; FXGMAC_DMA_IOWRITE_BITS(rxq, DMA_CH_CR, SPH, pdata->rx_pbl); } #endif regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_ECR); regval = FXGMAC_SET_REG_BITS(regval, MAC_ECR_HDSMS_POS, MAC_ECR_HDSMS_LEN, FXGMAC_SPH_HDSMS_SIZE); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_ECR); } static unsigned int fxgmac_usec_to_riwt(struct fxgmac_pdata *pdata, unsigned int usec) { unsigned long rate; unsigned int ret; rate = pdata->sysclk_rate; /* Convert the input usec value to the watchdog timer value. Each * watchdog timer value is equivalent to 256 clock cycles. * Calculate the required value as: * ( usec * ( system_clock_mhz / 10^6 ) / 256 */ ret = (usec * (rate / 1000000)) / 256; return ret; } static unsigned int fxgmac_riwt_to_usec(struct fxgmac_pdata *pdata, unsigned int riwt) { unsigned long rate; unsigned int ret; rate = pdata->sysclk_rate; /* Convert the input watchdog timer value to the usec value. Each * watchdog timer value is equivalent to 256 clock cycles. * Calculate the required value as: * ( riwt * 256 ) / ( system_clock_mhz / 10^6 ) */ ret = (riwt * 256) / (rate / 1000000); return ret; } static int fxgmac_config_rx_threshold(struct fxgmac_pdata *pdata, unsigned int val) { unsigned int i; u32 regval; for (i = 0; i < pdata->rx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_RTC_POS, MTL_Q_RQOMR_RTC_LEN, val); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); } return 0; } static void fxgmac_config_mtl_mode(struct fxgmac_pdata *pdata) { unsigned int i; u32 regval; /* Set Tx to weighted round robin scheduling algorithm */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MTL_OMR); regval = FXGMAC_SET_REG_BITS(regval, MTL_OMR_ETSALG_POS, MTL_OMR_ETSALG_LEN, MTL_ETSALG_WRR); writereg(pdata->pAdapter, regval, pdata->mac_regs + MTL_OMR); #if 1 /* Set Tx traffic classes to use WRR algorithm with equal weights */ for (i = 0; i < pdata->tx_q_count/*hw_feat.tc_cnt*/; i++) { //regval = readreg(FXGMAC_MTL_REG(pdata, i, MTL_TC_ETSCR)); //regval = FXGMAC_SET_REG_BITS(regval, MTL_TC_ETSCR_TSA_POS, // MTL_TC_ETSCR_TSA_LEN, MTL_TSA_ETS); //writereg(regval, FXGMAC_MTL_REG(pdata, i, MTL_TC_ETSCR)); regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_TC_QWR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_TC_QWR_QW_POS, MTL_TC_QWR_QW_LEN, 1); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_TC_QWR)); } #endif /* Set Rx to strict priority algorithm */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MTL_OMR); regval = FXGMAC_SET_REG_BITS(regval, MTL_OMR_RAA_POS, MTL_OMR_RAA_LEN, MTL_RAA_SP); writereg(pdata->pAdapter, regval, pdata->mac_regs + MTL_OMR); } static void fxgmac_config_queue_mapping(struct fxgmac_pdata *pdata) { unsigned int ppq, ppq_extra, prio, prio_queues; //unsigned int qptc, qptc_extra; unsigned int queue; unsigned int reg, regval; unsigned int mask; unsigned int i, j; /* Map the MTL Tx Queues to Traffic Classes * Note: Tx Queues >= Traffic Classes */ #if 0 qptc = pdata->tx_q_count / pdata->hw_feat.tc_cnt; qptc_extra = pdata->tx_q_count % pdata->hw_feat.tc_cnt; for (i = 0, queue = 0; i < pdata->hw_feat.tc_cnt; i++) { for (j = 0; j < qptc; j++) { netif_dbg(pdata, drv, pdata->netdev, "TXq%u mapped to TC%u\n", queue, i); regval = readreg(FXGMAC_MTL_REG(pdata, queue, MTL_Q_TQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_Q2TCMAP_POS, MTL_Q_TQOMR_Q2TCMAP_LEN, i); writereg(regval, FXGMAC_MTL_REG(pdata, queue, MTL_Q_TQOMR)); queue++; } if (i < qptc_extra) { netif_dbg(pdata, drv, pdata->netdev, "TXq%u mapped to TC%u\n", queue, i); regval = readreg(FXGMAC_MTL_REG(pdata, queue, MTL_Q_TQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_Q2TCMAP_POS, MTL_Q_TQOMR_Q2TCMAP_LEN, i); writereg(regval, FXGMAC_MTL_REG(pdata, queue, MTL_Q_TQOMR)); queue++; } } #else queue = 0; DPRINTK("need to map TXq(%u) to TC\n", queue); #endif /* Map the 8 VLAN priority values to available MTL Rx queues */ prio_queues = min_t(unsigned int, IEEE_8021QAZ_MAX_TCS, pdata->rx_q_count); ppq = IEEE_8021QAZ_MAX_TCS / prio_queues; ppq_extra = IEEE_8021QAZ_MAX_TCS % prio_queues; reg = MAC_RQC2R; regval = 0; for (i = 0, prio = 0; i < prio_queues;) { mask = 0; for (j = 0; j < ppq; j++) { netif_dbg(pdata, drv, pdata->netdev, "PRIO%u mapped to RXq%u\n", prio, i); mask |= (1 << prio); prio++; } if (i < ppq_extra) { netif_dbg(pdata, drv, pdata->netdev, "PRIO%u mapped to RXq%u\n", prio, i); mask |= (1 << prio); prio++; } regval |= (mask << ((i++ % MAC_RQC2_Q_PER_REG) << 3)); if ((i % MAC_RQC2_Q_PER_REG) && (i != prio_queues)) continue; writereg(pdata->pAdapter, regval, pdata->mac_regs + reg); reg += MAC_RQC2_INC; regval = 0; } /* Configure one to one, MTL Rx queue to DMA Rx channel mapping * ie Q0 <--> CH0, Q1 <--> CH1 ... Q11 <--> CH11 */ reg = MTL_RQDCM0R; regval = readreg(pdata->pAdapter, pdata->mac_regs + reg); regval |= (MTL_RQDCM0R_Q0MDMACH | MTL_RQDCM0R_Q1MDMACH | MTL_RQDCM0R_Q2MDMACH | MTL_RQDCM0R_Q3MDMACH); if (pdata->rss) { /* in version later 0617, need to enable DA-based DMA Channel Selection to let RSS work, * ie, bit4,12,20,28 for Q0,1,2,3 individual */ regval |= (MTL_RQDCM0R_Q0DDMACH | MTL_RQDCM0R_Q1DDMACH | MTL_RQDCM0R_Q2DDMACH | MTL_RQDCM0R_Q3DDMACH); } writereg(pdata->pAdapter, regval, pdata->mac_regs + reg); reg += MTL_RQDCM_INC; regval = readreg(pdata->pAdapter, pdata->mac_regs + reg); regval |= (MTL_RQDCM1R_Q4MDMACH | MTL_RQDCM1R_Q5MDMACH | MTL_RQDCM1R_Q6MDMACH | MTL_RQDCM1R_Q7MDMACH); writereg(pdata->pAdapter, regval, pdata->mac_regs + reg); #if 0 reg += MTL_RQDCM_INC; regval = readreg(pdata->mac_regs + reg); regval |= (MTL_RQDCM2R_Q8MDMACH | MTL_RQDCM2R_Q9MDMACH | MTL_RQDCM2R_Q10MDMACH | MTL_RQDCM2R_Q11MDMACH); writereg(regval, pdata->mac_regs + reg); #endif } static unsigned int fxgmac_calculate_per_queue_fifo( unsigned int fifo_size, unsigned int queue_count) { unsigned int q_fifo_size; unsigned int p_fifo; /* Calculate the configured fifo size */ q_fifo_size = 1 << (fifo_size + 7); /* The configured value may not be the actual amount of fifo RAM */ q_fifo_size = min_t(unsigned int, FXGMAC_MAX_FIFO, q_fifo_size); q_fifo_size = q_fifo_size / queue_count; /* Each increment in the queue fifo size represents 256 bytes of * fifo, with 0 representing 256 bytes. Distribute the fifo equally * between the queues. */ p_fifo = q_fifo_size / 256; if (p_fifo) p_fifo--; return p_fifo; } static void fxgmac_config_tx_fifo_size(struct fxgmac_pdata *pdata) { unsigned int fifo_size; unsigned int i; u32 regval; fifo_size = fxgmac_calculate_per_queue_fifo( pdata->hw_feat.tx_fifo_size, pdata->tx_q_count); for (i = 0; i < pdata->tx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_TQS_POS, MTL_Q_TQOMR_TQS_LEN, fifo_size); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); } netif_info(pdata, drv, pdata->netdev, "%d Tx hardware queues, %d byte fifo per queue\n", pdata->tx_q_count, ((fifo_size + 1) * 256)); } static void fxgmac_config_rx_fifo_size(struct fxgmac_pdata *pdata) { unsigned int fifo_size; unsigned int i; u32 regval; fifo_size = fxgmac_calculate_per_queue_fifo( pdata->hw_feat.rx_fifo_size, pdata->rx_q_count); for (i = 0; i < pdata->rx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_RQS_POS, MTL_Q_RQOMR_RQS_LEN, fifo_size); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); } netif_info(pdata, drv, pdata->netdev, "%d Rx hardware queues, %d byte fifo per queue\n", pdata->rx_q_count, ((fifo_size + 1) * 256)); } static void fxgmac_config_flow_control_threshold(struct fxgmac_pdata *pdata) { unsigned int i; u32 regval; for (i = 0; i < pdata->rx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); /* Activate flow control when less than 6k left in fifo */ //In windows driver,it sets the value 6, but in Linux it sets the value 10. Here it uses value that exists in windows driver regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_RFA_POS, MTL_Q_RQOMR_RFA_LEN, 6); /* De-activate flow control when more than 10k left in fifo */ regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_RFD_POS, MTL_Q_RQOMR_RFD_LEN, 10); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); } } static int fxgmac_config_tx_threshold(struct fxgmac_pdata *pdata, unsigned int val) { unsigned int i; u32 regval; for (i = 0; i < pdata->tx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_TTC_POS, MTL_Q_TQOMR_TTC_LEN, val); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); } return 0; } static int fxgmac_config_rsf_mode(struct fxgmac_pdata *pdata, unsigned int val) { unsigned int i; u32 regval; for (i = 0; i < pdata->rx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_RSF_POS, MTL_Q_RQOMR_RSF_LEN, val); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_RQOMR)); } return 0; } static int fxgmac_config_tsf_mode(struct fxgmac_pdata *pdata, unsigned int val) { unsigned int i; u32 regval; for (i = 0; i < pdata->tx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_TSF_POS, MTL_Q_TQOMR_TSF_LEN, val); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); } return 0; } static int fxgmac_config_osp_mode(struct fxgmac_pdata *pdata) { #ifndef DPDK struct fxgmac_channel *channel; unsigned int i; u32 regval; channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->tx_ring) break; regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_TCR_OSP_POS, DMA_CH_TCR_OSP_LEN, pdata->tx_osp_mode); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); } #else /* Force DMA to operate on second packet before closing descriptors * of first packet */ struct fxgmac_tx_queue *txq; unsigned int i; for (i = 0; i < pdata->expansion.eth_dev->data->nb_tx_queues; i++) { txq = pdata->expansion.eth_dev->data->tx_queues[i]; FXGMAC_DMA_IOWRITE_BITS(txq, DMA_CH_TCR, OSP, pdata->tx_osp_mode); } #endif return 0; } static int fxgmac_config_pblx8(struct fxgmac_pdata *pdata) { #ifndef DPDK struct fxgmac_channel *channel; unsigned int i; u32 regval; channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_CR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_CR_PBLX8_POS, DMA_CH_CR_PBLX8_LEN, pdata->pblx8); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_CR)); } #else struct fxgmac_tx_queue *txq; unsigned int i; for (i = 0; i < pdata->expansion.eth_dev->data->nb_tx_queues; i++) { txq = pdata->expansion.eth_dev->data->tx_queues[i]; FXGMAC_DMA_IOWRITE_BITS(txq, DMA_CH_CR, PBLX8, pdata->pblx8); } #endif return 0; } static int fxgmac_get_tx_pbl_val(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(pdata->channel_head, DMA_CH_TCR)); regval = FXGMAC_GET_REG_BITS(regval, DMA_CH_TCR_PBL_POS, DMA_CH_TCR_PBL_LEN); return regval; } static int fxgmac_config_tx_pbl_val(struct fxgmac_pdata *pdata) { #ifndef DPDK struct fxgmac_channel *channel; unsigned int i; u32 regval; channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->tx_ring) break; regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_TCR_PBL_POS, DMA_CH_TCR_PBL_LEN, pdata->tx_pbl); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); } #else struct fxgmac_tx_queue *txq; unsigned int i; for (i = 0; i < pdata->expansion.eth_dev->data->nb_tx_queues; i++) { txq = pdata->expansion.eth_dev->data->tx_queues[i]; FXGMAC_DMA_IOWRITE_BITS(txq, DMA_CH_TCR, PBL, pdata->tx_pbl); } #endif return 0; } static int fxgmac_get_rx_pbl_val(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(pdata->channel_head, DMA_CH_RCR)); regval = FXGMAC_GET_REG_BITS(regval, DMA_CH_RCR_PBL_POS, DMA_CH_RCR_PBL_LEN); return regval; } static int fxgmac_config_rx_pbl_val(struct fxgmac_pdata *pdata) { #ifndef DPDK struct fxgmac_channel *channel; unsigned int i; u32 regval; channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->rx_ring) break; regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_RCR_PBL_POS, DMA_CH_RCR_PBL_LEN, pdata->rx_pbl); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); } #else struct fxgmac_rx_queue *rxq; unsigned int i; for (i = 0; i < pdata->expansion.eth_dev->data->nb_rx_queues; i++) { rxq = pdata->expansion.eth_dev->data->rx_queues[i]; FXGMAC_DMA_IOWRITE_BITS(rxq, DMA_CH_RCR, PBL, pdata->rx_pbl); } #endif return 0; } static u64 fxgmac_mmc_read(struct fxgmac_pdata *pdata, unsigned int reg_lo) { /* bool read_hi; */ u64 val; #if 0 switch (reg_lo) { /* These registers are always 64 bit */ case MMC_TXOCTETCOUNT_GB_LO: case MMC_TXOCTETCOUNT_G_LO: case MMC_RXOCTETCOUNT_GB_LO: case MMC_RXOCTETCOUNT_G_LO: read_hi = true; break; default: read_hi = false; } #endif val = (u64)readreg(pdata->pAdapter, pdata->mac_regs + reg_lo); /* if (read_hi) val |= ((u64)readreg(pdata->mac_regs + reg_lo + 4) << 32); */ return val; } static void fxgmac_tx_mmc_int(struct fxgmac_pdata *pdata) { unsigned int mmc_isr = readreg(pdata->pAdapter, pdata->mac_regs + MMC_TISR); struct fxgmac_stats *stats = &pdata->stats; if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXOCTETCOUNT_GB_POS, MMC_TISR_TXOCTETCOUNT_GB_LEN)) stats->txoctetcount_gb += fxgmac_mmc_read(pdata, MMC_TXOCTETCOUNT_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXFRAMECOUNT_GB_POS, MMC_TISR_TXFRAMECOUNT_GB_LEN)) stats->txframecount_gb += fxgmac_mmc_read(pdata, MMC_TXFRAMECOUNT_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXBROADCASTFRAMES_G_POS, MMC_TISR_TXBROADCASTFRAMES_G_LEN)) stats->txbroadcastframes_g += fxgmac_mmc_read(pdata, MMC_TXBROADCASTFRAMES_G_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXMULTICASTFRAMES_G_POS, MMC_TISR_TXMULTICASTFRAMES_G_LEN)) stats->txmulticastframes_g += fxgmac_mmc_read(pdata, MMC_TXMULTICASTFRAMES_G_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TX64OCTETS_GB_POS, MMC_TISR_TX64OCTETS_GB_LEN)) stats->tx64octets_gb += fxgmac_mmc_read(pdata, MMC_TX64OCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TX65TO127OCTETS_GB_POS, MMC_TISR_TX65TO127OCTETS_GB_LEN)) stats->tx65to127octets_gb += fxgmac_mmc_read(pdata, MMC_TX65TO127OCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TX128TO255OCTETS_GB_POS, MMC_TISR_TX128TO255OCTETS_GB_LEN)) stats->tx128to255octets_gb += fxgmac_mmc_read(pdata, MMC_TX128TO255OCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TX256TO511OCTETS_GB_POS, MMC_TISR_TX256TO511OCTETS_GB_LEN)) stats->tx256to511octets_gb += fxgmac_mmc_read(pdata, MMC_TX256TO511OCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TX512TO1023OCTETS_GB_POS, MMC_TISR_TX512TO1023OCTETS_GB_LEN)) stats->tx512to1023octets_gb += fxgmac_mmc_read(pdata, MMC_TX512TO1023OCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TX1024TOMAXOCTETS_GB_POS, MMC_TISR_TX1024TOMAXOCTETS_GB_LEN)) stats->tx1024tomaxoctets_gb += fxgmac_mmc_read(pdata, MMC_TX1024TOMAXOCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXUNICASTFRAMES_GB_POS, MMC_TISR_TXUNICASTFRAMES_GB_LEN)) stats->txunicastframes_gb += fxgmac_mmc_read(pdata, MMC_TXUNICASTFRAMES_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXMULTICASTFRAMES_GB_POS, MMC_TISR_TXMULTICASTFRAMES_GB_LEN)) stats->txmulticastframes_gb += fxgmac_mmc_read(pdata, MMC_TXMULTICASTFRAMES_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXBROADCASTFRAMES_GB_POS, MMC_TISR_TXBROADCASTFRAMES_GB_LEN)) stats->txbroadcastframes_g += fxgmac_mmc_read(pdata, MMC_TXBROADCASTFRAMES_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXUNDERFLOWERROR_POS, MMC_TISR_TXUNDERFLOWERROR_LEN)) stats->txunderflowerror += fxgmac_mmc_read(pdata, MMC_TXUNDERFLOWERROR_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXSINGLECOLLISION_G_POS, MMC_TISR_TXSINGLECOLLISION_G_LEN)) stats->txsinglecollision_g += fxgmac_mmc_read(pdata, MMC_TXSINGLECOLLISION_G); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXMULTIPLECOLLISION_G_POS, MMC_TISR_TXMULTIPLECOLLISION_G_LEN)) stats->txmultiplecollision_g += fxgmac_mmc_read(pdata, MMC_TXMULTIPLECOLLISION_G); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXDEFERREDFRAMES_POS, MMC_TISR_TXDEFERREDFRAMES_LEN)) stats->txdeferredframes += fxgmac_mmc_read(pdata, MMC_TXDEFERREDFRAMES); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXLATECOLLISIONFRAMES_POS, MMC_TISR_TXLATECOLLISIONFRAMES_LEN)) stats->txlatecollisionframes += fxgmac_mmc_read(pdata, MMC_TXLATECOLLISIONFRAMES); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXEXCESSIVECOLLISIONFRAMES_POS, MMC_TISR_TXEXCESSIVECOLLISIONFRAMES_LEN)) stats->txexcessivecollisionframes += fxgmac_mmc_read(pdata, MMC_TXEXCESSIVECOLLSIONFRAMES); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXCARRIERERRORFRAMES_POS, MMC_TISR_TXCARRIERERRORFRAMES_LEN)) stats->txcarriererrorframes += fxgmac_mmc_read(pdata, MMC_TXCARRIERERRORFRAMES); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXOCTETCOUNT_G_POS, MMC_TISR_TXOCTETCOUNT_G_LEN)) stats->txoctetcount_g += fxgmac_mmc_read(pdata, MMC_TXOCTETCOUNT_G_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXFRAMECOUNT_G_POS, MMC_TISR_TXFRAMECOUNT_G_LEN)) stats->txframecount_g += fxgmac_mmc_read(pdata, MMC_TXFRAMECOUNT_G_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXEXCESSIVEDEFERRALFRAMES_POS, MMC_TISR_TXEXCESSIVEDEFERRALFRAMES_LEN)) stats->txexcessivedeferralerror += fxgmac_mmc_read(pdata, MMC_TXEXCESSIVEDEFERRALERROR); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXPAUSEFRAMES_POS, MMC_TISR_TXPAUSEFRAMES_LEN)) stats->txpauseframes += fxgmac_mmc_read(pdata, MMC_TXPAUSEFRAMES_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXVLANFRAMES_G_POS, MMC_TISR_TXVLANFRAMES_G_LEN)) stats->txvlanframes_g += fxgmac_mmc_read(pdata, MMC_TXVLANFRAMES_G_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_TISR_TXOVERSIZE_G_POS, MMC_TISR_TXOVERSIZE_G_LEN)) stats->txoversize_g += fxgmac_mmc_read(pdata, MMC_TXOVERSIZEFRAMES); } static void fxgmac_rx_mmc_int(struct fxgmac_pdata *pdata) { unsigned int mmc_isr = readreg(pdata->pAdapter, pdata->mac_regs + MMC_RISR); struct fxgmac_stats *stats = &pdata->stats; if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXFRAMECOUNT_GB_POS, MMC_RISR_RXFRAMECOUNT_GB_LEN)) stats->rxframecount_gb += fxgmac_mmc_read(pdata, MMC_RXFRAMECOUNT_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXOCTETCOUNT_GB_POS, MMC_RISR_RXOCTETCOUNT_GB_LEN)) stats->rxoctetcount_gb += fxgmac_mmc_read(pdata, MMC_RXOCTETCOUNT_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXOCTETCOUNT_G_POS, MMC_RISR_RXOCTETCOUNT_G_LEN)) stats->rxoctetcount_g += fxgmac_mmc_read(pdata, MMC_RXOCTETCOUNT_G_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXBROADCASTFRAMES_G_POS, MMC_RISR_RXBROADCASTFRAMES_G_LEN)) stats->rxbroadcastframes_g += fxgmac_mmc_read(pdata, MMC_RXBROADCASTFRAMES_G_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXMULTICASTFRAMES_G_POS, MMC_RISR_RXMULTICASTFRAMES_G_LEN)) stats->rxmulticastframes_g += fxgmac_mmc_read(pdata, MMC_RXMULTICASTFRAMES_G_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXCRCERROR_POS, MMC_RISR_RXCRCERROR_LEN)) stats->rxcrcerror += fxgmac_mmc_read(pdata, MMC_RXCRCERROR_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXALIGNERROR_POS, MMC_RISR_RXALIGNERROR_LEN)) stats->rxalignerror += fxgmac_mmc_read(pdata, MMC_RXALIGNERROR); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXRUNTERROR_POS, MMC_RISR_RXRUNTERROR_LEN)) stats->rxrunterror += fxgmac_mmc_read(pdata, MMC_RXRUNTERROR); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXJABBERERROR_POS, MMC_RISR_RXJABBERERROR_LEN)) stats->rxjabbererror += fxgmac_mmc_read(pdata, MMC_RXJABBERERROR); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXUNDERSIZE_G_POS, MMC_RISR_RXUNDERSIZE_G_LEN)) stats->rxundersize_g += fxgmac_mmc_read(pdata, MMC_RXUNDERSIZE_G); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXOVERSIZE_G_POS, MMC_RISR_RXOVERSIZE_G_LEN)) stats->rxoversize_g += fxgmac_mmc_read(pdata, MMC_RXOVERSIZE_G); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RX64OCTETS_GB_POS, MMC_RISR_RX64OCTETS_GB_LEN)) stats->rx64octets_gb += fxgmac_mmc_read(pdata, MMC_RX64OCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RX65TO127OCTETS_GB_POS, MMC_RISR_RX65TO127OCTETS_GB_LEN)) stats->rx65to127octets_gb += fxgmac_mmc_read(pdata, MMC_RX65TO127OCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RX128TO255OCTETS_GB_POS, MMC_RISR_RX128TO255OCTETS_GB_LEN)) stats->rx128to255octets_gb += fxgmac_mmc_read(pdata, MMC_RX128TO255OCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RX256TO511OCTETS_GB_POS, MMC_RISR_RX256TO511OCTETS_GB_LEN)) stats->rx256to511octets_gb += fxgmac_mmc_read(pdata, MMC_RX256TO511OCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RX512TO1023OCTETS_GB_POS, MMC_RISR_RX512TO1023OCTETS_GB_LEN)) stats->rx512to1023octets_gb += fxgmac_mmc_read(pdata, MMC_RX512TO1023OCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RX1024TOMAXOCTETS_GB_POS, MMC_RISR_RX1024TOMAXOCTETS_GB_LEN)) stats->rx1024tomaxoctets_gb += fxgmac_mmc_read(pdata, MMC_RX1024TOMAXOCTETS_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXUNICASTFRAMES_G_POS, MMC_RISR_RXUNICASTFRAMES_G_LEN)) stats->rxunicastframes_g += fxgmac_mmc_read(pdata, MMC_RXUNICASTFRAMES_G_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXLENGTHERROR_POS, MMC_RISR_RXLENGTHERROR_LEN)) stats->rxlengtherror += fxgmac_mmc_read(pdata, MMC_RXLENGTHERROR_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXOUTOFRANGETYPE_POS, MMC_RISR_RXOUTOFRANGETYPE_LEN)) stats->rxoutofrangetype += fxgmac_mmc_read(pdata, MMC_RXOUTOFRANGETYPE_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXPAUSEFRAMES_POS, MMC_RISR_RXPAUSEFRAMES_LEN)) stats->rxpauseframes += fxgmac_mmc_read(pdata, MMC_RXPAUSEFRAMES_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXFIFOOVERFLOW_POS, MMC_RISR_RXFIFOOVERFLOW_LEN)) stats->rxfifooverflow += fxgmac_mmc_read(pdata, MMC_RXFIFOOVERFLOW_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXVLANFRAMES_GB_POS, MMC_RISR_RXVLANFRAMES_GB_LEN)) stats->rxvlanframes_gb += fxgmac_mmc_read(pdata, MMC_RXVLANFRAMES_GB_LO); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXWATCHDOGERROR_POS, MMC_RISR_RXWATCHDOGERROR_LEN)) stats->rxwatchdogerror += fxgmac_mmc_read(pdata, MMC_RXWATCHDOGERROR); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXERRORFRAMES_POS, MMC_RISR_RXERRORFRAMES_LEN)) stats->rxreceiveerrorframe += fxgmac_mmc_read(pdata, MMC_RXRECEIVEERRORFRAME); if (FXGMAC_GET_REG_BITS(mmc_isr, MMC_RISR_RXERRORCONTROLFRAMES_POS, MMC_RISR_RXERRORCONTROLFRAMES_LEN)) stats->rxcontrolframe_g += fxgmac_mmc_read(pdata, MMC_RXCONTROLFRAME_G); } static void fxgmac_read_mmc_stats(struct fxgmac_pdata *pdata) { struct fxgmac_stats *stats = &pdata->stats; u32 regval; /* Freeze counters */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MMC_CR); regval = FXGMAC_SET_REG_BITS(regval, MMC_CR_MCF_POS, MMC_CR_MCF_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MMC_CR); stats->txoctetcount_gb += fxgmac_mmc_read(pdata, MMC_TXOCTETCOUNT_GB_LO); stats->txframecount_gb += fxgmac_mmc_read(pdata, MMC_TXFRAMECOUNT_GB_LO); stats->txbroadcastframes_g += fxgmac_mmc_read(pdata, MMC_TXBROADCASTFRAMES_G_LO); stats->txmulticastframes_g += fxgmac_mmc_read(pdata, MMC_TXMULTICASTFRAMES_G_LO); stats->tx64octets_gb += fxgmac_mmc_read(pdata, MMC_TX64OCTETS_GB_LO); stats->tx65to127octets_gb += fxgmac_mmc_read(pdata, MMC_TX65TO127OCTETS_GB_LO); stats->tx128to255octets_gb += fxgmac_mmc_read(pdata, MMC_TX128TO255OCTETS_GB_LO); stats->tx256to511octets_gb += fxgmac_mmc_read(pdata, MMC_TX256TO511OCTETS_GB_LO); stats->tx512to1023octets_gb += fxgmac_mmc_read(pdata, MMC_TX512TO1023OCTETS_GB_LO); stats->tx1024tomaxoctets_gb += fxgmac_mmc_read(pdata, MMC_TX1024TOMAXOCTETS_GB_LO); stats->txunicastframes_gb += fxgmac_mmc_read(pdata, MMC_TXUNICASTFRAMES_GB_LO); stats->txmulticastframes_gb += fxgmac_mmc_read(pdata, MMC_TXMULTICASTFRAMES_GB_LO); stats->txbroadcastframes_g += fxgmac_mmc_read(pdata, MMC_TXBROADCASTFRAMES_GB_LO); stats->txunderflowerror += fxgmac_mmc_read(pdata, MMC_TXUNDERFLOWERROR_LO); stats->txsinglecollision_g += fxgmac_mmc_read(pdata, MMC_TXSINGLECOLLISION_G); stats->txmultiplecollision_g += fxgmac_mmc_read(pdata, MMC_TXMULTIPLECOLLISION_G); stats->txdeferredframes += fxgmac_mmc_read(pdata, MMC_TXDEFERREDFRAMES); stats->txlatecollisionframes += fxgmac_mmc_read(pdata, MMC_TXLATECOLLISIONFRAMES); stats->txexcessivecollisionframes += fxgmac_mmc_read(pdata, MMC_TXEXCESSIVECOLLSIONFRAMES); stats->txcarriererrorframes += fxgmac_mmc_read(pdata, MMC_TXCARRIERERRORFRAMES); stats->txoctetcount_g += fxgmac_mmc_read(pdata, MMC_TXOCTETCOUNT_G_LO); stats->txframecount_g += fxgmac_mmc_read(pdata, MMC_TXFRAMECOUNT_G_LO); stats->txexcessivedeferralerror += fxgmac_mmc_read(pdata, MMC_TXEXCESSIVEDEFERRALERROR); stats->txpauseframes += fxgmac_mmc_read(pdata, MMC_TXPAUSEFRAMES_LO); stats->txvlanframes_g += fxgmac_mmc_read(pdata, MMC_TXVLANFRAMES_G_LO); stats->txoversize_g += fxgmac_mmc_read(pdata, MMC_TXOVERSIZEFRAMES); stats->rxframecount_gb += fxgmac_mmc_read(pdata, MMC_RXFRAMECOUNT_GB_LO); stats->rxoctetcount_gb += fxgmac_mmc_read(pdata, MMC_RXOCTETCOUNT_GB_LO); stats->rxoctetcount_g += fxgmac_mmc_read(pdata, MMC_RXOCTETCOUNT_G_LO); stats->rxbroadcastframes_g += fxgmac_mmc_read(pdata, MMC_RXBROADCASTFRAMES_G_LO); stats->rxmulticastframes_g += fxgmac_mmc_read(pdata, MMC_RXMULTICASTFRAMES_G_LO); stats->rxcrcerror += fxgmac_mmc_read(pdata, MMC_RXCRCERROR_LO); stats->rxalignerror += fxgmac_mmc_read(pdata, MMC_RXALIGNERROR); stats->rxrunterror += fxgmac_mmc_read(pdata, MMC_RXRUNTERROR); stats->rxjabbererror += fxgmac_mmc_read(pdata, MMC_RXJABBERERROR); stats->rxundersize_g += fxgmac_mmc_read(pdata, MMC_RXUNDERSIZE_G); stats->rxoversize_g += fxgmac_mmc_read(pdata, MMC_RXOVERSIZE_G); stats->rx64octets_gb += fxgmac_mmc_read(pdata, MMC_RX64OCTETS_GB_LO); stats->rx65to127octets_gb += fxgmac_mmc_read(pdata, MMC_RX65TO127OCTETS_GB_LO); stats->rx128to255octets_gb += fxgmac_mmc_read(pdata, MMC_RX128TO255OCTETS_GB_LO); stats->rx256to511octets_gb += fxgmac_mmc_read(pdata, MMC_RX256TO511OCTETS_GB_LO); stats->rx512to1023octets_gb += fxgmac_mmc_read(pdata, MMC_RX512TO1023OCTETS_GB_LO); stats->rx1024tomaxoctets_gb += fxgmac_mmc_read(pdata, MMC_RX1024TOMAXOCTETS_GB_LO); stats->rxunicastframes_g += fxgmac_mmc_read(pdata, MMC_RXUNICASTFRAMES_G_LO); stats->rxlengtherror += fxgmac_mmc_read(pdata, MMC_RXLENGTHERROR_LO); stats->rxoutofrangetype += fxgmac_mmc_read(pdata, MMC_RXOUTOFRANGETYPE_LO); stats->rxpauseframes += fxgmac_mmc_read(pdata, MMC_RXPAUSEFRAMES_LO); stats->rxfifooverflow += fxgmac_mmc_read(pdata, MMC_RXFIFOOVERFLOW_LO); stats->rxvlanframes_gb += fxgmac_mmc_read(pdata, MMC_RXVLANFRAMES_GB_LO); stats->rxwatchdogerror += fxgmac_mmc_read(pdata, MMC_RXWATCHDOGERROR); stats->rxreceiveerrorframe += fxgmac_mmc_read(pdata, MMC_RXRECEIVEERRORFRAME); stats->rxcontrolframe_g += fxgmac_mmc_read(pdata, MMC_RXCONTROLFRAME_G); /* Un-freeze counters */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MMC_CR); regval = FXGMAC_SET_REG_BITS(regval, MMC_CR_MCF_POS, MMC_CR_MCF_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MMC_CR); } static void fxgmac_config_mmc(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MMC_CR); /* Set counters to reset on read */ regval = FXGMAC_SET_REG_BITS(regval, MMC_CR_ROR_POS, MMC_CR_ROR_LEN, 1); /* Reset the counters */ regval = FXGMAC_SET_REG_BITS(regval, MMC_CR_CR_POS, MMC_CR_CR_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MMC_CR); #if defined(FUXI_MISC_INT_HANDLE_FEATURE_EN) && FUXI_MISC_INT_HANDLE_FEATURE_EN //disable interrupts for rx Tcp and ip good pkt counter which is not read by MMC counter process. //regval = readreg(pdata->mac_regs + 0x800); writereg(pdata->pAdapter, 0xffffffff, pdata->mac_regs + MMC_IPCRXINTMASK); #endif } static int fxgmac_write_rss_reg(struct fxgmac_pdata *pdata, unsigned int type, unsigned int index, unsigned int val) { int ret = 0; type = type; writereg(pdata->pAdapter, val, (pdata->base_mem+ index)); return ret; } static u32 fxgmac_read_rss_options(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_RSS_CTRL); /* Get the RSS options bits */ regval = FXGMAC_GET_REG_BITS(regval, MGMT_RSS_CTRL_OPT_POS, MGMT_RSS_CTRL_OPT_LEN); return regval; } static int fxgmac_write_rss_options(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_RSS_CTRL); /* Set the RSS options */ regval = FXGMAC_SET_REG_BITS(regval, MGMT_RSS_CTRL_OPT_POS, MGMT_RSS_CTRL_OPT_LEN, pdata->rss_options); writereg(pdata->pAdapter, regval, (pdata->base_mem + MGMT_RSS_CTRL)); return 0; } #if !defined(DPDK) static int fxgmac_read_rss_hash_key(struct fxgmac_pdata *pdata, u8 *key_buf) { //struct net_device *netdev = pdata->netdev; unsigned int key_regs = sizeof(pdata->rss_key) / sizeof(u32); u32 *key = (u32 *)key_buf; while (key_regs--) { (*key) = cpu_to_be32(readreg(pdata->pAdapter, pdata->base_mem + (MGMT_RSS_KEY0 + key_regs * MGMT_RSS_KEY_REG_INC))) ; DBGPRINT(MP_LOUD, ("fxgmac_read_rss_hash_key: idx=%d, reg=%x, key=0x%08x\n", key_regs, MGMT_RSS_KEY0 + key_regs * MGMT_RSS_KEY_REG_INC, (u32)(*key))); key++; } return 0; } #endif static int fxgmac_write_rss_hash_key(struct fxgmac_pdata *pdata) { unsigned int key_regs = sizeof(pdata->rss_key) / sizeof(u32); u32 *key = (u32 *)&pdata->rss_key; int ret; while (key_regs--) { ret = fxgmac_write_rss_reg(pdata, FXGMAC_RSS_HASH_KEY_TYPE, MGMT_RSS_KEY0 + key_regs * MGMT_RSS_KEY_REG_INC, cpu_to_be32 (*key)); if (ret) return ret; key++; } return 0; } static int fxgmac_write_rss_lookup_table(struct fxgmac_pdata *pdata) { unsigned int i, j; u32 regval = 0; int ret; for (i = 0, j = 0; i < ARRAY_SIZE(pdata->rss_table); i++, j++) { if(j < MGMT_RSS_IDT_ENTRY_PER_REG) { regval |= ((pdata->rss_table[i] & MGMT_RSS_IDT_ENTRY_MASK) << (j * 2)); }else{ ret = fxgmac_write_rss_reg(pdata, FXGMAC_RSS_LOOKUP_TABLE_TYPE, MGMT_RSS_IDT + (i / MGMT_RSS_IDT_ENTRY_PER_REG - 1) * MGMT_RSS_IDT_REG_INC, regval); if (ret) return ret; regval = pdata->rss_table[i]; j = 0; } } if (j == MGMT_RSS_IDT_ENTRY_PER_REG) { //last IDT fxgmac_write_rss_reg(pdata, FXGMAC_RSS_LOOKUP_TABLE_TYPE, MGMT_RSS_IDT + (i / MGMT_RSS_IDT_ENTRY_PER_REG - 1) * MGMT_RSS_IDT_REG_INC, regval); } return 0; } static int fxgmac_set_rss_hash_key(struct fxgmac_pdata *pdata, const u8 *key) { memcpy(pdata->rss_key, key, sizeof(pdata->rss_key));//CopyMem return fxgmac_write_rss_hash_key(pdata); } static int fxgmac_set_rss_lookup_table(struct fxgmac_pdata *pdata, const u32 *table) { unsigned int i; u32 tval; #if FXGMAC_MSIX_CH0RXDIS_EN DPRINTK("Set_rss_table, rss ctrl eth=0x%08x\n", 0); return 0; #endif for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++) { tval = table[i]; pdata->rss_table[i] = FXGMAC_SET_REG_BITS( pdata->rss_table[i], MAC_RSSDR_DMCH_POS, MAC_RSSDR_DMCH_LEN, tval); } return fxgmac_write_rss_lookup_table(pdata); } static u32 log2ex(u32 value) { u32 i = 31; while (i > 0) { if (value & 0x80000000) { break; } value <<= 1; i--; } return i; } static int fxgmac_enable_rss(struct fxgmac_pdata* pdata) { u32 regval; u32 size = 0; #ifdef LINUX int ret; if (!pdata->hw_feat.rss) { return -EOPNOTSUPP; } /* Program the hash key */ ret = fxgmac_write_rss_hash_key(pdata); if (ret) { return ret; } /* Program the lookup table */ ret = fxgmac_write_rss_lookup_table(pdata); if (ret) { return ret; } #endif regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_RSS_CTRL); //2022-04-19 xiaojiang comment //In Linux driver, it does not set the IDT table size, but windos implement it, so linux driver follow it. /* Set RSS IDT table size */ size = log2ex(FXGMAC_RSS_MAX_TABLE_SIZE) - 1; regval = FXGMAC_SET_REG_BITS(regval, MGMT_RSS_CTRL_TBL_SIZE_POS, MGMT_RSS_CTRL_TBL_SIZE_LEN, size); #if FXGMAC_MSIX_CH0RXDIS_EN /* set default cpu id to 1 */ regval = FXGMAC_SET_REG_BITS(regval, 8, 2, 1); #endif /* Enable RSS */ regval = FXGMAC_SET_REG_BITS(regval, MAC_RSSCR_RSSE_POS, MAC_RSSCR_RSSE_LEN, 1); /* Set the RSS options */ regval = FXGMAC_SET_REG_BITS(regval, MGMT_RSS_CTRL_OPT_POS, MGMT_RSS_CTRL_OPT_LEN, pdata->rss_options); writereg(pdata->pAdapter, regval, (pdata->base_mem + MGMT_RSS_CTRL)); DPRINTK("enable_rss callout, rss ctrl reg=0x%08x\n", regval); return 0; } static int fxgmac_disable_rss(struct fxgmac_pdata *pdata) { u32 regval; if (!pdata->hw_feat.rss) return -EOPNOTSUPP; #if FXGMAC_MSIX_CH0RXDIS_EN DPRINTK("Disable_rss, rss ctrl eth=0x%08x\n", 0); return 0; #endif regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_RSS_CTRL); regval = FXGMAC_SET_REG_BITS(regval, MAC_RSSCR_RSSE_POS, MAC_RSSCR_RSSE_LEN, 0); writereg(pdata->pAdapter, regval, (pdata->base_mem + MGMT_RSS_CTRL)); DPRINTK("disable_rss, rss ctrl reg=0x%08x\n", regval); return 0; } static void fxgmac_config_rss(struct fxgmac_pdata *pdata) { int ret; if (!pdata->hw_feat.rss) return; if (pdata->rss) ret = fxgmac_enable_rss(pdata); else ret = fxgmac_disable_rss(pdata); if (ret) DBGPRINT(MP_ERROR, ("fxgmac_config_rss: error configuring RSS\n")); } #if defined(LINUX) || defined(_WIN64) || defined(_WIN32) // void fxgmac_update_aoe_ipv4addr(struct fxgmac_pdata* pdata, u8* ip_addr) { unsigned int regval, ipval = 0; /* enable or disable ARP offload engine. */ if (!pdata->hw_feat.aoe) { netdev_err(pdata->netdev, "error update ip addr - arp offload not supported.\n"); return; } #if 0 if(ip_addr) { sscanf(ip_addr, "%x.%x.%x.%x", (unsigned int *)&tmp32[0], (unsigned int *)&tmp32[1], (unsigned int *)&tmp32[2], (unsigned int *)&tmp32[3]); tmp[0] = (uint8_t)tmp32[0]; tmp[1] = (uint8_t)tmp32[1]; tmp[2] = (uint8_t)tmp32[2]; tmp[3] = (uint8_t)tmp32[3]; } else { ipval = 0; //0xc0a801ca; //here just hard code to 192.168.1.202 } #endif if(ip_addr) { //inet_aton((const char *)ip_addr, (struct in_addr *)&ipval); //ipval = (unsigned int)in_aton((const char *)ip_addr); ipval = (ip_addr[0] << 24) | (ip_addr[1] << 16) | (ip_addr[2] << 8) | (ip_addr[3] << 0); DPRINTK("%s, covert IP dotted-addr %s to binary 0x%08x ok.\n", __FUNCTION__, ip_addr, cpu_to_be32(ipval)); } else { #ifdef LINUX /* get ipv4 addr from net device */ //2022-04-25 xiaojiang Linux Driver behavior ipval = fxgmac_get_netdev_ip4addr(pdata); DPRINTK("%s, Get net device binary IP ok, 0x%08x\n", __FUNCTION__, cpu_to_be32(ipval)); ipval = cpu_to_be32(ipval); #endif } regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_ARP_PROTO_ADDR); if(regval != /*cpu_to_be32*/(ipval)) { writereg(pdata->pAdapter, /*cpu_to_be32*/(ipval), pdata->mac_regs + MAC_ARP_PROTO_ADDR); DPRINTK("%s, update arp ipaddr reg from 0x%08x to 0x%08x\n", __FUNCTION__, regval, /*cpu_to_be32*/(ipval)); } } void fxgmac_config_arp_offload(struct fxgmac_pdata *pdata, int en) { unsigned int regval = 0; /* enable or disable ARP offload engine. */ if (!pdata->hw_feat.aoe) { netdev_err(pdata->netdev, "error configuring ARP offload - not supported.\n"); return; } regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_ARPEN_POS, MAC_CR_ARPEN_LEN, en ? 1 : 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); DPRINTK("config_aoe, reg val=0x%08x, arp offload en=%d\n", regval, en); } static int fxgmac_enable_arp_offload(struct fxgmac_pdata* pdata) { u32 regval; if (!pdata->hw_feat.aoe) return -EOPNOTSUPP; /* Enable arpoffload */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_ARPEN_POS, MAC_CR_ARPEN_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); return 0; } static int fxgmac_disable_arp_offload(struct fxgmac_pdata* pdata) { u32 regval; if (!pdata->hw_feat.aoe) return -EOPNOTSUPP; /* disable arpoffload */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_ARPEN_POS, MAC_CR_ARPEN_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); return 0; } /* this function config register for NS offload function * parameters: * index - 0~1, index to NS look up table. one entry of the lut is like this |remote|solicited|target0|target1| * remote_addr - ipv6 addr where fuxi gets the NS solicitation pkt(request). in common, it is 0 to match any remote machine. * solicited_addr - the solicited node multicast group address which fuxi computes and joins. * target_addr1 - it is the target address in NS solicitation pkt. * target_addr2 - second target address, any address (with last 6B same with target address?). */ static int fxgmac_set_ns_offload(struct fxgmac_pdata* pdata,unsigned int index, unsigned char* remote_addr,unsigned char* solicited_addr,unsigned char*target_addr1,unsigned char *target_addr2,unsigned char *mac_addr) //static int fxgmac_set_ns_offload(struct nic_pdata* pdata,unsigned char index, PIPV6NSPARAMETERS PIPv6NSPara) { u32 regval; u32 Address[4],mac_addr_hi,mac_addr_lo; u8 i, remote_not_zero = 0; #if 1 regval = readreg(pdata->pAdapter, pdata->base_mem + NS_TPID_PRO); regval = FXGMAC_SET_REG_BITS(regval, NS_TPID_PRO_STPID_POS, NS_TPID_PRO_STPID_LEN, 0X8100); regval = FXGMAC_SET_REG_BITS(regval, NS_TPID_PRO_CTPID_POS, NS_TPID_PRO_CTPID_LEN, 0X9100); writereg(pdata->pAdapter, regval, pdata->base_mem + NS_TPID_PRO); regval = readreg(pdata->pAdapter, pdata->base_mem + 0X38 * index + NS_LUT_MAC_ADDR_CTL ); regval = FXGMAC_SET_REG_BITS(regval, NS_LUT_DST_CMP_TYPE_POS, NS_LUT_DST_CMP_TYPE_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, NS_LUT_DST_IGNORED_POS, NS_LUT_DST_IGNORED_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, NS_LUT_REMOTE_AWARED_POS, NS_LUT_REMOTE_AWARED_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, NS_LUT_TARGET_ISANY_POS, NS_LUT_TARGET_ISANY_LEN, 0); writereg(pdata->pAdapter, regval, pdata->base_mem + 0X38 * index + NS_LUT_MAC_ADDR_CTL); //AR for (i = 0; i < 16/4; i++) { Address[i] = (remote_addr[i * 4 + 0] << 24) | (remote_addr[i * 4 + 1] << 16) | (remote_addr[i * 4 + 2] << 8) | (remote_addr[i * 4 + 3] << 0); writereg(pdata->pAdapter, Address[i], pdata->base_mem + 0X38 * index + NS_LUT_ROMOTE0 + 4 * i); if(Address[i] ) { remote_not_zero = 1; } Address[i] = (target_addr1[i * 4 + 0] << 24) | (target_addr1[i * 4 + 1] << 16) | (target_addr1[i * 4 + 2] << 8) | (target_addr1[i * 4 + 3] << 0); writereg(pdata->pAdapter, Address[i], pdata->base_mem + 0X38 * index + NS_LUT_TARGET0 + 4 * i); Address[i] = (solicited_addr[i * 4 + 0] << 24) | (solicited_addr[i * 4 + 1] << 16) | (solicited_addr[i * 4 + 2] << 8) | (solicited_addr[i * 4 + 3] << 0); writereg(pdata->pAdapter, Address[i], pdata->base_mem + 0X38 * index + NS_LUT_SOLICITED0 + 4 * i); Address[i] = (target_addr2[i * 4 + 0] << 24) | (target_addr2[i * 4 + 1] << 16) | (target_addr2[i * 4 + 2] << 8) | (target_addr2[i * 4 + 3] << 0); writereg(pdata->pAdapter, Address[i], pdata->base_mem + 0X10 * index + NS_LUT_TARGET4 + 4 * i); } mac_addr_hi = (mac_addr[0] << 24) | (mac_addr[1] << 16)|(mac_addr[2] << 8) | (mac_addr[3] << 0); mac_addr_lo = (mac_addr[4] << 8) | (mac_addr[5] << 0); writereg(pdata->pAdapter, mac_addr_hi, pdata->base_mem + 0X38 * index + NS_LUT_MAC_ADDR); if(remote_not_zero==0) { regval = readreg(pdata->pAdapter, pdata->base_mem + 0X38 * index + NS_LUT_MAC_ADDR_CTL ); regval = FXGMAC_SET_REG_BITS(regval, NS_LUT_REMOTE_AWARED_POS, NS_LUT_REMOTE_AWARED_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, NS_LUT_MAC_ADDR_LOW_POS, NS_LUT_MAC_ADDR_LOW_LEN, mac_addr_lo); writereg(pdata->pAdapter, regval, pdata->base_mem + 0X38 * index + NS_LUT_MAC_ADDR_CTL); } else { regval = readreg(pdata->pAdapter, pdata->base_mem + 0X38 * index + NS_LUT_MAC_ADDR_CTL ); regval = FXGMAC_SET_REG_BITS(regval, NS_LUT_REMOTE_AWARED_POS, NS_LUT_REMOTE_AWARED_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, NS_LUT_MAC_ADDR_LOW_POS, NS_LUT_MAC_ADDR_LOW_LEN, mac_addr_lo); writereg(pdata->pAdapter, regval, pdata->base_mem + 0X38 * index + NS_LUT_MAC_ADDR_CTL); } #else regval = readreg(pdata->mac_regs -0x2000 + NS_TPID_PRO); regval = FXGMAC_SET_REG_BITS(regval, NS_TPID_PRO_STPID_POS, NS_TPID_PRO_STPID_LEN, 0X8100); regval = FXGMAC_SET_REG_BITS(regval, NS_TPID_PRO_CTPID_POS, NS_TPID_PRO_CTPID_LEN, 0X9100); writereg(regval, pdata->mac_regs - 0x2000 + NS_TPID_PRO); //AR writereg(0X20000000, pdata->mac_regs - 0x2000 + NS_LUT_ROMOTE0); writereg(0X00000000, pdata->mac_regs - 0x2000 + NS_LUT_ROMOTE1); writereg(0X00000000, pdata->mac_regs - 0x2000 + NS_LUT_ROMOTE2); writereg(0X00000001, pdata->mac_regs - 0x2000 + NS_LUT_ROMOTE3); writereg(0X20000000, pdata->mac_regs - 0x2000 + NS_LUT_TARGET0); writereg(0X00000000, pdata->mac_regs - 0x2000 + NS_LUT_TARGET1); writereg(0X00000000, pdata->mac_regs - 0x2000 + NS_LUT_TARGET2); writereg(0X00000002, pdata->mac_regs - 0x2000 + NS_LUT_TARGET3); writereg(0Xff020000, pdata->mac_regs - 0x2000 + NS_LUT_SOLICITED0); writereg(0X00000000, pdata->mac_regs - 0x2000 + NS_LUT_SOLICITED1); writereg(0X00000001, pdata->mac_regs - 0x2000 + NS_LUT_SOLICITED2); writereg(0Xff000002, pdata->mac_regs - 0x2000 + NS_LUT_SOLICITED3); writereg(0X00e0fc69, pdata->mac_regs - 0x2000 + NS_LUT_MAC_ADDR); writereg(0X00033381, pdata->mac_regs - 0x2000 + NS_LUT_MAC_ADDR_CTL); //NUD writereg(0X20000000, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_ROMOTE0); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_ROMOTE1); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_ROMOTE2); writereg(0X00000001, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_ROMOTE3); writereg(0X20000000, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_TARGET0); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_TARGET1); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_TARGET2); writereg(0X00000002, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_TARGET3); writereg(0X20000000, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_SOLICITED0); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_SOLICITED1); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_SOLICITED2); writereg(0X00000002, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_SOLICITED3); writereg(0X00e0fc69, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_MAC_ADDR); writereg(0X00033382, pdata->mac_regs - 0x2000 + 0X38 * 2 + NS_LUT_MAC_ADDR_CTL); //DAD writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_ROMOTE0); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_ROMOTE1); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_ROMOTE2); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_ROMOTE3); writereg(0X20000000, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_TARGET0); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_TARGET1); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_TARGET2); writereg(0X00000002, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_TARGET3); writereg(0Xff020000, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_SOLICITED0); writereg(0X00000000, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_SOLICITED1); writereg(0X00000001, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_SOLICITED2); writereg(0Xff000002, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_SOLICITED3); writereg(0X00e0fc69, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_MAC_ADDR); writereg(0X00033381, pdata->mac_regs - 0x2000 + 0X38 * 3 + NS_LUT_MAC_ADDR_CTL); writereg(0X00000001, pdata->mac_regs - 0x2000 + NS_OF_GLB_CTL); #endif return 0; } #ifdef LINUX void fxgmac_update_ns_offload_ipv6addr(struct fxgmac_pdata *pdata, unsigned int param) { struct net_device *netdev = pdata->netdev; unsigned char addr_buf[5][16]; unsigned char * remote_addr = (unsigned char *)&addr_buf[0][0]; unsigned char * solicited_addr = (unsigned char *)&addr_buf[1][0]; unsigned char * target_addr1 = (unsigned char *)&addr_buf[2][0]; //unsigned char * target_addr2 = (unsigned char *)&addr_buf[3][0]; unsigned char * mac_addr = (unsigned char *)&addr_buf[4][0]; /* get ipv6 addr from net device */ if (NULL == fxgmac_get_netdev_ip6addr(pdata, target_addr1, solicited_addr, (FXGMAC_NS_IFA_LOCAL_LINK | FXGMAC_NS_IFA_GLOBAL_UNICAST) & param)) { DPRINTK("%s, get net device ipv6 addr with err and ignore NS offload.\n", __FUNCTION__); return; } DPRINTK("%s, Get net device binary IPv6 ok, local-link=%pI6\n", __FUNCTION__, target_addr1); DPRINTK("%s, Get net device binary IPv6 ok, solicited =%pI6\n", __FUNCTION__, solicited_addr); memcpy(mac_addr, netdev->dev_addr, netdev->addr_len); DPRINTK("%s, Get net device MAC addr ok, ns_tab idx=%d, %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, pdata->expansion.ns_offload_tab_idx, mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); memset(remote_addr, 0, 16); fxgmac_set_ns_offload(pdata, pdata->expansion.ns_offload_tab_idx++, remote_addr, solicited_addr, target_addr1, target_addr1, mac_addr); if(pdata->expansion.ns_offload_tab_idx >= 2) pdata->expansion.ns_offload_tab_idx = 0; } #endif static int fxgmac_enable_ns_offload(struct fxgmac_pdata* pdata) { writereg(pdata->pAdapter, 0X00000011, pdata->base_mem + NS_OF_GLB_CTL); return 0; } static int fxgmac_disable_ns_offload(struct fxgmac_pdata* pdata) { writereg(pdata->pAdapter, 0X00000000, pdata->base_mem + NS_OF_GLB_CTL); return 0; } static int fxgmac_check_wake_pattern_fifo_pointer(struct fxgmac_pdata* pdata) { u32 regval; int ret = 0; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PMT_STA); regval = FXGMAC_SET_REG_BITS(regval, MAC_PMT_STA_RWKFILTERST_POS, MAC_PMT_STA_RWKFILTERST_LEN,1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PMT_STA); regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PMT_STA); regval = FXGMAC_GET_REG_BITS(regval, MAC_PMT_STA_RWKPTR_POS, MAC_PMT_STA_RWKPTR_LEN); if (regval != 0) { DPRINTK("Remote fifo pointer is not 0\n"); ret = -EINVAL; } return ret; } static int fxgmac_set_wake_pattern_mask(struct fxgmac_pdata* pdata, u32 filter_index, u8 register_index,u32 Data) { const u16 address_offset[16][3] = { {0x1020, 0x1024, 0x1028}, {0x102c, 0x1030, 0x1034}, {0x1038, 0x103c, 0x1040}, {0x1044, 0x1050, 0x1054}, {0x1058, 0x105c, 0x1060}, {0x1064, 0x1068, 0x106c}, {0x1070, 0x1074, 0x1078}, {0x107c, 0x1080, 0x1084}, {0x1088, 0x108c, 0x1090}, {0x1134, 0x113c, 0x1140}, {0x1208, 0x1200, 0x1204}, {0x1218, 0x1210, 0x1214}, {0x1228, 0x1220, 0x1224}, {0x1238, 0x1230, 0x1234}, {0x1248, 0x1240, 0x1244}, {0x1258, 0x1250, 0x1254}, }; if (filter_index > 15||register_index > 2) { DbgPrintF(MP_TRACE, "%s - Remote mask pointer is over range, filter_index:%d, register_index:0x%x\n", __FUNCTION__, filter_index, register_index); return -1; } writereg(pdata->pAdapter, Data, pdata->base_mem + address_offset[filter_index][register_index]); return 0; } static u16 wol_crc16(u8* pucframe, u16 uslen) { int i; union type16 { u16 raw; struct { u16 bit_0 : 1; u16 bit_1 : 1; u16 bit_2 : 1; u16 bit_3 : 1; u16 bit_4 : 1; u16 bit_5 : 1; u16 bit_6 : 1; u16 bit_7 : 1; u16 bit_8 : 1; u16 bit_9 : 1; u16 bit_10 : 1; u16 bit_11 : 1; u16 bit_12 : 1; u16 bit_13 : 1; u16 bit_14 : 1; u16 bit_15 : 1; }bits; }; union type8 { u16 raw; struct { u16 bit_0 : 1; u16 bit_1 : 1; u16 bit_2 : 1; u16 bit_3 : 1; u16 bit_4 : 1; u16 bit_5 : 1; u16 bit_6 : 1; u16 bit_7 : 1; }bits; }; union type16 crc, crc_comb; union type8 next_crc, rrpe_data; next_crc.raw = 0; crc.raw = 0xffff; for (i = 0; i < uslen;i++) { rrpe_data.raw = pucframe[i]; next_crc.bits.bit_0 = crc.bits.bit_15 ^ rrpe_data.bits.bit_0; next_crc.bits.bit_1 = crc.bits.bit_14 ^ next_crc.bits.bit_0 ^ rrpe_data.bits.bit_1; next_crc.bits.bit_2 = crc.bits.bit_13 ^ next_crc.bits.bit_1 ^ rrpe_data.bits.bit_2; next_crc.bits.bit_3 = crc.bits.bit_12 ^ next_crc.bits.bit_2 ^ rrpe_data.bits.bit_3; next_crc.bits.bit_4 = crc.bits.bit_11 ^ next_crc.bits.bit_3 ^ rrpe_data.bits.bit_4; next_crc.bits.bit_5 = crc.bits.bit_10 ^ next_crc.bits.bit_4 ^ rrpe_data.bits.bit_5; next_crc.bits.bit_6 = crc.bits.bit_9 ^ next_crc.bits.bit_5 ^ rrpe_data.bits.bit_6; next_crc.bits.bit_7 = crc.bits.bit_8 ^ next_crc.bits.bit_6 ^ rrpe_data.bits.bit_7; crc_comb.bits.bit_15 = crc.bits.bit_7 ^ next_crc.bits.bit_7; crc_comb.bits.bit_14 = crc.bits.bit_6; crc_comb.bits.bit_13 = crc.bits.bit_5; crc_comb.bits.bit_12 = crc.bits.bit_4; crc_comb.bits.bit_11 = crc.bits.bit_3; crc_comb.bits.bit_10 = crc.bits.bit_2; crc_comb.bits.bit_9 = crc.bits.bit_1 ^ next_crc.bits.bit_0; crc_comb.bits.bit_8 = crc.bits.bit_0 ^ next_crc.bits.bit_1; crc_comb.bits.bit_7 = next_crc.bits.bit_0 ^ next_crc.bits.bit_2; crc_comb.bits.bit_6 = next_crc.bits.bit_1 ^ next_crc.bits.bit_3; crc_comb.bits.bit_5 = next_crc.bits.bit_2 ^ next_crc.bits.bit_4; crc_comb.bits.bit_4 = next_crc.bits.bit_3 ^ next_crc.bits.bit_5; crc_comb.bits.bit_3 = next_crc.bits.bit_4 ^ next_crc.bits.bit_6; crc_comb.bits.bit_2 = next_crc.bits.bit_5 ^ next_crc.bits.bit_7; crc_comb.bits.bit_1 = next_crc.bits.bit_6; crc_comb.bits.bit_0 = next_crc.bits.bit_7; crc.raw = crc_comb.raw; } return crc.raw; } static int fxgmac_set_wake_pattern( struct fxgmac_pdata* pdata, struct wol_bitmap_pattern* wol_pattern, u32 pattern_cnt) { u32 i, j, kp, km, mask_index; int z; u16 map_index; u8 mask[MAX_PATTERN_SIZE]; u32 regval = 0; u32 total_cnt = 0, pattern_inherited_cnt = 0; u8* ptdata, * ptmask; if (pattern_cnt > MAX_PATTERN_COUNT) { DbgPrintF(MP_TRACE, "%s - Error: %d patterns, exceed %d, not supported!\n", __FUNCTION__, pattern_cnt, MAX_PATTERN_COUNT); return -1; } /* Reset the FIFO head pointer. */ if (fxgmac_check_wake_pattern_fifo_pointer(pdata)) { DbgPrintF(MP_TRACE, "%s - Warning: the remote pattern array pointer is not be 0\n", __FUNCTION__); return -1; } for (i = 0; i < pattern_cnt; i++) { memcpy(&pdata->pattern[i], wol_pattern + i, sizeof(wol_pattern[0])); if (pattern_cnt + pattern_inherited_cnt < MAX_PATTERN_COUNT) { if (wol_pattern[i].pattern_offset || !(wol_pattern[i].mask_info[0] & 0x01)) { memcpy(&pdata->pattern[pattern_cnt + pattern_inherited_cnt], wol_pattern + i, sizeof(wol_pattern[0])); pattern_inherited_cnt++; } } } total_cnt = pattern_cnt + pattern_inherited_cnt; /* * calculate the crc-16 of the mask pattern * print the pattern and mask for debug purpose. */ for (i = 0; i < total_cnt; i++) { /* Please program pattern[i] to NIC for pattern match wakeup. * pattern_size, pattern_info, mask_info */ //save the mask pattern mask_index = 0; map_index = 0; for (j = 0; j < pdata->pattern[i].mask_size; j++) { for (z = 0; z < ((j == (MAX_PATTERN_SIZE / 8 - 1)) ? 7 : 8); z++) { if (pdata->pattern[i].mask_info[j] & (0x01 << z)) { mask[map_index] = pdata->pattern[i].pattern_info[pdata->pattern[i].pattern_offset + mask_index]; map_index++; } mask_index++; } } //calculate the crc-16 of the mask pattern pdata->pattern[i].pattern_crc = wol_crc16(mask, map_index); // Print pattern match, for debug purpose. DbgPrintF(MP_LOUD, "%s - Pattern[%d]:", __FUNCTION__, i); for (kp = 0, km = 0; kp < sizeof(pdata->pattern[i].pattern_info); kp += 16, km += 2) { ptdata = &pdata->pattern[i].pattern_info[kp]; ptmask = &pdata->pattern[i].mask_info[km]; DBGPRINT(MP_LOUD, ("\n %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x Mask %02x-%02x", ptdata[0], ptdata[1], ptdata[2], ptdata[3], ptdata[4], ptdata[5], ptdata[6], ptdata[7], ptdata[8], ptdata[9], ptdata[10], ptdata[11], ptdata[12], ptdata[13], ptdata[14], ptdata[15], ptmask[0], ptmask[1])); } //fxgmac_dump_buffer(mask, map_index, 2); DbgPrintF(MP_LOUD, "WritePatternToNic62 the %d patterns crc = %x mask length = %d, mask_offset=%x.\n", i, pdata->pattern[i].pattern_crc, map_index, pdata->pattern[i].pattern_offset); memset(mask, 0, sizeof(mask)); } // Write patterns by FIFO block. for (i = 0; i < (total_cnt + 3) / 4; i++) { // 1. Write the first 4Bytes of Filter. writereg(pdata->pAdapter, ((pdata->pattern[i * 4 + 0].mask_info[3] & 0x7f) << 24) | (pdata->pattern[i * 4 + 0].mask_info[2] << 16) | (pdata->pattern[i * 4 + 0].mask_info[1] << 8) | (pdata->pattern[i * 4 + 0].mask_info[0] << 0), pdata->mac_regs + MAC_RWK_PAC); writereg(pdata->pAdapter, ((pdata->pattern[i * 4 + 1].mask_info[3] & 0x7f) << 24) | (pdata->pattern[i * 4 + 1].mask_info[2] << 16) | (pdata->pattern[i * 4 + 1].mask_info[1] << 8) | (pdata->pattern[i * 4 + 1].mask_info[0] << 0), pdata->mac_regs + MAC_RWK_PAC); writereg(pdata->pAdapter, ((pdata->pattern[i * 4 + 2].mask_info[3] & 0x7f) << 24) | (pdata->pattern[i * 4 + 2].mask_info[2] << 16) | (pdata->pattern[i * 4 + 2].mask_info[1] << 8) | (pdata->pattern[i * 4 + 2].mask_info[0] << 0), pdata->mac_regs + MAC_RWK_PAC); writereg(pdata->pAdapter, ((pdata->pattern[i * 4 + 3].mask_info[3] & 0x7f) << 24) | (pdata->pattern[i * 4 + 3].mask_info[2] << 16) | (pdata->pattern[i * 4 + 3].mask_info[1] << 8) | (pdata->pattern[i * 4 + 3].mask_info[0] << 0), pdata->mac_regs + MAC_RWK_PAC); // 2. Write the Filter Command. regval = 0; // Set filter enable bit. regval |= ((i * 4 + 0) < total_cnt) ? (0x1 << 0) : 0x0; regval |= ((i * 4 + 1) < total_cnt) ? (0x1 << 8) : 0x0; regval |= ((i * 4 + 2) < total_cnt) ? (0x1 << 16) : 0x0; regval |= ((i * 4 + 3) < total_cnt) ? (0x1 << 24) : 0x0; // Set filter address type, 0- unicast, 1 - multicast. regval |= (i * 4 + 0 >= total_cnt) ? 0x0 : (i * 4 + 0 >= pattern_cnt) ? (0x1 << (3 + 0)) : pdata->pattern[i * 4 + 0].pattern_offset ? 0x0 : !(pdata->pattern[i * 4 + 0].mask_info[0] & 0x01) ? 0x0 : (pdata->pattern[i * 4 + 0].pattern_info[0] & 0x01) ? (0x1 << (3 + 0)) : 0x0; regval |= (i * 4 + 1 >= total_cnt) ? 0x0 : (i * 4 + 1 >= pattern_cnt) ? (0x1 << (3 + 8)) : pdata->pattern[i * 4 + 1].pattern_offset ? 0x0 : !(pdata->pattern[i * 4 + 1].mask_info[0] & 0x01) ? 0x0 : (pdata->pattern[i * 4 + 1].pattern_info[0] & 0x01) ? (0x1 << (3 + 8)) : 0x0; regval |= (i * 4 + 2 >= total_cnt) ? 0x0 : (i * 4 + 2 >= pattern_cnt) ? (0x1 << (3 + 16)) : pdata->pattern[i * 4 + 2].pattern_offset ? 0x0 : !(pdata->pattern[i * 4 + 2].mask_info[0] & 0x01) ? 0x0 : (pdata->pattern[i * 4 + 2].pattern_info[0] & 0x01) ? (0x1 << (3 + 16)) : 0x0; regval |= (i * 4 + 3 >= total_cnt) ? 0x0 : (i * 4 + 3 >= pattern_cnt) ? (0x1 << (3 + 24)) : pdata->pattern[i * 4 + 3].pattern_offset ? 0x0 : !(pdata->pattern[i * 4 + 3].mask_info[0] & 0x01) ? 0x0 : (pdata->pattern[i * 4 + 3].pattern_info[0] & 0x01) ? (0x1 << (3 + 24)) : 0x0; writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_RWK_PAC); //DbgPrintF(MP_LOUD, "FilterCMD 0x%08x", regval); // 3. Write the mask offset. writereg(pdata->pAdapter, (pdata->pattern[i * 4 + 3].pattern_offset << 24) | (pdata->pattern[i * 4 + 2].pattern_offset << 16) | (pdata->pattern[i * 4 + 1].pattern_offset << 8) | (pdata->pattern[i * 4 + 0].pattern_offset << 0), pdata->mac_regs + MAC_RWK_PAC); // 4. Write the masked data CRC. writereg(pdata->pAdapter, (pdata->pattern[i * 4 + 1].pattern_crc << 16) | (pdata->pattern[i * 4 + 0].pattern_crc << 0), pdata->mac_regs + MAC_RWK_PAC); writereg(pdata->pAdapter, (pdata->pattern[i * 4 + 3].pattern_crc << 16) | (pdata->pattern[i * 4 + 2].pattern_crc << 0), pdata->mac_regs + MAC_RWK_PAC); } for (i = 0; i < total_cnt; i++) { fxgmac_set_wake_pattern_mask(pdata, i, 0, ((pdata->pattern[i].mask_info[7] & 0x7f) << (24 + 1)) | (pdata->pattern[i].mask_info[6] << (16 + 1)) | (pdata->pattern[i].mask_info[5] << (8 + 1)) | (pdata->pattern[i].mask_info[4] << (0 + 1)) | ((pdata->pattern[i].mask_info[3] & 0x80) >> 7));//global manager regitster mask bit 31~62 fxgmac_set_wake_pattern_mask(pdata, i, 1, ((pdata->pattern[i].mask_info[11] & 0x7f) << (24 + 1)) | (pdata->pattern[i].mask_info[10] << (16 + 1)) | (pdata->pattern[i].mask_info[9] << (8 + 1)) | (pdata->pattern[i].mask_info[8] << (0 + 1)) | ((pdata->pattern[i].mask_info[7] & 0x80) >> 7));//global manager regitster mask bit 63~94 fxgmac_set_wake_pattern_mask(pdata, i, 2, \ ((pdata->pattern[i].mask_info[15] & 0x7f) << (24 + 1)) | (pdata->pattern[i].mask_info[14] << (16 + 1)) | (pdata->pattern[i].mask_info[13] << (8 + 1)) | (pdata->pattern[i].mask_info[12] << (0 + 1)) | ((pdata->pattern[i].mask_info[11] & 0x80) >> 7));//global manager regitster mask bit 95~126 } return 0; } static int fxgmac_enable_wake_pattern(struct fxgmac_pdata* pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PMT_STA); regval = FXGMAC_SET_REG_BITS(regval, MAC_PMT_STA_RWKFILTERST_POS, MAC_PMT_STA_RWKFILTERST_LEN,1); regval = FXGMAC_SET_REG_BITS(regval, MAC_PMT_STA_RWKPKTEN_POS, MAC_PMT_STA_RWKPKTEN_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PMT_STA); regval = readreg(pdata->pAdapter, pdata->base_mem + WOL_CTL); regval = FXGMAC_SET_REG_BITS(regval, WOL_PKT_EN_POS, WOL_PKT_EN_LEN, 1); writereg(pdata->pAdapter, regval, pdata->base_mem + WOL_CTL); return 0; } static int fxgmac_disable_wake_pattern(struct fxgmac_pdata* pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PMT_STA); regval = FXGMAC_SET_REG_BITS(regval, MAC_PMT_STA_RWKFILTERST_POS, MAC_PMT_STA_RWKFILTERST_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_PMT_STA_RWKPKTEN_POS, MAC_PMT_STA_RWKPKTEN_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PMT_STA); regval = readreg(pdata->pAdapter, pdata->base_mem + WOL_CTL); regval = FXGMAC_SET_REG_BITS(regval, WOL_PKT_EN_POS, WOL_PKT_EN_LEN, 0); writereg(pdata->pAdapter, regval, pdata->base_mem + WOL_CTL); return 0; } static int fxgmac_enable_wake_magic_pattern(struct fxgmac_pdata* pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PMT_STA); regval = FXGMAC_SET_REG_BITS(regval, MAC_PMT_STA_MGKPKTEN_POS, MAC_PMT_STA_MGKPKTEN_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PMT_STA); regval = readreg(pdata->pAdapter, pdata->base_mem + WOL_CTL); regval = FXGMAC_SET_REG_BITS(regval, WOL_PKT_EN_POS, WOL_PKT_EN_LEN, 1); writereg(pdata->pAdapter, regval, pdata->base_mem + WOL_CTL); /* Enable PME Enable Bit. */ cfg_r32(pdata, REG_PM_STATCTRL, ®val); regval = FXGMAC_SET_REG_BITS(regval, PM_CTRLSTAT_PME_EN_POS, PM_CTRLSTAT_PME_EN_LEN, 1); cfg_w32(pdata, REG_PM_STATCTRL, regval); return 0; } static int fxgmac_disable_wake_magic_pattern(struct fxgmac_pdata* pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->base_mem + WOL_CTL); regval = FXGMAC_SET_REG_BITS(regval, WOL_PKT_EN_POS, WOL_PKT_EN_LEN, 0); writereg(pdata->pAdapter, regval, pdata->base_mem + WOL_CTL); regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PMT_STA); regval = FXGMAC_SET_REG_BITS(regval, MAC_PMT_STA_MGKPKTEN_POS, MAC_PMT_STA_MGKPKTEN_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PMT_STA); return 0; } #if defined(FUXI_PM_WPI_READ_FEATURE_EN) && FUXI_PM_WPI_READ_FEATURE_EN /* * enable Wake packet indication. called to enable before sleep/hibernation * and no needed to call disable for that, fxgmac_get_wake_packet_indication will clear to normal once done. */ static void fxgmac_enable_wake_packet_indication(struct fxgmac_pdata* pdata, int en) { u32 val_wpi_crtl0; /* read-clear WoL event. */ readreg(pdata->pAdapter, pdata->base_mem + MGMT_WOL_CTRL); /* get wake packet information */ val_wpi_crtl0 = (u32)readreg(pdata->pAdapter, pdata->base_mem + MGMT_WPI_CTRL0); /* prepare to write packet data by write wpi_mode to 1 */ val_wpi_crtl0 = FXGMAC_SET_REG_BITS(val_wpi_crtl0, MGMT_WPI_CTRL0_WPI_MODE_POS, MGMT_WPI_CTRL0_WPI_MODE_LEN, (en ? MGMT_WPI_CTRL0_WPI_MODE_WR : MGMT_WPI_CTRL0_WPI_MODE_NORMAL)); writereg(pdata->pAdapter, val_wpi_crtl0, pdata->base_mem + MGMT_WPI_CTRL0); DbgPrintF(MP_TRACE, "%s - WPI pkt enable=%d, reg=%08x.\n", __FUNCTION__, en, val_wpi_crtl0); return; } /* * this function read Wake up packet after MDIS resume * input: * pdata * wpi_buf container of a packet. * buf_size size of the packet container. since HW limit to 14bits, ie 16KB all together. * output: * wake_reason from HW, we can indentify 1)magic packet, or 2)pattern(remote wake packet) or WAKE_REASON_HW_ERR indicates err * packet_size length of the wake packet. 0 indicates exception. * */ static void fxgmac_get_wake_packet_indication(struct fxgmac_pdata* pdata, int* wake_reason, u32* wake_pattern_number, u8* wpi_buf, u32 buf_size, u32* packet_size) { u32 i, regval, val_wpi_crtl0, *dw_wpi_buf; u32 data_len, data_len_dw, b_need_pkt = 0; *wake_reason = WAKE_REASON_NONE; *packet_size = 0; fxgmac_release_phy(pdata); #if 1 /* try to check wake reason. GMAC reg 20c0 only tells Magic or remote-pattern * read from MGMT_WOL_CTRL, 1530 instead. */ regval = (u32)readreg(pdata->pAdapter, pdata->base_mem + MGMT_WOL_CTRL); DbgPrintF(MP_TRACE, "%s - 0x1530=%x.\n", __FUNCTION__, regval); if (!regval) { DbgPrintF(MP_TRACE, "%s - nothing for WPI pkt.\n", __FUNCTION__); return; } if (regval & MGMT_WOL_CTRL_WPI_MGC_PKT) { *wake_reason = WAKE_REASON_MAGIC; b_need_pkt = 1; } else if (regval & MGMT_WOL_CTRL_WPI_RWK_PKT) { *wake_reason = WAKE_REASON_PATTERNMATCH; b_need_pkt = 1; *wake_pattern_number = 0; /* * wake_pattern_number, HW should tell,,tbd */ for (i = 0;i < MAX_PATTERN_COUNT;i++) { if (regval & (MGMT_WOL_CTRL_WPI_RWK_PKT_NUMBER << i)) { *wake_pattern_number = i; break; } } //*wake_pattern_number = regval&MGMT_WOL_CTRL_WPI_RWK_PKT_NUMBER; } else if (regval & MGMT_WOL_CTRL_WPI_LINK_CHG) { *wake_reason = WAKE_REASON_LINK; } #else /* for 20c0 */ regval = (u32)readreg(pdata->mac_regs + MAC_PMT_STA); DbgPrintF(MP_TRACE, "%s - 0x20c0=%x.\n", __FUNCTION__, regval); if (FXGMAC_GET_REG_BITS(regval, MAC_PMT_STA_MGKPRCVD_POS, MAC_PMT_STA_MGKPRCVD_LEN)) { *wake_reason = WAKE_REASON_MAGIC; b_need_pkt = 1; DbgPrintF(MP_TRACE, "%s - waken up by Magic.\n", __FUNCTION__); } else if (FXGMAC_GET_REG_BITS(regval, MAC_PMT_STA_RWKPRCVD_POS, MAC_PMT_STA_RWKPRCVD_LEN)) { *wake_reason = WAKE_REASON_PATTERNMATCH; b_need_pkt = 1; DbgPrintF(MP_TRACE, "%s - waken up by Pattern.\n", __FUNCTION__); } #endif if (!b_need_pkt) { DbgPrintF(MP_TRACE, "%s - wake by link and no WPI pkt.\n", __FUNCTION__); return; } /* get wake packet information */ val_wpi_crtl0 = (u32)readreg(pdata->pAdapter, pdata->base_mem + MGMT_WPI_CTRL0); if (val_wpi_crtl0 & MGMT_WPI_CTRL0_WPI_FAIL) { *wake_reason = WAKE_REASON_HW_ERR; DbgPrintF(MP_TRACE, "%s - WPI pkt fail from hw.\n", __FUNCTION__); return; } *packet_size = FXGMAC_GET_REG_BITS(val_wpi_crtl0, MGMT_WPI_CTRL0_WPI_PKT_LEN_POS, MGMT_WPI_CTRL0_WPI_PKT_LEN_LEN); if (0 == *packet_size) { *wake_reason = WAKE_REASON_HW_ERR; DbgPrintF(MP_TRACE, "%s - WPI pkt len is 0 from hw.\n", __FUNCTION__); return; } DbgPrintF(MP_TRACE, "%s - WPI pkt len from hw, *packet_size=%u.\n", __FUNCTION__, *packet_size); if (buf_size < *packet_size) { DbgPrintF(MP_WARN, "%s - too small buf_size=%u, WPI pkt len is %u.\n", __FUNCTION__, buf_size, *packet_size); data_len = buf_size; } else { data_len = *packet_size; } /* prepare to read packet data by write wpi_mode to 2 */ val_wpi_crtl0 = FXGMAC_SET_REG_BITS(val_wpi_crtl0, MGMT_WPI_CTRL0_WPI_MODE_POS, MGMT_WPI_CTRL0_WPI_MODE_LEN, MGMT_WPI_CTRL0_WPI_MODE_RD); writereg(pdata->pAdapter, val_wpi_crtl0, pdata->base_mem + MGMT_WPI_CTRL0); dw_wpi_buf = (u32*)wpi_buf; data_len_dw = (data_len + 3) / 4; i = 0; DbgPrintF(MP_TRACE, "%s - before retrieve, len=%d, len_dw=%d, reg_wpi_ctrl0=%08x.\n", __FUNCTION__, data_len, data_len_dw, val_wpi_crtl0); while ((0 == (val_wpi_crtl0 & MGMT_WPI_CTRL0_WPI_OP_DONE))) { if (i < data_len_dw) { regval = (u32)readreg(pdata->pAdapter, pdata->base_mem + MGMT_WPI_CTRL1_DATA); /*dw_wpi_buf[i] = SWAP_BYTES_32(regval);*/ dw_wpi_buf[i] = regval; //DbgPrintF(MP_TRACE, "%s - read data, reg=%x, data[%d]=%08x.\n", __FUNCTION__, MGMT_WPI_CTRL1_DATA, i, dw_wpi_buf[i]); } else { break; } val_wpi_crtl0 = (u32)readreg(pdata->pAdapter, pdata->base_mem + MGMT_WPI_CTRL0); i++; } if (*packet_size <= MAC_CRC_LENGTH) { DbgPrintF(MP_TRACE, "%s - Warning, WPI pkt len is less 4 from hw.\n", __FUNCTION__); return; } *packet_size -= MAC_CRC_LENGTH; /* once read data complete and write wpi_mode to 0, normal */ val_wpi_crtl0 = FXGMAC_SET_REG_BITS(val_wpi_crtl0, MGMT_WPI_CTRL0_WPI_MODE_POS, MGMT_WPI_CTRL0_WPI_MODE_LEN, MGMT_WPI_CTRL0_WPI_MODE_NORMAL); writereg(pdata->pAdapter, val_wpi_crtl0, pdata->base_mem + MGMT_WPI_CTRL0); DbgPrintF(MP_TRACE, "%s - WPI done and back to normal mode, reg=%08x, read data=%dB.\n", __FUNCTION__, val_wpi_crtl0, i * 4); return; } #endif /* FUXI_PM_WPI_READ_FEATURE_EN */ static int fxgmac_enable_wake_link_change(struct fxgmac_pdata* pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->base_mem + WOL_CTL); regval = FXGMAC_SET_REG_BITS(regval, WOL_LINKCHG_EN_POS, WOL_LINKCHG_EN_LEN, 1); writereg(pdata->pAdapter, regval, pdata->base_mem + WOL_CTL); return 0; } static int fxgmac_disable_wake_link_change(struct fxgmac_pdata* pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->base_mem + WOL_CTL); regval = FXGMAC_SET_REG_BITS(regval, WOL_LINKCHG_EN_POS, WOL_LINKCHG_EN_LEN, 0); writereg(pdata->pAdapter, regval, pdata->base_mem + WOL_CTL); return 0; } #endif // LINUX/_WIN64/_WIN32 #ifdef LINUX static void fxgmac_config_wol(struct fxgmac_pdata *pdata, int en) { /* enable or disable WOL. this function only set wake-up type, and power related configure * will be in other place, see power management. */ if (!pdata->hw_feat.rwk) { netdev_err(pdata->netdev, "error configuring WOL - not supported.\n"); return; } fxgmac_disable_wake_magic_pattern(pdata); fxgmac_disable_wake_pattern(pdata); fxgmac_disable_wake_link_change(pdata); if(en) { /* config mac address for rx of magic or ucast */ fxgmac_set_mac_address(pdata, (u8*)(pdata->netdev->dev_addr)); /* Enable Magic packet */ if (pdata->expansion.wol & WAKE_MAGIC) { fxgmac_enable_wake_magic_pattern(pdata); } /* Enable global unicast packet */ if (pdata->expansion.wol & WAKE_UCAST || pdata->expansion.wol & WAKE_MCAST || pdata->expansion.wol & WAKE_BCAST || pdata->expansion.wol & WAKE_ARP) { fxgmac_enable_wake_pattern(pdata); } /* Enable ephy link change */ if ((FXGMAC_WOL_UPON_EPHY_LINK) && (pdata->expansion.wol & WAKE_PHY)) { fxgmac_enable_wake_link_change(pdata); } } device_set_wakeup_enable(/*pci_dev_to_dev*/(pdata->dev), en); DPRINTK("config_wol callout\n"); } #endif static int fxgmac_get_ephy_state(struct fxgmac_pdata* pdata) { u32 value; value = readreg(pdata->pAdapter, pdata->base_mem + MGMT_EPHY_CTRL); return value; } static void fxgmac_enable_dma_interrupts(struct fxgmac_pdata *pdata) { #ifndef DPDK unsigned int dma_ch_isr, dma_ch_ier; struct fxgmac_channel *channel; unsigned int i; #ifdef NIC_NET_ADAPETERCX u32 regval; //config interrupt to level signal regval = (u32)readreg(pdata->pAdapter, pdata->mac_regs + DMA_MR); regval = FXGMAC_SET_REG_BITS(regval, DMA_MR_INTM_POS, DMA_MR_INTM_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, DMA_MR_QUREAD_POS, DMA_MR_QUREAD_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + DMA_MR); #endif channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { /* Clear all the interrupts which are set */ dma_ch_isr = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_SR)); writereg(pdata->pAdapter, dma_ch_isr, FXGMAC_DMA_REG(channel, DMA_CH_SR)); /* Clear all interrupt enable bits */ dma_ch_ier = 0; /* Enable following interrupts * NIE - Normal Interrupt Summary Enable * AIE - Abnormal Interrupt Summary Enable * FBEE - Fatal Bus Error Enable */ dma_ch_ier = FXGMAC_SET_REG_BITS(dma_ch_ier, DMA_CH_IER_NIE_POS, DMA_CH_IER_NIE_LEN, 1); /* dma_ch_ier = FXGMAC_SET_REG_BITS(dma_ch_ier, DMA_CH_IER_AIE_POS, DMA_CH_IER_AIE_LEN, 1); */ dma_ch_ier = FXGMAC_SET_REG_BITS(dma_ch_ier, DMA_CH_IER_FBEE_POS, DMA_CH_IER_FBEE_LEN, 1); if (channel->tx_ring) { /* Enable the following Tx interrupts * TIE - Transmit Interrupt Enable (unless using * per channel interrupts) */ if (!pdata->per_channel_irq) dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_TIE_POS, DMA_CH_IER_TIE_LEN, 1); if (FXGMAC_IS_CHANNEL_WITH_TX_IRQ(i)) { if (pdata->per_channel_irq) { dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_TIE_POS, DMA_CH_IER_TIE_LEN, 1); /*dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_TBUE_POS, DMA_CH_IER_TBUE_LEN, 1);*/ } } } if (channel->rx_ring) { /* Enable following Rx interrupts * RBUE - Receive Buffer Unavailable Enable * RIE - Receive Interrupt Enable (unless using * per channel interrupts) */ dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_RBUE_POS, DMA_CH_IER_RBUE_LEN, 1); //2022-04-20 xiaojiang comment //windows driver set the per_channel_irq to be zero, Linux driver also comment this, so comment it directly //if (!pdata->per_channel_irq) dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_RIE_POS, DMA_CH_IER_RIE_LEN, 1); } writereg(pdata->pAdapter, dma_ch_ier, FXGMAC_DMA_REG(channel, DMA_CH_IER)); } #else struct fxgmac_tx_queue *txq; unsigned int dma_ch_isr, dma_ch_ier; unsigned int i; for (i = 0; i < pdata->expansion.eth_dev->data->nb_tx_queues; i++) { txq = pdata->expansion.eth_dev->data->tx_queues[i]; /* Clear all the interrupts which are set */ dma_ch_isr = FXGMAC_DMA_IOREAD(txq, DMA_CH_SR); FXGMAC_DMA_IOWRITE(txq, DMA_CH_SR, dma_ch_isr); /* Clear all interrupt enable bits */ dma_ch_ier = 0; /* Enable following interrupts * NIE - Normal Interrupt Summary Enable * AIE - Abnormal Interrupt Summary Enable * FBEE - Fatal Bus Error Enable */ FXGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, NIE, 1);//0 fx 1 FXGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, AIE, 1); FXGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, FBEE, 1); /* Enable following Rx interrupts * RBUE - Receive Buffer Unavailable Enable * RIE - Receive Interrupt Enable (unless using * per channel interrupts in edge triggered * mode) */ FXGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RBUE, 1);//0 fx 1 FXGMAC_SET_BITS(dma_ch_ier, DMA_CH_IER, RIE, 0);// 0 fx 1 FXGMAC_DMA_IOWRITE(txq, DMA_CH_IER, dma_ch_ier); } #endif } static void fxgmac_enable_mtl_interrupts(struct fxgmac_pdata *pdata) { unsigned int q_count, i; unsigned int mtl_q_isr; q_count = max(pdata->hw_feat.tx_q_cnt, pdata->hw_feat.rx_q_cnt); for (i = 0; i < q_count; i++) { /* Clear all the interrupts which are set */ mtl_q_isr = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_ISR)); writereg(pdata->pAdapter, mtl_q_isr, FXGMAC_MTL_REG(pdata, i, MTL_Q_ISR)); /* No MTL interrupts to be enabled */ writereg(pdata->pAdapter, 0, FXGMAC_MTL_REG(pdata, i, MTL_Q_IER)); } } static void fxgmac_enable_mac_interrupts(struct fxgmac_pdata *pdata) { unsigned int mac_ier = 0; u32 regval; /* Enable Timestamp interrupt */ mac_ier = FXGMAC_SET_REG_BITS(mac_ier, MAC_IER_TSIE_POS, MAC_IER_TSIE_LEN, 1); writereg(pdata->pAdapter, mac_ier, pdata->mac_regs + MAC_IER); /* Enable all counter interrupts */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MMC_RIER); regval = FXGMAC_SET_REG_BITS(regval, MMC_RIER_ALL_INTERRUPTS_POS, MMC_RIER_ALL_INTERRUPTS_LEN, 0xffffffff); writereg(pdata->pAdapter, regval, pdata->mac_regs + MMC_RIER); regval = readreg(pdata->pAdapter, pdata->mac_regs + MMC_TIER); regval = FXGMAC_SET_REG_BITS(regval, MMC_TIER_ALL_INTERRUPTS_POS, MMC_TIER_ALL_INTERRUPTS_LEN, 0xffffffff); writereg(pdata->pAdapter, regval, pdata->mac_regs + MMC_TIER); } static int fxgmac_set_fxgmii_2500_speed(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_PS_POS, MAC_CR_PS_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_FES_POS, MAC_CR_FES_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_DM_POS, MAC_CR_DM_LEN , pdata->phy_duplex); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); return 0; } static int fxgmac_set_fxgmii_1000_speed(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_PS_POS, MAC_CR_PS_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_FES_POS, MAC_CR_FES_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_DM_POS, MAC_CR_DM_LEN , pdata->phy_duplex); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); return 0; } static int fxgmac_set_fxgmii_100_speed(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_PS_POS, MAC_CR_PS_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_FES_POS, MAC_CR_FES_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_DM_POS, MAC_CR_DM_LEN , pdata->phy_duplex); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); return 0; } static int fxgmac_set_fxgmii_10_speed(struct fxgmac_pdata *pdata) { u32 regval; regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_PS_POS, MAC_CR_PS_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_FES_POS, MAC_CR_FES_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_DM_POS, MAC_CR_DM_LEN , pdata->phy_duplex); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); return 0; } /** * fxgmac_check_phy_link - Get link/speed status * @pdata: pointer to gmac structure * @speed: pointer to link speed * @link_up: true is link is up, false otherwise * @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 int fxgmac_check_phy_link(struct fxgmac_pdata *pdata, u32 *speed, bool *link_up, bool link_up_wait_to_complete) { #if defined(LINUX) || defined(DPDK) u16 link_reg = 0; //DPRINTK("fxgmac_check_phy_link callin\n"); #ifndef DPDK struct net_device *netdev = pdata->netdev; if (netdev->base_addr) { link_reg = (u16)(* ((u32 *)(netdev->base_addr + MGMT_EPHY_CTRL))); #else (void) link_up_wait_to_complete; if (pdata->base_mem) { link_reg = (u16)readreg(pdata->pAdapter, pdata->base_mem + MGMT_EPHY_CTRL); pdata->phy_duplex = !!(link_reg&0x4);//need check #endif /* * check register address 0x1004 * b[6:5] ephy_pause * b[4:3] ephy_speed 0b10 1000m 0b01 100m * b[2] ephy_duplex * b[1] ephy_link * b[0] ephy_reset. should be set to 1 before use phy. */ *link_up = false; if (link_reg & MGMT_EPHY_CTRL_STA_EPHY_RELEASE) { if(link_up) { *link_up = (link_reg & MGMT_EPHY_CTRL_STA_EPHY_LINKUP) ? true : false; } if(speed) *speed = (link_reg & MGMT_EPHY_CTRL_STA_SPEED_MASK) >> MGMT_EPHY_CTRL_STA_SPEED_POS; } else { DPRINTK("fxgmac_check_phy_link ethernet PHY not released.\n"); return -1; } }else { DPRINTK("fxgmac_check_phy_link null base addr err\n"); return -1; } //DPRINTK("fxgmac_check_phy_link callout, reg=%#x\n", link_reg); #else pdata = pdata; speed = speed; link_up = link_up; link_up_wait_to_complete = link_up_wait_to_complete; #endif return 0; } static int fxgmac_config_mac_speed(struct fxgmac_pdata *pdata) { switch (pdata->phy_speed) { case SPEED_2500: fxgmac_set_fxgmii_2500_speed(pdata); break; case SPEED_1000: fxgmac_set_fxgmii_1000_speed(pdata); break; case SPEED_100: fxgmac_set_fxgmii_100_speed(pdata); break; case SPEED_10: fxgmac_set_fxgmii_10_speed(pdata); break; } return 0; } static int fxgmac_write_ephy_reg(struct fxgmac_pdata* pdata, u32 reg_id, u32 data) { u32 regval; u32 mdioctrl = reg_id * 0x10000 + 0x8000205; int busy = 15; writereg(pdata->pAdapter, data, pdata->mac_regs + MAC_MDIO_DATA); writereg(pdata->pAdapter, mdioctrl, pdata->mac_regs + MAC_MDIO_ADDRESS); do { regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_MDIO_ADDRESS); busy--; }while((regval & MAC_MDIO_ADDRESS_BUSY) && (busy)); DPRINTK("fxgmac_write_ephy_reg id %d %s, ctrl=0x%08x, data=0x%08x\n", reg_id, (regval & 0x1)?"err" : "ok", regval, data); return (regval & MAC_MDIO_ADDRESS_BUSY) ? -1 : 0; //-1 indicates err } static int fxgmac_read_ephy_reg(struct fxgmac_pdata* pdata, u32 reg_id, u32*data) { u32 regval = 0, regret; u32 mdioctrl = reg_id * 0x10000 + 0x800020d; int busy = 15; writereg(pdata->pAdapter, mdioctrl, pdata->mac_regs + MAC_MDIO_ADDRESS); do { regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_MDIO_ADDRESS); busy--; //DPRINTK("fxgmac_read_ephy_reg, check busy %d, ctrl=0x%08x\n", busy, regval); }while((regval & MAC_MDIO_ADDRESS_BUSY) && (busy)); if (0 == (regval & MAC_MDIO_ADDRESS_BUSY)) { regret = readreg(pdata->pAdapter, pdata->mac_regs + MAC_MDIO_DATA); if(data) *data = regret; //DPRINTK("fxgmac_read_ephy_reg ok, reg=0x%02x, ctrl=0x%08x, data=0x%08x\n", reg_id, regval, *data); return regret; } DPRINTK("fxgmac_read_ephy_reg id=0x%02x err, busy=%d, ctrl=0x%08x.\n", reg_id, busy, regval); return -1; } static int fxgmac_write_ephy_mmd_reg(struct fxgmac_pdata* pdata, u32 reg_id, u32 mmd, u32 data) { u32 regval; u32 mdioctrl = (mmd << 16) + 0x8000207; u32 regdata = (reg_id << 16) + data; //for phy mmd reg r/w operation, set more delay time than phy mii reg r/w int busy = 60; writereg(pdata->pAdapter, regdata, pdata->mac_regs + MAC_MDIO_DATA); writereg(pdata->pAdapter, mdioctrl, pdata->mac_regs + MAC_MDIO_ADDRESS); do { regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_MDIO_ADDRESS); busy--; } while ((regval & MAC_MDIO_ADDRESS_BUSY) && (busy)); DPRINTK("fxgmac_write_ephy_mmd_reg id %d mmd %d %s, ctrl=0x%08x, data=0x%08x\n", reg_id, mmd, (regval & 0x1) ? "err" : "ok", regval, data); //DbgPrintF(MP_TRACE, "fxgmac_write_ephy_mmd_reg id %d %s, ctrl=0x%08x, data=0x%08x busy %d", reg_id, (regval & 0x1) ? "err" : "ok", regval, data, busy); return (regval & MAC_MDIO_ADDRESS_BUSY) ? -1 : 0; //-1 indicates err } #if !defined(LINUX) && !defined(DPDK) static int fxgmac_read_ephy_mmd_reg(struct fxgmac_pdata* pdata, u32 reg_id, u32 mmd, u32* data) { u32 regval = 0, regret; u32 mdioctrl = (mmd << 16) + 0x800020f; u32 regdata = (reg_id << 16); //for phy mmd reg r/w operation, set more delay time than phy mii reg r/w int busy = 60; writereg(pdata->pAdapter, regdata, pdata->mac_regs + MAC_MDIO_DATA); writereg(pdata->pAdapter, mdioctrl, pdata->mac_regs + MAC_MDIO_ADDRESS); do { regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_MDIO_ADDRESS); busy--; } while ((regval & MAC_MDIO_ADDRESS_BUSY) && (busy)); if (0 == (regval & MAC_MDIO_ADDRESS_BUSY)) { regret = readreg(pdata->pAdapter, pdata->mac_regs + MAC_MDIO_DATA); if (data) *data = (regret & 0xffff); return regret; } DPRINTK("fxgmac_read_ephy_mmd_reg id=0x%02x mmd %d err, busy=%d, ctrl=0x%08x\n", reg_id, mmd, busy, regval); //DbgPrintF(MP_TRACE, "fxgmac_read_ephy_mmd_reg id=0x%02x err, busy=%d, ctrl=0x%08x\n", reg_id, busy, regval); return -1; } #endif static void fxgmac_config_flow_control(struct fxgmac_pdata* pdata) { #ifndef UEFI u32 regval = 0; #endif fxgmac_config_tx_flow_control(pdata); fxgmac_config_rx_flow_control(pdata); #ifndef UEFI fxgmac_read_ephy_reg(pdata, REG_MII_ADVERTISE, ®val); //set auto negotiation advertisement pause ability if (pdata->tx_pause || pdata->rx_pause) { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_PAUSE_POS, PHY_MII_ADVERTISE_PAUSE_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_ASYPAUSE_POS, PHY_MII_ADVERTISE_ASYPAUSE_LEN, 1); } else { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_PAUSE_POS, PHY_MII_ADVERTISE_PAUSE_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_ASYPAUSE_POS, PHY_MII_ADVERTISE_ASYPAUSE_LEN, 0); } fxgmac_write_ephy_reg(pdata, REG_MII_ADVERTISE, regval); //after change the auto negotiation advertisement need to soft reset fxgmac_read_ephy_reg(pdata, REG_MII_BMCR, ®val); regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_RESET_POS, PHY_CR_RESET_LEN, 1); fxgmac_write_ephy_reg(pdata, REG_MII_BMCR, regval); #endif } static int fxgmac_set_ephy_autoneg_advertise(struct fxgmac_pdata* pdata, struct fxphy_ag_adv phy_ag_adv) { u32 regval = 0, ret = 0; if (phy_ag_adv.auto_neg_en) { fxgmac_read_ephy_reg(pdata, REG_MII_BMCR, ®val); regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN, 1); ret |= fxgmac_write_ephy_reg(pdata, REG_MII_BMCR, regval); } else { fxgmac_read_ephy_reg(pdata, REG_MII_BMCR, ®val); regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN, 0); ret |= fxgmac_write_ephy_reg(pdata, REG_MII_BMCR, regval); } fxgmac_read_ephy_reg(pdata, REG_MII_CTRL1000, ®val); if (phy_ag_adv.full_1000m) { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_CTRL1000_1000FULL_POS, PHY_MII_CTRL1000_1000FULL_LEN, 1); } else { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_CTRL1000_1000FULL_POS, PHY_MII_CTRL1000_1000FULL_LEN, 0); } if (phy_ag_adv.half_1000m) { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_CTRL1000_1000HALF_POS, PHY_MII_CTRL1000_1000HALF_LEN, 1); } else { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_CTRL1000_1000HALF_POS, PHY_MII_CTRL1000_1000HALF_LEN, 0); } ret |= fxgmac_write_ephy_reg(pdata, REG_MII_CTRL1000, regval); fxgmac_read_ephy_reg(pdata, REG_MII_ADVERTISE, ®val); if (phy_ag_adv.full_100m) { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_100FULL_POS, PHY_MII_ADVERTISE_100FULL_LEN, 1); } else { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_100FULL_POS, PHY_MII_ADVERTISE_100FULL_LEN, 0); } if (phy_ag_adv.half_100m) { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_100HALF_POS, PHY_MII_ADVERTISE_100HALF_LEN, 1); } else { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_100HALF_POS, PHY_MII_ADVERTISE_100HALF_LEN, 0); } if (phy_ag_adv.full_10m) { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_10FULL_POS, PHY_MII_ADVERTISE_10FULL_LEN, 1); } else { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_10FULL_POS, PHY_MII_ADVERTISE_10FULL_LEN, 0); } if (phy_ag_adv.half_10m) { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_10HALF_POS, PHY_MII_ADVERTISE_10HALF_LEN, 1); } else { regval = FXGMAC_SET_REG_BITS(regval, PHY_MII_ADVERTISE_10HALF_POS, PHY_MII_ADVERTISE_10HALF_LEN, 0); } ret |= fxgmac_write_ephy_reg(pdata, REG_MII_ADVERTISE, regval); //after change the auto negotiation advertisement need to soft reset fxgmac_read_ephy_reg(pdata, REG_MII_BMCR, ®val); regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_RESET_POS, PHY_CR_RESET_LEN, 1); ret |= fxgmac_write_ephy_reg(pdata, REG_MII_BMCR, regval); return ret; } static int fxgmac_phy_config(struct fxgmac_pdata* pdata) { struct fxphy_ag_adv phy_ag_adv; if (pdata->phy_autoeng) { phy_ag_adv.auto_neg_en = 1; } else { phy_ag_adv.auto_neg_en = 0; } switch (pdata->phy_speed) { case SPEED_1000: phy_ag_adv.full_1000m = 1, phy_ag_adv.half_1000m = 0, phy_ag_adv.full_100m = 1, phy_ag_adv.half_100m = 1, phy_ag_adv.full_10m = 1, phy_ag_adv.half_10m = 1; break; case SPEED_100: phy_ag_adv.full_1000m = 0, phy_ag_adv.half_1000m = 0; if (pdata->phy_duplex) { phy_ag_adv.full_100m = 1; } else { phy_ag_adv.full_100m = 0; } phy_ag_adv.half_100m = 1, phy_ag_adv.full_10m = 1, phy_ag_adv.half_10m = 1; break; case SPEED_10: phy_ag_adv.full_1000m = 0, phy_ag_adv.half_1000m = 0; phy_ag_adv.full_100m = 0, phy_ag_adv.half_100m = 0; if (pdata->phy_duplex) { phy_ag_adv.full_10m = 1; } else { phy_ag_adv.full_10m = 0; } phy_ag_adv.half_10m = 1; break; default: break; } return fxgmac_set_ephy_autoneg_advertise(pdata, phy_ag_adv); } static void fxgmac_phy_green_ethernet(struct fxgmac_pdata* pdata) { u32 regval = 0; //GREEN fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_REG_PMA_DBG0_ADC); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_ENABLE_GIGA_POWER_SAVING_FOR_SHORT_CABLE); //CLD fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_REG_CLD_REG0); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_ENABLE_CLD_NP_WP); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_REG_CLD_REG1); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_ENABLE_CLD_GT_HT_BT); //after change green ethernet & CLD need to soft reset fxgmac_read_ephy_reg(pdata, REG_MII_BMCR, ®val); regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_RESET_POS, PHY_CR_RESET_LEN, 1); fxgmac_write_ephy_reg(pdata, REG_MII_BMCR, regval); } static void fxgmac_phy_eee_feature(struct fxgmac_pdata* pdata) { u32 regval = 0; regval = readreg(pdata->pAdapter, pdata->mac_regs + DMA_SBMR); regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_EN_LPI_POS, DMA_SBMR_EN_LPI_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_LPI_XIT_PKT_POS, DMA_SBMR_LPI_XIT_PKT_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_AALE_POS, DMA_SBMR_AALE_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + DMA_SBMR); //regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_IER); //regval = FXGMAC_SET_REG_BITS(regval, MAC_LPIIE_POS, MAC_LPIIE_LEN, 1); //writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_IER); regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_LPI_STA); regval = FXGMAC_SET_REG_BITS(regval, MAC_LPIATE_POS, MAC_LPIATE_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_LPITXA_POS, MAC_LPITXA_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_PLS_POS, MAC_PLS_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, MAC_LPIEN_POS, MAC_LPIEN_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_LPI_STA); regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_LPI_TIMER); regval = FXGMAC_SET_REG_BITS(regval, MAC_LPIET_POS, MAC_LPIET_LEN, MAC_LPI_ENTRY_TIMER); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_LPI_TIMER); regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_LPI_CONTROL); regval = FXGMAC_SET_REG_BITS(regval, MAC_TWT_POS, MAC_TWT_LEN, MAC_TWT_TIMER); regval = FXGMAC_SET_REG_BITS(regval, MAC_LST_POS, MAC_LST_LEN, MAC_LST_TIMER); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_LPI_CONTROL); regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_MS_TIC_COUNTER); regval = FXGMAC_SET_REG_BITS(regval, MAC_MS_TIC_POS, MAC_MS_TIC_LEN, MAC_MS_TIC); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_MS_TIC_COUNTER); //usleep_range_ex(pdata->pAdapter, 1500, 1500); fxgmac_write_ephy_mmd_reg(pdata, REG_MMD_EEE_ABILITY_REG, 0x07, REG_MMD_EEE_ABILITY_VALUE); //after change EEE need to soft reset fxgmac_read_ephy_reg(pdata, REG_MII_BMCR, ®val); regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_RESET_POS, PHY_CR_RESET_LEN, 1); fxgmac_write_ephy_reg(pdata, REG_MII_BMCR, regval); } static void fxgmac_reset_phy(struct fxgmac_pdata* pdata) { u32 value = 0; value = FXGMAC_SET_REG_BITS(value, MGMT_EPHY_CTRL_RESET_POS, MGMT_EPHY_CTRL_RESET_LEN, MGMT_EPHY_CTRL_STA_EPHY_RESET); writereg(pdata->pAdapter, value, pdata->base_mem + MGMT_EPHY_CTRL); usleep_range_ex(pdata->pAdapter, 1500, 1500); } void fxgmac_release_phy(struct fxgmac_pdata* pdata) { u32 value = 0; value = FXGMAC_SET_REG_BITS(value, MGMT_EPHY_CTRL_RESET_POS, MGMT_EPHY_CTRL_RESET_LEN, MGMT_EPHY_CTRL_STA_EPHY_RELEASE); writereg(pdata->pAdapter, value, pdata->base_mem + MGMT_EPHY_CTRL); usleep_range_ex(pdata->pAdapter, 100, 150); value = readreg(pdata->pAdapter, pdata->base_mem + MGMT_EPHY_CTRL); DBGPRINT(MP_LOUD, ("0x1004: 0x%x\n", value)); #ifdef AISC_MODE fxgmac_read_ephy_reg(pdata, REG_MII_SPEC_CTRL, &value);// read phy specific control value = FXGMAC_SET_REG_BITS(value, PHY_MII_SPEC_CTRL_CRS_ON_POS, PHY_MII_SPEC_CTRL_CRS_ON_LEN, 1);//set on crs on fxgmac_write_ephy_reg(pdata, REG_MII_SPEC_CTRL, value);// phy specific control set on crs on fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_ANALOG_CFG3); fxgmac_read_ephy_reg(pdata, REG_MII_EXT_DATA, &value); // VGA bandwidth, default is 2 after reset. Set to 0 to mitigate unstable issue in 130m. value = FXGMAC_SET_REG_BITS(value, MII_EXT_ANALOG_CFG3_ADC_START_CFG_POS, MII_EXT_ANALOG_CFG3_ADC_START_CFG_LEN, MII_EXT_ANALOG_CFG3_ADC_START_CFG_DEFAULT); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, value); #if 0 fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_PMA_DEBUG_KCOEF); fxgmac_read_ephy_reg(pdata, REG_MII_EXT_DATA, &value); /* After reset, it's 0x10. We need change it to 0x20 to make it easier to linkup in gigabit mode with long cable. But this is has side effect.*/ value = FXGMAC_SET_REG_BITS(value, MII_EXT_PMA_DEBUG_KCOEF_IPR_KCOEF_GE_LNG_POS, MII_EXT_PMA_DEBUG_KCOEF_IPR_KCOEF_GE_LNG_LEN, MII_EXT_PMA_DEBUG_KCOEF_IPR_KCOEF_GE_LNG_DEFAULT); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, value); #endif fxgmac_efuse_read_data(pdata, EFUSE_LED_ADDR, &value); //led index use bit0~bit5 value = FXGMAC_GET_REG_BITS(value, EFUSE_LED_POS, EFUSE_LED_LEN); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_ANALOG_CFG2); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_ANALOG_CFG2_LED_VALUE); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_ANALOG_CFG8); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_ANALOG_CFG8_LED_VALUE); if (EFUSE_LED_COMMON_SOLUTION != value) { fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED0_CFG); switch (value) { case EFUSE_LED_SOLUTION1: fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED0_CFG_VALUE_SOLUTION1); break; case EFUSE_LED_SOLUTION2: fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED0_CFG_VALUE_SOLUTION2); break; case EFUSE_LED_SOLUTION3: case EFUSE_LED_SOLUTION4: fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED0_CFG_VALUE_SOLUTION3); break; default: //default solution fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED0_CFG_VALUE_SOLUTION0); break; } fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED1_CFG); switch (value) { case EFUSE_LED_SOLUTION1: case EFUSE_LED_SOLUTION4: fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED1_CFG_VALUE_SOLUTION1); break; case EFUSE_LED_SOLUTION2: case EFUSE_LED_SOLUTION3: fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED1_CFG_VALUE_SOLUTION2); break; default: //default solution fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED1_CFG_VALUE_SOLUTION0); break; } fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED2_CFG); switch (value) { case EFUSE_LED_SOLUTION1: fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED2_CFG_VALUE_SOLUTION0); break; case EFUSE_LED_SOLUTION2: fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED2_CFG_VALUE_SOLUTION2); break; case EFUSE_LED_SOLUTION3: fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED2_CFG_VALUE_SOLUTION3); break; case EFUSE_LED_SOLUTION4: fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED2_CFG_VALUE_SOLUTION4); break; default: //default solution fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED2_CFG_VALUE_SOLUTION0); break; } if (EFUSE_LED_SOLUTION2 == value) { fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED_BLINK_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED_BLINK_CFG_SOLUTION2); } } #endif } #if !defined(UEFI) static void fxgmac_enable_phy_check(struct fxgmac_pdata* pdata) { u32 value = 0; //value = 0xa8d0; fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_PKG_CFG0); fxgmac_read_ephy_reg(pdata, REG_MII_EXT_DATA, &value); value = FXGMAC_SET_REG_BITS(value, REG_MII_EXT_PKG_CHECK_POS, REG_MII_EXT_PKG_CHECK_LEN, REG_MII_EXT_PKG_ENABLE_CHECK); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_PKG_CFG0); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, value); } static void fxgmac_disable_phy_check(struct fxgmac_pdata* pdata) { u32 value = 0; //value = 0x68d0; fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_PKG_CFG0); fxgmac_read_ephy_reg(pdata, REG_MII_EXT_DATA, &value); value = FXGMAC_SET_REG_BITS(value, REG_MII_EXT_PKG_CHECK_POS, REG_MII_EXT_PKG_CHECK_LEN, REG_MII_EXT_PKG_DISABLE_CHECK); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_PKG_CFG0); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, value); } static void fxgmac_setup_cable_loopback(struct fxgmac_pdata* pdata) { fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_SLEEP_CONTROL_REG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_SLEEP_REG_ENABLE_LOOPBACK); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_LPBK_REG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_LPBK_REG_ENABLE_LOOPBACK); fxgmac_write_ephy_reg(pdata, REG_MII_BMCR, REG_MII_BMCR_ENABLE_LOOPBACK); } static void fxgmac_clean_cable_loopback(struct fxgmac_pdata* pdata) { fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_SLEEP_CONTROL_REG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_SLEEP_REG_CLEAN_LOOPBACK); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_LPBK_REG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_LPBK_REG_CLEAN_LOOPBACK); fxgmac_write_ephy_reg(pdata, REG_MII_BMCR, REG_MII_BMCR_DISABLE_LOOPBACK); } static void fxgmac_disable_phy_sleep(struct fxgmac_pdata* pdata) { u32 value = 0; fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_SLEEP_CONTROL_REG); fxgmac_read_ephy_reg(pdata, REG_MII_EXT_DATA, &value); value = FXGMAC_SET_REG_BITS(value, MII_EXT_SLEEP_CONTROL1_EN_POS, MII_EXT_SLEEP_CONTROL1_EN_LEN, 0); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_SLEEP_CONTROL_REG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, value); } static void fxgmac_enable_phy_sleep(struct fxgmac_pdata* pdata) { u32 value = 0; fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_SLEEP_CONTROL_REG); fxgmac_read_ephy_reg(pdata, REG_MII_EXT_DATA, &value); value = FXGMAC_SET_REG_BITS(value, MII_EXT_SLEEP_CONTROL1_EN_POS, MII_EXT_SLEEP_CONTROL1_EN_LEN, 1); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_SLEEP_CONTROL_REG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, value); } #endif static void fxgmac_close_phy_led(struct fxgmac_pdata* pdata) { fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED0_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, 0x00); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED1_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, 0x00); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED2_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, 0x00); } static void fxmgac_config_led_under_active(struct fxgmac_pdata* pdata) { u32 regval = 0; fxgmac_efuse_read_data(pdata, EFUSE_LED_ADDR, ®val); //led index use bit0~bit5 regval = FXGMAC_GET_REG_BITS(regval, EFUSE_LED_POS, EFUSE_LED_LEN); if (EFUSE_LED_COMMON_SOLUTION == regval) { DbgPrintF(MP_TRACE, "%s >>>", __FUNCTION__); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s0_led_setting[0]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED0_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s0_led_setting[1]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED1_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s0_led_setting[2]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED2_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s0_led_setting[3]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED_BLINK_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s0_led_setting[4]); } } static void fxgmac_config_led_under_sleep(struct fxgmac_pdata* pdata) { u32 regval = 0; fxgmac_efuse_read_data(pdata, EFUSE_LED_ADDR, ®val); //led index use bit0~bit5 regval = FXGMAC_GET_REG_BITS(regval, EFUSE_LED_POS, EFUSE_LED_LEN); if (EFUSE_LED_COMMON_SOLUTION == regval) { DbgPrintF(MP_TRACE, "%s >>>", __FUNCTION__); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s3_led_setting[0]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED0_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s3_led_setting[1]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED1_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s3_led_setting[2]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED2_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s3_led_setting[3]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED_BLINK_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s3_led_setting[4]); } } static void fxgmac_config_led_under_shutdown(struct fxgmac_pdata* pdata) { u32 regval = 0; fxgmac_efuse_read_data(pdata, EFUSE_LED_ADDR, ®val); //led index use bit0~bit5 regval = FXGMAC_GET_REG_BITS(regval, EFUSE_LED_POS, EFUSE_LED_LEN); if (EFUSE_LED_COMMON_SOLUTION == regval) { DbgPrintF(MP_TRACE, "%s >>>", __FUNCTION__); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s5_led_setting[0]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED0_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s5_led_setting[1]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED1_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s5_led_setting[2]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED2_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s5_led_setting[3]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED_BLINK_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.s5_led_setting[4]); } } static void fxgmac_config_led_under_disable(struct fxgmac_pdata* pdata) { u32 regval = 0; fxgmac_efuse_read_data(pdata, EFUSE_LED_ADDR, ®val); //led index use bit0~bit5 regval = FXGMAC_GET_REG_BITS(regval, EFUSE_LED_POS, EFUSE_LED_LEN); if (EFUSE_LED_COMMON_SOLUTION == regval) { DbgPrintF(MP_TRACE, "%s >>>", __FUNCTION__); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.disable_led_setting[0]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED0_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.disable_led_setting[1]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED1_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.disable_led_setting[2]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED2_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.disable_led_setting[3]); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED_BLINK_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, pdata->led.disable_led_setting[4]); } else { //http://redmine.motor-comm.com/issues/4101 //for disable case,reset phy to close LED fxgmac_reset_phy(pdata); } } #ifdef LINUX extern void fxgmac_diag_get_rx_info(struct fxgmac_channel *channel); static int fxgmac_dev_read(struct fxgmac_channel *channel) { struct fxgmac_pdata *pdata = channel->pdata; struct fxgmac_ring *ring = channel->rx_ring; struct net_device *netdev = pdata->netdev; struct fxgmac_desc_data *desc_data; struct fxgmac_dma_desc *dma_desc; struct fxgmac_pkt_info *pkt_info; unsigned int err, etlt, l34t; //unsigned int i; static unsigned int cnt_incomplete = 0; desc_data = FXGMAC_GET_DESC_DATA(ring, ring->cur); dma_desc = desc_data->dma_desc; pkt_info = &ring->pkt_info; /* Check for data availability */ if (FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_NORMAL_DESC3_OWN_POS, RX_NORMAL_DESC3_OWN_LEN)) { return 1; } /* Make sure descriptor fields are read after reading the OWN bit */ dma_rmb(); if (netif_msg_rx_status(pdata)) fxgmac_dump_rx_desc(pdata, ring, ring->cur); if (FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_NORMAL_DESC3_CTXT_POS, RX_NORMAL_DESC3_CTXT_LEN)) { /* Timestamp Context Descriptor */ fxgmac_get_rx_tstamp(pkt_info, dma_desc); pkt_info->attributes = FXGMAC_SET_REG_BITS( pkt_info->attributes, RX_PACKET_ATTRIBUTES_CONTEXT_POS, RX_PACKET_ATTRIBUTES_CONTEXT_LEN, 1); pkt_info->attributes = FXGMAC_SET_REG_BITS( pkt_info->attributes, RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_POS, RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_LEN, 0); if(netif_msg_rx_status(pdata)) DPRINTK("dev_read context desc,ch=%s\n",channel->name); return 0; } /* Normal Descriptor, be sure Context Descriptor bit is off */ pkt_info->attributes = FXGMAC_SET_REG_BITS( pkt_info->attributes, RX_PACKET_ATTRIBUTES_CONTEXT_POS, RX_PACKET_ATTRIBUTES_CONTEXT_LEN, 0); /* Indicate if a Context Descriptor is next */ #if 0 if (FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_NORMAL_DESC3_CDA_POS, RX_NORMAL_DESC3_CDA_LEN)) pkt_info->attributes = FXGMAC_SET_REG_BITS( pkt_info->attributes, RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_POS, RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_LEN, 1); #endif /* Get the header length */ if (FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_NORMAL_DESC3_FD_POS, RX_NORMAL_DESC3_FD_LEN)) { desc_data->rx.hdr_len = FXGMAC_GET_REG_BITS_LE(dma_desc->desc2, RX_NORMAL_DESC2_HL_POS, RX_NORMAL_DESC2_HL_LEN); if (desc_data->rx.hdr_len) pdata->stats.rx_split_header_packets++; } l34t = 0; #if 0 //(FXGMAC_RSS_FEATURE_ENABLED) //20210608 /* Get the RSS hash */ if (FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_NORMAL_DESC3_RSV_POS, RX_NORMAL_DESC3_RSV_LEN)) { pkt_info->attributes = FXGMAC_SET_REG_BITS( pkt_info->attributes, RX_PACKET_ATTRIBUTES_RSS_HASH_POS, RX_PACKET_ATTRIBUTES_RSS_HASH_LEN, 1); pkt_info->rss_hash = le32_to_cpu(dma_desc->desc1); l34t = FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_NORMAL_DESC3_L34T_POS, RX_NORMAL_DESC3_L34T_LEN); switch (l34t) { case RX_DESC3_L34T_IPV4_TCP: case RX_DESC3_L34T_IPV4_UDP: case RX_DESC3_L34T_IPV6_TCP: case RX_DESC3_L34T_IPV6_UDP: pkt_info->rss_hash_type = PKT_HASH_TYPE_L4; break; default: pkt_info->rss_hash_type = PKT_HASH_TYPE_L3; } } #endif /* Get the pkt_info length */ desc_data->rx.len = FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_NORMAL_DESC3_PL_POS, RX_NORMAL_DESC3_PL_LEN); //DPRINTK("dev_read upon FD=1, pkt_len=%u\n",desc_data->rx.len); if (!FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_NORMAL_DESC3_LD_POS, RX_NORMAL_DESC3_LD_LEN)) { /* Not all the data has been transferred for this pkt_info */ pkt_info->attributes = FXGMAC_SET_REG_BITS( pkt_info->attributes, RX_PACKET_ATTRIBUTES_INCOMPLETE_POS, RX_PACKET_ATTRIBUTES_INCOMPLETE_LEN, 1); cnt_incomplete++; if ((cnt_incomplete < 2) && netif_msg_rx_status(pdata)) DPRINTK("dev_read NOT last desc,pkt incomplete yet,%u\n", cnt_incomplete); return 0; } if ((cnt_incomplete) && netif_msg_rx_status(pdata)) DPRINTK("dev_read rx back to normal and incomplete cnt=%u\n", cnt_incomplete); cnt_incomplete = 0; //when back to normal, reset cnt /* This is the last of the data for this pkt_info */ pkt_info->attributes = FXGMAC_SET_REG_BITS( pkt_info->attributes, RX_PACKET_ATTRIBUTES_INCOMPLETE_POS, RX_PACKET_ATTRIBUTES_INCOMPLETE_LEN, 0); /* Set checksum done indicator as appropriate */ if (netdev->features & NETIF_F_RXCSUM) pkt_info->attributes = FXGMAC_SET_REG_BITS( pkt_info->attributes, RX_PACKET_ATTRIBUTES_CSUM_DONE_POS, RX_PACKET_ATTRIBUTES_CSUM_DONE_LEN, 1); /* Check for errors (only valid in last descriptor) */ err = FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_NORMAL_DESC3_ES_POS, RX_NORMAL_DESC3_ES_LEN); etlt = FXGMAC_GET_REG_BITS_LE(dma_desc->desc3, RX_NORMAL_DESC3_ETLT_POS, RX_NORMAL_DESC3_ETLT_LEN); //netif_dbg(pdata, rx_status, netdev, "err=%u, etlt=%#x\n", err, etlt); if((err) && netif_msg_rx_status(pdata)) { DPRINTK("dev_read:head_len=%u,pkt_len=%u,err=%u, etlt=%#x,desc2=0x%08x,desc3=0x%08x\n",desc_data->rx.hdr_len, desc_data->rx.len, err, etlt, dma_desc->desc2, dma_desc->desc3); } if (!err || !etlt) { /* No error if err is 0 or etlt is 0 */ if ((etlt == 0x4 /*yzhang changed to 0x4, 0x09*/) && (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) { pkt_info->attributes = FXGMAC_SET_REG_BITS( pkt_info->attributes, RX_PACKET_ATTRIBUTES_VLAN_CTAG_POS, RX_PACKET_ATTRIBUTES_VLAN_CTAG_LEN, 1); pkt_info->vlan_ctag = FXGMAC_GET_REG_BITS_LE(dma_desc->desc0, RX_NORMAL_DESC0_OVT_POS, RX_NORMAL_DESC0_OVT_LEN); netif_dbg(pdata, rx_status, netdev, "vlan-ctag=%#06x\n", pkt_info->vlan_ctag); } } else { if (etlt == 0x05 || etlt == 0x06) pkt_info->attributes = FXGMAC_SET_REG_BITS( pkt_info->attributes, RX_PACKET_ATTRIBUTES_CSUM_DONE_POS, RX_PACKET_ATTRIBUTES_CSUM_DONE_LEN, 0); else pkt_info->errors = FXGMAC_SET_REG_BITS( pkt_info->errors, RX_PACKET_ERRORS_FRAME_POS, RX_PACKET_ERRORS_FRAME_LEN, 1); } return 0; } #endif static int fxgmac_enable_int(struct fxgmac_channel *channel, enum fxgmac_int int_id) { unsigned int dma_ch_ier; dma_ch_ier = readreg(channel->pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_IER)); switch (int_id) { case FXGMAC_INT_DMA_CH_SR_TI: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_TIE_POS, DMA_CH_IER_TIE_LEN, 1); break; case FXGMAC_INT_DMA_CH_SR_TPS: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_TXSE_POS, DMA_CH_IER_TXSE_LEN, 1); break; case FXGMAC_INT_DMA_CH_SR_TBU: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_TBUE_POS, DMA_CH_IER_TBUE_LEN, 1); break; case FXGMAC_INT_DMA_CH_SR_RI: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_RIE_POS, DMA_CH_IER_RIE_LEN, 1); break; case FXGMAC_INT_DMA_CH_SR_RBU: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_RBUE_POS, DMA_CH_IER_RBUE_LEN, 1); break; case FXGMAC_INT_DMA_CH_SR_RPS: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_RSE_POS, DMA_CH_IER_RSE_LEN, 1); break; case FXGMAC_INT_DMA_CH_SR_TI_RI: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_TIE_POS, DMA_CH_IER_TIE_LEN, 1); dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_RIE_POS, DMA_CH_IER_RIE_LEN, 1); dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_NIE_POS, DMA_CH_IER_NIE_LEN, 1); break; case FXGMAC_INT_DMA_CH_SR_FBE: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_FBEE_POS, DMA_CH_IER_FBEE_LEN, 1); break; case FXGMAC_INT_DMA_ALL: dma_ch_ier |= channel->saved_ier; break; default: return -1; } writereg(channel->pdata->pAdapter, dma_ch_ier, FXGMAC_DMA_REG(channel, DMA_CH_IER)); return 0; } static int fxgmac_disable_int(struct fxgmac_channel *channel, enum fxgmac_int int_id) { unsigned int dma_ch_ier; dma_ch_ier = readreg(channel->pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_IER)); switch (int_id) { case FXGMAC_INT_DMA_CH_SR_TI: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_TIE_POS, DMA_CH_IER_TIE_LEN, 0); break; case FXGMAC_INT_DMA_CH_SR_TPS: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_TXSE_POS, DMA_CH_IER_TXSE_LEN, 0); break; case FXGMAC_INT_DMA_CH_SR_TBU: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_TBUE_POS, DMA_CH_IER_TBUE_LEN, 0); break; case FXGMAC_INT_DMA_CH_SR_RI: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_RIE_POS, DMA_CH_IER_RIE_LEN, 0); break; case FXGMAC_INT_DMA_CH_SR_RBU: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_RBUE_POS, DMA_CH_IER_RBUE_LEN, 0); break; case FXGMAC_INT_DMA_CH_SR_RPS: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_RSE_POS, DMA_CH_IER_RSE_LEN, 0); break; case FXGMAC_INT_DMA_CH_SR_TI_RI: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_TIE_POS, DMA_CH_IER_TIE_LEN, 0); dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_RIE_POS, DMA_CH_IER_RIE_LEN, 0); dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_NIE_POS, DMA_CH_IER_NIE_LEN, 0); break; case FXGMAC_INT_DMA_CH_SR_FBE: dma_ch_ier = FXGMAC_SET_REG_BITS( dma_ch_ier, DMA_CH_IER_FBEE_POS, DMA_CH_IER_FBEE_LEN, 0); break; case FXGMAC_INT_DMA_ALL: channel->saved_ier = dma_ch_ier & FXGMAC_DMA_INTERRUPT_MASK; dma_ch_ier &= ~FXGMAC_DMA_INTERRUPT_MASK; break; default: return -1; } writereg(channel->pdata->pAdapter, dma_ch_ier, FXGMAC_DMA_REG(channel, DMA_CH_IER)); return 0; } #ifdef LINUX static int fxgmac_dismiss_DMA_int(struct fxgmac_channel *channel, int int_id) { unsigned int dma_ch_ier; int_id = int_id; dma_ch_ier = readreg(channel->pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_SR /*1160*/)); writereg(channel->pdata->pAdapter, dma_ch_ier, FXGMAC_DMA_REG(channel, DMA_CH_SR)); return 0; } static void fxgmac_dismiss_MTL_Q_int(struct fxgmac_pdata *pdata) { unsigned int q_count, i; unsigned int mtl_q_isr; q_count = max(pdata->hw_feat.tx_q_cnt, pdata->hw_feat.rx_q_cnt); for (i = 0; i < q_count; i++) { /* Clear all the interrupts which are set */ mtl_q_isr = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_ISR)); writereg(pdata->pAdapter, mtl_q_isr, FXGMAC_MTL_REG(pdata, i, MTL_Q_ISR)); } } static int fxgmac_dismiss_MAC_int(struct fxgmac_pdata *pdata) { u32 regval,regErrVal; /* all MAC interrupts in 0xb0 */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_ISR); /* MAC tx/rx error interrupts in 0xb8 */ regErrVal = readreg(pdata->pAdapter, pdata->mac_regs + MAC_TX_RX_STA); #if 0 //write clear if(FXGMAC_GET_REG_BITS(readreg(pdata->mac_regs + MAC_CSR_SW_CTRL), 0/*rcwe*/, 1)) { writereg(regval, pdata->mac_regs + MAC_ISR); writereg(regErrVal, pdata->mac_regs + MAC_TX_RX_STA); } #endif return 0; } static int fxgmac_dismiss_MAC_PMT_int(struct fxgmac_pdata *pdata) { u32 regval; /* MAC PMT interrupts in 0xc0 */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PMT_STA); #if 0 //write clear if(FXGMAC_GET_REG_BITS(readreg(pdata->mac_regs + MAC_CSR_SW_CTRL), 0/*rcwe*/, 1)) { writereg(regval, pdata->mac_regs + MAC_PMT_STA); } #endif return 0; } static int fxgmac_dismiss_MAC_LPI_int(struct fxgmac_pdata *pdata) { u32 regval; /* MAC PMT interrupts in 0xc0 */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_LPI_STA); #if 0 //write clear if(FXGMAC_GET_REG_BITS(readreg(pdata->mac_regs + MAC_CSR_SW_CTRL), 0/*rcwe*/, 1)) { writereg(regval, pdata->mac_regs + MAC_LPI_STA); } #endif return 0; } static int fxgmac_dismiss_MAC_DBG_int(struct fxgmac_pdata *pdata) { u32 regval; /* MAC PMT interrupts in 0xc0 */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_DBG_STA); #if 1 //write clear { writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_DBG_STA); } #endif return 0; } #endif int fxgmac_dismiss_all_int(struct fxgmac_pdata *pdata) { #ifdef LINUX struct fxgmac_channel *channel; unsigned int i, regval; struct net_device *netdev = pdata->netdev; if (netif_msg_drv(pdata)) { DPRINTK("fxgmac_dismiss_all_int callin\n"); } channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { fxgmac_dismiss_DMA_int(channel, 0); } fxgmac_dismiss_MTL_Q_int(pdata); fxgmac_dismiss_MAC_int(pdata); fxgmac_dismiss_MAC_PMT_int(pdata); fxgmac_dismiss_MAC_LPI_int(pdata); fxgmac_dismiss_MAC_DBG_int(pdata); //control module int to PCIe slot if (netdev->base_addr) { regval = (unsigned int)(* ((u32 *)(netdev->base_addr + MGMT_INT_CTRL0))); } #else pdata = pdata; #endif return 0; } static void fxgmac_set_interrupt_moderation(struct fxgmac_pdata* pdata) { u32 value = 0, time; #if defined (UEFI) pdata->intr_mod_timer = INT_MOD_IN_US; #elif defined (_WIN32) || defined (_WIN64) // the Windows driver initializes it somewhere else #else pdata->intr_mod_timer = INT_MOD_IN_US; #endif time = (pdata->intr_mod) ? pdata->intr_mod_timer : 0; #ifdef LINUX time = (pdata->intr_mod) ? pdata->tx_usecs : 0; #endif value = FXGMAC_SET_REG_BITS(value, INT_MOD_TX_POS, INT_MOD_TX_LEN, time); #ifdef LINUX time = (pdata->intr_mod) ? pdata->rx_usecs : 0; #endif value = FXGMAC_SET_REG_BITS(value, INT_MOD_RX_POS, INT_MOD_RX_LEN, time); writereg(pdata->pAdapter, value, pdata->base_mem + INT_MOD); } static void fxgmac_enable_msix_rxtxinterrupt(struct fxgmac_pdata* pdata) { u32 intid; for (intid = 0; intid < MSIX_TBL_RXTX_NUM; intid++) { writereg(pdata->pAdapter, 0, pdata->base_mem + MSIX_TBL_BASE_ADDR + MSIX_TBL_MASK_OFFSET + intid * 16); } } static void fxgmac_disable_msix_interrupt(struct fxgmac_pdata* pdata) { u32 intid; for (intid = 0; intid < MSIX_TBL_MAX_NUM; intid++) { writereg(pdata->pAdapter, 0x1, pdata->base_mem + MSIX_TBL_BASE_ADDR + MSIX_TBL_MASK_OFFSET + intid * 16); } } static void fxgmac_enable_msix_rxtxphyinterrupt(struct fxgmac_pdata* pdata) { u32 intid, regval = 0; #if !(FUXI_EPHY_INTERRUPT_D0_OFF) struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops; #endif for (intid = 0; intid < MSIX_TBL_RXTX_NUM; intid++) { writereg(pdata->pAdapter, 0, pdata->base_mem + MSIX_TBL_BASE_ADDR + MSIX_TBL_MASK_OFFSET + intid * 16); } writereg(pdata->pAdapter, 0, pdata->base_mem + MSIX_TBL_BASE_ADDR + MSIX_TBL_MASK_OFFSET + MSI_ID_PHY_OTHER * 16); #if !(FUXI_EPHY_INTERRUPT_D0_OFF) hw_ops->read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL);// clear phy interrupt regval = FXGMAC_SET_REG_BITS(0, PHY_INT_MASK_LINK_UP_POS, PHY_INT_MASK_LINK_UP_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, PHY_INT_MASK_LINK_DOWN_POS, PHY_INT_MASK_LINK_DOWN_LEN, 1); hw_ops->write_ephy_reg(pdata, REG_MII_INT_MASK, regval);//enable phy interrupt ASIC bit10 linkup bit11 linkdown #endif } static void fxgmac_enable_msix_one_interrupt(struct fxgmac_pdata* pdata,u32 intid) { writereg(pdata->pAdapter, 0, pdata->base_mem + MSIX_TBL_BASE_ADDR + MSIX_TBL_MASK_OFFSET + intid * 16); //DbgPrintF(MP_LOUD, "%s - Ephy, MsgId %d is enabled.", __FUNCTION__, IntId); } static void fxgmac_disable_msix_one_interrupt(struct fxgmac_pdata* pdata, u32 intid) { writereg(pdata->pAdapter, 0x01, pdata->base_mem + MSIX_TBL_BASE_ADDR + MSIX_TBL_MASK_OFFSET + intid * 16); //DbgPrintF(MP_LOUD, "%s - Ephy, MsgId %d is disabled.", __FUNCTION__, IntId); } static bool fxgmac_enable_mgm_interrupt(struct fxgmac_pdata* pdata) { writereg(pdata->pAdapter, 0xf0000000, pdata->base_mem + MGMT_INT_CTRL0); return true; } static bool fxgmac_disable_mgm_interrupt(struct fxgmac_pdata* pdata) { writereg(pdata->pAdapter, 0xffff0000, pdata->base_mem + MGMT_INT_CTRL0); return true; } static int fxgmac_flush_tx_queues(struct fxgmac_pdata *pdata) { unsigned int i, count; u32 regval; for (i = 0; i < pdata->tx_q_count; i++) { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_TQOMR_FTQ_POS, MTL_Q_TQOMR_FTQ_LEN, 1); writereg(pdata->pAdapter, regval, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); DPRINTK("fxgmac_flush_tx_queues, reg=0x%p, val=0x%08x\n", FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR), regval); } //2022-04-20 xiaojiang comment //the following windows implement has some unreasonable part //Take Linux implement method instead /* Poll Until Poll Condition */ /*for (i = 0; i < pdata->tx_q_count; i++) { count = 2000; regval = readreg(FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); regval = FXGMAC_GET_REG_BITS(regval, MTL_Q_TQOMR_FTQ_POS, MTL_Q_TQOMR_FTQ_LEN); while (--count && regval) { usleep_range(pdata->pAdapter, 500, 600); } DPRINTK("fxgmac_flush_tx_queues wait... reg=0x%p, val=0x%08x\n", FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR), regval); if (!count) return -EBUSY; }*/ for (i = 0; i < pdata->tx_q_count; i++) { count = 2000; //regval = 1; //reset is not cleared.... do { usleep_range_ex(pdata->pAdapter, 40, 50); regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR)); regval = FXGMAC_GET_REG_BITS(regval, MTL_Q_TQOMR_FTQ_POS, MTL_Q_TQOMR_FTQ_LEN); } while (--count && regval); DPRINTK("fxgmac_flush_tx_queues wait... reg=0x%p, val=0x%08x\n", FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR), regval); if (regval) {/*(!count)*/ return -EBUSY; } } return 0; } static void fxgmac_config_dma_bus(struct fxgmac_pdata *pdata) { u32 regval; #if 1//set no fix burst length regval = readreg(pdata->pAdapter, pdata->mac_regs + DMA_SBMR); /* Set enhanced addressing mode */ regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_EAME_POS, DMA_SBMR_EAME_LEN, 1); /* Set the System Bus mode */ regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_FB_POS, DMA_SBMR_FB_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_BLEN_4_POS, DMA_SBMR_BLEN_4_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_BLEN_8_POS, DMA_SBMR_BLEN_8_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_BLEN_16_POS, DMA_SBMR_BLEN_16_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_BLEN_32_POS, DMA_SBMR_BLEN_32_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + DMA_SBMR); #else regval = readreg(pdata->mac_regs + DMA_SBMR); /* Set enhanced addressing mode */ regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_EAME_POS, DMA_SBMR_EAME_LEN, 1); /* Set the System Bus mode */ regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_FB_POS, DMA_SBMR_FB_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_BLEN_256_POS, DMA_SBMR_BLEN_256_LEN, 1); writereg(regval, pdata->mac_regs + DMA_SBMR); #endif } static void fxgmac_legacy_link_speed_setting(struct fxgmac_pdata* pdata) { unsigned int i = 0, regval = 0; fxgmac_phy_config(pdata); for (i = 0, regval = fxgmac_get_ephy_state(pdata); (!(regval & MGMT_EPHY_CTRL_STA_EPHY_RELEASE) || !(regval & MGMT_EPHY_CTRL_STA_EPHY_LINKUP)) && (i < PHY_LINK_TIMEOUT); regval = fxgmac_get_ephy_state(pdata), i++) { usleep_range_ex(pdata->pAdapter, 2000, 2000); } fxgmac_read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL); // clear phy interrupt. } static void fxgmac_pre_powerdown(struct fxgmac_pdata* pdata, bool phyloopback) { unsigned int regval = 0; fxgmac_disable_rx(pdata); /* HERE, WE NEED TO CONSIDER PHY CONFIG...TBD */ DPRINTK("fxgmac_config_powerdown, phy and mac status update\n"); //2022-11-09 xiaojiang comment //for phy cable loopback,it can't configure phy speed, it will cause os resume again by link change although it has finished speed setting, if (!phyloopback) { #ifndef LINUX #if defined(UEFI) #elif defined(DPDK) (void) i; #elif defined(_WIN32) || defined(_WIN64) LONGLONG tick_interval; ULONG tick_inc; LARGE_INTEGER tick_count; unsigned int i = 0; if ((ULONG)pdata->phy_speed != ((PMP_ADAPTER)pdata->pAdapter)->usLinkSpeed) { DbgPrintF(MP_TRACE, "%s change phy speed", __FUNCTION__); if (((PMP_ADAPTER)pdata->pAdapter)->RegParameter.LinkChgWol) { fxgmac_phy_config(pdata); //sleep fixed value(6s) for (i = 0; i < PHY_LINK_TIMEOUT; i++) { usleep_range_ex(pdata->pAdapter, 2000, 2000); } fxgmac_read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL); // clear phy interrupt. } else { regval = fxgmac_get_ephy_state(pdata); KeQueryTickCount(&tick_count); tick_inc = KeQueryTimeIncrement(); tick_interval = tick_count.QuadPart - ((PMP_ADAPTER)pdata->pAdapter)->D0_entry_tick_count.QuadPart; tick_interval *= tick_inc; tick_interval /= 10; /*DbgPrintF(MP_TRACE, "base tick %lld", ((PMP_ADAPTER)pdata->pAdapter)->D0_entry_tick_count.QuadPart); DbgPrintF(MP_TRACE, "current tick %lld", tick_count.QuadPart); DbgPrintF(MP_TRACE, "tick inc is %u", tick_inc); DbgPrintF(MP_TRACE, "tick_interval is %lld", tick_interval);*/ if (((regval & MGMT_EPHY_CTRL_STA_EPHY_RELEASE) && (regval & MGMT_EPHY_CTRL_STA_EPHY_LINKUP)) || ((regval & MGMT_EPHY_CTRL_STA_EPHY_RELEASE) && !(regval & MGMT_EPHY_CTRL_STA_EPHY_LINKUP) && (tick_interval < RESUME_MAX_TIME) && (MediaConnectStateConnected == ((PMP_ADAPTER)pdata->pAdapter)->PreMediaState)) ) { fxgmac_legacy_link_speed_setting(pdata); } } } #else #endif #endif /* When the Linux platform enters the s4 state, it goes through the suspend->resume->suspend process. The process of suspending again after resume is fast, and PHY auto-negotiation is not yet complete, so the auto-negotiation of PHY must be carried out again.Windows platforms and UEFI platforms do not need to auto-negotiate again, as they will not have such a process. When the Linux platform enters the s4 state, force speed to 10M. */ #ifdef UEFI fxgmac_legacy_link_speed_setting(pdata); #elif defined(_WIN32) || defined(_WIN64) #elif defined(LINUX) pdata->phy_speed = SPEED_10; fxgmac_legacy_link_speed_setting(pdata); #else fxgmac_legacy_link_speed_setting(pdata); #endif } fxgmac_config_mac_speed(pdata); /* After enable OOB_WOL from efuse, mac will loopcheck phy status, and lead to panic sometimes. So we should disable it from powerup, enable it from power down.*/ regval = (u32)readreg(pdata->pAdapter, pdata->base_mem + OOB_WOL_CTRL); regval = FXGMAC_SET_REG_BITS(regval, OOB_WOL_CTRL_DIS_POS, OOB_WOL_CTRL_DIS_LEN, 0); writereg(pdata->pAdapter, regval, pdata->base_mem + OOB_WOL_CTRL); usleep_range_ex(pdata->pAdapter, 2000, 2000); //after enable OOB_WOL,recofigure mac addr again fxgmac_set_mac_address(pdata, pdata->mac_addr); //fxgmac_suspend_clock_gate(pdata); } #if defined(LINUX) // only supports four patterns, and patterns will be cleared on every call static void fxgmac_set_pattern_data(struct fxgmac_pdata *pdata) { u32 ip_addr, i = 0; u8 type_offset, op_offset, tip_offset; struct pattern_packet packet; struct wol_bitmap_pattern pattern[4]; // for WAKE_UCAST, WAKE_BCAST, WAKE_MCAST, WAKE_ARP. memset(pattern, 0, sizeof(struct wol_bitmap_pattern) * 4); //config ucast if (pdata->expansion.wol & WAKE_UCAST) { pattern[i].mask_info[0] = 0x3F; pattern[i].mask_size = sizeof(pattern[0].mask_info); memcpy(pattern[i].pattern_info, pdata->mac_addr, ETH_ALEN); pattern[i].pattern_offset = 0; i++; } // config bcast if (pdata->expansion.wol & WAKE_BCAST) { pattern[i].mask_info[0] = 0x3F; pattern[i].mask_size = sizeof(pattern[0].mask_info); memset(pattern[i].pattern_info, 0xFF, ETH_ALEN); pattern[i].pattern_offset = 0; i++; } // config mcast if (pdata->expansion.wol & WAKE_MCAST) { pattern[i].mask_info[0] = 0x7; pattern[i].mask_size = sizeof(pattern[0].mask_info); pattern[i].pattern_info[0] = 0x1; pattern[i].pattern_info[1] = 0x0; pattern[i].pattern_info[2] = 0x5E; pattern[i].pattern_offset = 0; i++; } // config arp if (pdata->expansion.wol & WAKE_ARP) { memset(pattern[i].mask_info, 0, sizeof(pattern[0].mask_info)); type_offset = offsetof(struct pattern_packet, ar_pro); pattern[i].mask_info[type_offset / 8] |= 1 << type_offset % 8; type_offset++; pattern[i].mask_info[type_offset / 8] |= 1 << type_offset % 8; op_offset = offsetof(struct pattern_packet, ar_op); pattern[i].mask_info[op_offset / 8] |= 1 << op_offset % 8; op_offset++; pattern[i].mask_info[op_offset / 8] |= 1 << op_offset % 8; tip_offset = offsetof(struct pattern_packet, ar_tip); pattern[i].mask_info[tip_offset / 8] |= 1 << tip_offset % 8; tip_offset++; pattern[i].mask_info[tip_offset / 8] |= 1 << type_offset % 8; tip_offset++; pattern[i].mask_info[tip_offset / 8] |= 1 << type_offset % 8; tip_offset++; pattern[i].mask_info[tip_offset / 8] |= 1 << type_offset % 8; packet.ar_pro = 0x0 << 8 | 0x08; // arp type is 0x0800, notice that ar_pro and ar_op is big endian packet.ar_op = 0x1 << 8; // 1 is arp request,2 is arp replay, 3 is rarp request, 4 is rarp replay ip_addr = fxgmac_get_netdev_ip4addr(pdata); packet.ar_tip[0] = ip_addr & 0xFF; packet.ar_tip[1] = (ip_addr >> 8) & 0xFF; packet.ar_tip[2] = (ip_addr >> 16) & 0xFF; packet.ar_tip[3] = (ip_addr >> 24) & 0xFF; memcpy(pattern[i].pattern_info, &packet, MAX_PATTERN_SIZE); pattern[i].mask_size = sizeof(pattern[0].mask_info); pattern[i].pattern_offset = 0; i++; } fxgmac_set_wake_pattern(pdata, pattern, i); } static void fxgmac_config_powerdown(struct fxgmac_pdata *pdata, unsigned int wol) #else static void fxgmac_config_powerdown(struct fxgmac_pdata* pdata, unsigned int offloadcount, bool magic_en, bool remote_pattern_en) #endif { u32 regval = 0; fxgmac_disable_tx(pdata); fxgmac_disable_rx(pdata); /* performs fxgmac power down sequence * 1. set led * 2. check wol. * 3. check arp offloading * 4. disable gmac rx * 5. set gmac power down */ //Close LED when entering the S3,S4,S5 except solution3 fxgmac_efuse_read_data(pdata, EFUSE_LED_ADDR, ®val); //led index use bit0~bit5 regval = FXGMAC_GET_REG_BITS(regval, EFUSE_LED_POS, EFUSE_LED_LEN); if (EFUSE_LED_COMMON_SOLUTION != regval) { fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED0_CFG); if (EFUSE_LED_SOLUTION3 == regval) { fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, REG_MII_EXT_COMMON_LED0_CFG_VALUE_SLEEP_SOLUTION3); } else { fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, 0x00); } fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED1_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, 0x00); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_COMMON_LED2_CFG); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, 0x00); } #if defined(LINUX) if(!test_bit(FXGMAC_POWER_STATE_DOWN, &pdata->expansion.powerstate)) { netdev_err(pdata->netdev, "fxgmac powerstate is %lu when config power to down.\n", pdata->expansion.powerstate); } #if FXGMAC_WOL_FEATURE_ENABLED fxgmac_config_wol(pdata, wol); #endif #if FXGMAC_AOE_FEATURE_ENABLED /* use default arp offloading feature */ fxgmac_update_aoe_ipv4addr(pdata, (u8 *)NULL); fxgmac_enable_arp_offload(pdata); #endif #if FXGMAC_NS_OFFLOAD_ENABLED /* pls do not change the seq below */ fxgmac_update_ns_offload_ipv6addr(pdata, FXGMAC_NS_IFA_GLOBAL_UNICAST); fxgmac_update_ns_offload_ipv6addr(pdata, FXGMAC_NS_IFA_LOCAL_LINK); fxgmac_enable_ns_offload(pdata); #endif #endif // LINUX. #if defined(_WIN32) || defined(_WIN64) fxgmac_enable_wake_packet_indication(pdata, 1); #endif /* Enable MAC Rx TX */ #if defined(LINUX) if (1) { #else if (magic_en || remote_pattern_en || offloadcount) { #endif regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_RE_POS, MAC_CR_RE_LEN, 1); #if defined(LINUX) if(pdata->hw_feat.aoe) { #else if (offloadcount) { #endif regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_TE_POS, MAC_CR_TE_LEN, 1); } writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); } /* Enable fast link mode. - ECO to fix it.*/ #if 0 cfg_r32(pdata, REG_POWER_EIOS, ®val); regval = FXGMAC_SET_REG_BITS(regval, POWER_EIOS_POS, POWER_EIOS_LEN, 1); cfg_w32(pdata, REG_POWER_EIOS, regval); #endif regval = readreg(pdata->pAdapter, pdata->base_mem + LPW_CTRL); regval = FXGMAC_SET_REG_BITS(regval, LPW_CTRL_ASPM_LPW_EN_POS, LPW_CTRL_ASPM_LPW_EN_LEN, 1); // Enable PCIE PM_L23. #if 0 regval = FXGMAC_SET_REG_BITS(regval, LPW_CTRL_ASPM_L0S_EN_POS, LPW_CTRL_ASPM_L0S_EN_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, LPW_CTRL_ASPM_L1_EN_POS, LPW_CTRL_ASPM_L1_EN_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, LPW_CTRL_L1SS_EN_POS, LPW_CTRL_L1SS_EN_LEN, 0); #endif writereg(pdata->pAdapter, regval, pdata->base_mem + LPW_CTRL); /* set gmac power down */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PMT_STA); regval = FXGMAC_SET_REG_BITS(regval, MAC_PMT_STA_PWRDWN_POS, MAC_PMT_STA_PWRDWN_LEN, 1); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PMT_STA); #ifdef LINUX /*adjust sigdet threshold*/ //redmine.motor-comm.com/issues/5093 // fix issue can not wake up os on some FT-D2000 platform, this modification is only temporary // if it is 55mv, wol maybe failed. regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_SIGDET); regval = FXGMAC_SET_REG_BITS(regval, MGMT_SIGDET_POS, MGMT_SIGDET_LEN, MGMT_SIGDET_40MV); writereg(pdata->pAdapter, regval, pdata->base_mem + MGMT_SIGDET); #endif DPRINTK("fxgmac_config_powerdown callout, reg=0x%08x\n", regval); } static void fxgmac_config_powerup(struct fxgmac_pdata* pdata) { u32 regval = 0; #if defined(LINUX) if (test_bit(FXGMAC_POWER_STATE_DOWN, &pdata->expansion.powerstate)) { netdev_err(pdata->netdev, "fxgmac powerstate is %lu when config power to up.\n", pdata->expansion.powerstate); } #endif /* After enable OOB_WOL from efuse, mac will loopcheck phy status, and lead to panic sometimes. So we should disable it from powerup, enable it from power down.*/ regval = (u32)readreg(pdata->pAdapter, pdata->base_mem + OOB_WOL_CTRL); regval = FXGMAC_SET_REG_BITS(regval, OOB_WOL_CTRL_DIS_POS, OOB_WOL_CTRL_DIS_LEN, 1); writereg(pdata->pAdapter, regval, pdata->base_mem + OOB_WOL_CTRL); /* clear wpi mode whether or not waked by WOL, write reset value */ regval = (u32)readreg(pdata->pAdapter, pdata->base_mem + MGMT_WPI_CTRL0); regval = FXGMAC_SET_REG_BITS(regval, MGMT_WPI_CTRL0_WPI_MODE_POS, MGMT_WPI_CTRL0_WPI_MODE_LEN, 0); writereg(pdata->pAdapter, regval, pdata->base_mem + MGMT_WPI_CTRL0); /* read pmt_status register to De-assert the pmt_intr_o */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_PMT_STA); /* wether or not waked up by WOL, write reset value */ regval = FXGMAC_SET_REG_BITS(regval, MAC_PMT_STA_PWRDWN_POS, MAC_PMT_STA_PWRDWN_LEN, 0); /* write register to synchronized always-on block */ writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_PMT_STA); /* Disable fast link mode*/ cfg_r32(pdata, REG_POWER_EIOS, ®val); regval = FXGMAC_SET_REG_BITS(regval, POWER_EIOS_POS, POWER_EIOS_LEN, 0); cfg_w32(pdata, REG_POWER_EIOS, regval); fxgmac_pwr_clock_gate(pdata); } #if FXGMAC_SANITY_CHECK_ENABLED /* * fxgmac_diag_sanity_check * check if there is any error like tx q hang * return: 0 normal and other fatal error */ static int fxgmac_diag_sanity_check(struct fxgmac_pdata *pdata) { u32 reg_q_val, reg_tail_val; static u32 reg_tail_pre = 0; static int cnt = 0; reg_q_val = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, 0/* tx channe 0 */, 0x8/* 0x2d08 */)); if (!(reg_q_val & 0x10)) { //tx q is empty return 0; } reg_tail_val = readreg(pdata->pAdapter, FXGMAC_DMA_REG(pdata->channel_head, DMA_CH_TDTR_LO)); if(reg_tail_pre != reg_tail_val) { reg_tail_pre = reg_tail_val; cnt = 0; } else { cnt++; } if(cnt > 10) { reg_q_val = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, 0/* tx channe 0 */, 0x8/* 0x2d08 */)); if(reg_q_val & 0x10) { //double check DPRINTK("fxgmac, WARNing, tx Q status is 0x%x and tail keeps unchanged for %d times, 0x%x\n", reg_q_val, cnt, reg_tail_val); return 1; } } return 0; } #endif static void fxgmac_pwr_clock_gate(struct fxgmac_pdata* pdata) { u32 regval = 0; fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_SLEEP_CONTROL1); fxgmac_read_ephy_reg(pdata, REG_MII_EXT_DATA, ®val); // close pll in sleep mode regval = FXGMAC_SET_REG_BITS(regval, MII_EXT_SLEEP_CONTROL1_PLLON_IN_SLP_POS, MII_EXT_SLEEP_CONTROL1_PLLON_IN_SLP_LEN, 0); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, regval); /*regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_XST_OSC_CTRL); regval = FXGMAC_SET_REG_BITS(regval, MGMT_XST_OSC_CTRL_XST_OSC_SEL_POS, MGMT_XST_OSC_CTRL_XST_OSC_SEL_LEN, 0); writereg(pdata->pAdapter, regval, pdata->base_mem + MGMT_XST_OSC_CTRL); regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_XST_OSC_CTRL); regval = FXGMAC_SET_REG_BITS(regval, MGMT_XST_OSC_CTRL_EN_XST_POS, MGMT_XST_OSC_CTRL_EN_XST_LEN, 0); writereg(pdata->pAdapter, regval, pdata->base_mem + MGMT_XST_OSC_CTRL);*/ } static void fxgmac_pwr_clock_ungate(struct fxgmac_pdata* pdata) { u32 regval = 0; fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_SLEEP_CONTROL1); fxgmac_read_ephy_reg(pdata, REG_MII_EXT_DATA, ®val); // keep pll in sleep mode regval = FXGMAC_SET_REG_BITS(regval, MII_EXT_SLEEP_CONTROL1_PLLON_IN_SLP_POS, MII_EXT_SLEEP_CONTROL1_PLLON_IN_SLP_LEN, 1); fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, regval); /*regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_XST_OSC_CTRL); regval = FXGMAC_SET_REG_BITS(regval, MGMT_XST_OSC_CTRL_EN_XST_POS, MGMT_XST_OSC_CTRL_EN_XST_LEN, 1); writereg(pdata->pAdapter, regval, pdata->base_mem + MGMT_XST_OSC_CTRL); regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_XST_OSC_CTRL); regval = FXGMAC_SET_REG_BITS(regval, MGMT_XST_OSC_CTRL_XST_OSC_SEL_POS, MGMT_XST_OSC_CTRL_XST_OSC_SEL_LEN, 1); writereg(pdata->pAdapter, regval, pdata->base_mem + MGMT_XST_OSC_CTRL);*/ } static unsigned char fxgmac_suspend_int(void* context) // context - pointer to struct nic_pdata. { //ULONG_PTR addr; u32 intid; #if FUXI_EPHY_INTERRUPT_D0_OFF u32 regval = 0; #endif u32 val_mgmt_intcrtl0; struct fxgmac_pdata* pdata = (struct fxgmac_pdata*)context; val_mgmt_intcrtl0 = (u32)readreg(pdata->pAdapter, pdata->base_mem + MGMT_INT_CTRL0); //disable management interrupts. enable only pmt interrupts. val_mgmt_intcrtl0 = FXGMAC_SET_REG_BITS(val_mgmt_intcrtl0, MGMT_INT_CTRL0_INT_MASK_POS, MGMT_INT_CTRL0_INT_MASK_LEN, MGMT_INT_CTRL0_INT_MASK_EX_PMT); writereg(pdata->pAdapter, val_mgmt_intcrtl0, pdata->base_mem + MGMT_INT_CTRL0); for (intid = 0; intid < MSIX_TBL_MAX_NUM; intid++) { // disable all msix writereg(pdata->pAdapter, 0x1, pdata->base_mem + MSIX_TBL_BASE_ADDR + MSIX_TBL_MASK_OFFSET + intid * 16); } //enable pmt msix writereg(pdata->pAdapter, 0x0, pdata->base_mem + MSIX_TBL_BASE_ADDR + MSIX_TBL_MASK_OFFSET + MSI_ID_PHY_OTHER * 16); readreg(pdata->pAdapter, pdata->base_mem + MGMT_WOL_CTRL);// read clear wake up reason //since Msix interrupt masked now, enable EPHY interrupt for case of link change wakeup fxgmac_read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL); // clear phy interrupt #if FUXI_EPHY_INTERRUPT_D0_OFF regval = FXGMAC_SET_REG_BITS(0, PHY_INT_MASK_LINK_UP_POS, PHY_INT_MASK_LINK_UP_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, PHY_INT_MASK_LINK_DOWN_POS, PHY_INT_MASK_LINK_DOWN_LEN, 1); fxgmac_write_ephy_reg(pdata, REG_MII_INT_MASK, regval);//enable phy interrupt #endif return true; } static int fxgmac_suspend_txrx(struct fxgmac_pdata* pdata) { struct fxgmac_channel* channel; unsigned int i; u32 regval; int busy = 15; /* Prepare for Tx DMA channel stop */ channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->tx_ring) { break; } fxgmac_prepare_tx_stop(pdata, channel); } /* Disable each Tx DMA channel */ channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->tx_ring) { break; } regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_TCR_ST_POS, DMA_CH_TCR_ST_LEN, 0); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_TCR)); DBGPRINT(MP_TRACE, (" %s disable tx dma", __FUNCTION__)); } do { regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_DBG_STA); busy--; } while ((regval & MAC_DBG_STA_TX_BUSY) && (busy)); if (0 != (regval & MAC_DBG_STA_TX_BUSY)) { regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_DBG_STA); DbgPrintF(MP_WARN, "warning !!!timed out waiting for Tx MAC to stop\n"); return -1; } /* wait empty Tx queue */ for (i = 0; i < pdata->tx_q_count; i++) { do { regval = readreg(pdata->pAdapter, FXGMAC_MTL_REG(pdata, i, MTL_TXQ_DEG)); busy--; } while ((regval & MTL_TXQ_DEG_TX_BUSY) && (busy)); if (0 != (regval & MTL_TXQ_DEG_TX_BUSY)) { regval = readreg(pdata->pAdapter, pdata->mac_regs + MTL_TXQ_DEG); DbgPrintF(MP_WARN, "warning !!!timed out waiting for tx queue %u to empty\n", i); return -1; } } /* Disable MAC TxRx */ regval = readreg(pdata->pAdapter, pdata->mac_regs + MAC_CR); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_TE_POS, MAC_CR_TE_LEN, 0); regval = FXGMAC_SET_REG_BITS(regval, MAC_CR_RE_POS, MAC_CR_RE_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + MAC_CR); /* Prepare for Rx DMA channel stop */ for (i = 0; i < pdata->rx_q_count; i++) { fxgmac_prepare_rx_stop(pdata, i); } /* Disable each Rx DMA channel */ channel = pdata->channel_head; for (i = 0; i < pdata->channel_count; i++, channel++) { if (!channel->rx_ring) { break; } regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_RCR_SR_POS, DMA_CH_RCR_SR_LEN, 0); writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_RCR)); DBGPRINT(MP_TRACE, (" %s disable rx dma", __FUNCTION__)); } return 0; } static void fxgmac_resume_int(struct fxgmac_pdata* pdata) { u32 intid, regval = 0; u32 val_mgmt_intcrtl0; val_mgmt_intcrtl0 = (u32)readreg(pdata->pAdapter, pdata->base_mem + MGMT_INT_CTRL0); //disable management interrupts. enable only pmt interrupts. val_mgmt_intcrtl0 = FXGMAC_SET_REG_BITS(val_mgmt_intcrtl0, MGMT_INT_CTRL0_INT_MASK_POS, MGMT_INT_CTRL0_INT_MASK_LEN, MGMT_INT_CTRL0_INT_MASK_DISABLE); writereg(pdata->pAdapter, val_mgmt_intcrtl0, pdata->base_mem + MGMT_INT_CTRL0); for (intid = 0; intid < MSIX_TBL_RXTX_NUM; intid++) { writereg(pdata->pAdapter, 0, pdata->base_mem + MSIX_TBL_BASE_ADDR + MSIX_TBL_MASK_OFFSET + intid * 16); } for (intid = MSIX_TBL_RXTX_NUM; intid < MSIX_TBL_MAX_NUM; intid++) { // disable some msix writereg(pdata->pAdapter, 0, pdata->base_mem + MSIX_TBL_BASE_ADDR + MSIX_TBL_MASK_OFFSET + intid * 16); } #if FUXI_EPHY_INTERRUPT_D0_OFF fxgmac_write_ephy_reg(pdata, REG_MII_INT_MASK,0x0); //disable phy interrupt fxgmac_read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL); // clear phy interrupt #else //hw_ops->read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL);// clear phy interrupt regval = FXGMAC_SET_REG_BITS(0, PHY_INT_MASK_LINK_UP_POS, PHY_INT_MASK_LINK_UP_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, PHY_INT_MASK_LINK_DOWN_POS, PHY_INT_MASK_LINK_DOWN_LEN, 1); fxgmac_write_ephy_reg(pdata, REG_MII_INT_MASK, regval);//enable phy interrupt #endif } static int fxgmac_hw_init(struct fxgmac_pdata *pdata) { struct fxgmac_desc_ops *desc_ops = &pdata->desc_ops; int ret; u32 regval = 0; if (netif_msg_drv(pdata)) { DPRINTK("fxgmac hw init call in\n"); } /* Flush Tx queues */ ret = fxgmac_flush_tx_queues(pdata); if (ret) { if (netif_msg_drv(pdata)) { DPRINTK("fxgmac_hw_init call flush tx queue err.\n"); } #ifdef LINUX return ret; #endif } /* Initialize DMA related features */ fxgmac_config_dma_bus(pdata); fxgmac_config_osp_mode(pdata); fxgmac_config_pblx8(pdata); fxgmac_config_tx_pbl_val(pdata); fxgmac_config_rx_pbl_val(pdata); fxgmac_config_rx_coalesce(pdata); fxgmac_config_tx_coalesce(pdata); fxgmac_config_rx_buffer_size(pdata); fxgmac_config_tso_mode(pdata); fxgmac_config_sph_mode(pdata); fxgmac_config_rss(pdata); #ifdef LINUX fxgmac_config_wol(pdata, pdata->expansion.wol); #endif desc_ops->tx_desc_init(pdata); desc_ops->rx_desc_init(pdata); fxgmac_enable_dma_interrupts(pdata); /* Initialize MTL related features */ fxgmac_config_mtl_mode(pdata); fxgmac_config_queue_mapping(pdata); fxgmac_config_tsf_mode(pdata, pdata->tx_sf_mode); fxgmac_config_rsf_mode(pdata, pdata->rx_sf_mode); fxgmac_config_tx_threshold(pdata, pdata->tx_threshold); fxgmac_config_rx_threshold(pdata, pdata->rx_threshold); fxgmac_config_tx_fifo_size(pdata); fxgmac_config_rx_fifo_size(pdata); fxgmac_config_flow_control_threshold(pdata); fxgmac_config_rx_fep_disable(pdata); fxgmac_config_rx_fup_enable(pdata); fxgmac_enable_mtl_interrupts(pdata); /* Initialize MAC related features */ fxgmac_config_mac_address(pdata); fxgmac_config_crc_check(pdata); fxgmac_config_rx_mode(pdata); fxgmac_config_jumbo(pdata); fxgmac_config_flow_control(pdata); fxgmac_config_mac_speed(pdata); fxgmac_config_checksum_offload(pdata); fxgmac_config_vlan_support(pdata); fxgmac_config_mmc(pdata); fxgmac_enable_mac_interrupts(pdata); /* enable EPhy link change interrupt */ fxgmac_read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL);// clear phy interrupt regval = FXGMAC_SET_REG_BITS(0, PHY_INT_MASK_LINK_UP_POS, PHY_INT_MASK_LINK_UP_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, PHY_INT_MASK_LINK_DOWN_POS, PHY_INT_MASK_LINK_DOWN_LEN, 1); fxgmac_write_ephy_reg(pdata, REG_MII_INT_MASK, regval);//enable phy interrupt if (netif_msg_drv(pdata)) { DPRINTK("fxgmac hw init callout\n"); } return 0; } static void fxgmac_save_nonstick_reg(struct fxgmac_pdata* pdata) { u32 i; for (i = REG_PCIE_TRIGGER; i < MSI_PBA_REG; i += 4) { pdata->reg_nonstick[(i - REG_PCIE_TRIGGER) >> 2] = readreg(pdata->pAdapter, pdata->base_mem + i); } #if defined(UBOOT) /* PCI config space info */ dm_pci_read_config16(pdata->pdev, PCI_VENDOR_ID, &pdata->expansion.pci_venid); dm_pci_read_config16(pdata->pdev, PCI_DEVICE_ID, &pdata->expansion.pci_devid); dm_pci_read_config16(pdata->pdev, PCI_SUBSYSTEM_VENDOR_ID, &pdata->expansion.SubVendorID); dm_pci_read_config16(pdata->pdev, PCI_SUBSYSTEM_ID, &pdata->expansion.SubSystemID); dm_pci_read_config8(pdata->pdev, PCI_REVISION_ID, &pdata->expansion.pci_revid); //dm_pci_read_config16(pdata->pdev, PCI_COMMAND, &pdata->pci_cmd_word); DbgPrintF(MP_TRACE, "VenId is %x, Devid is %x, SubId is %x, SubSysId is %x, Revid is %x.\n", pdata->expansion.pci_venid, pdata->expansion.pci_devid, pdata->expansion.SubVendorID, pdata->expansion.SubSystemID, pdata->expansion.pci_revid); #elif !defined(UEFI) && !defined(PXE) && !defined(DPDK) cfg_r32(pdata, REG_PCI_COMMAND, &pdata->expansion.cfg_pci_cmd); cfg_r32(pdata, REG_CACHE_LINE_SIZE, &pdata->expansion.cfg_cache_line_size); cfg_r32(pdata, REG_MEM_BASE, &pdata->expansion.cfg_mem_base); cfg_r32(pdata, REG_MEM_BASE_HI, &pdata->expansion.cfg_mem_base_hi); cfg_r32(pdata, REG_IO_BASE, &pdata->expansion.cfg_io_base); cfg_r32(pdata, REG_INT_LINE, &pdata->expansion.cfg_int_line); cfg_r32(pdata, REG_DEVICE_CTRL1, &pdata->expansion.cfg_device_ctrl1); cfg_r32(pdata, REG_PCI_LINK_CTRL, &pdata->expansion.cfg_pci_link_ctrl); cfg_r32(pdata, REG_DEVICE_CTRL2, &pdata->expansion.cfg_device_ctrl2); cfg_r32(pdata, REG_MSIX_CAPABILITY, &pdata->expansion.cfg_msix_capability); DbgPrintF(MP_TRACE, "%s:\nCFG%02x-%02x\nCFG%02x-%02x\nCFG%02x-%02x\nCFG%02x-%02x\nCFG%02x-%02x\nCFG%02x-%02x\nCFG%02x-%02x\nCFG%02x-%02x\nCFG%02x-%02x\nCFG%02x-%02x\n", __FUNCTION__, REG_PCI_COMMAND, pdata->expansion.cfg_pci_cmd, REG_CACHE_LINE_SIZE, pdata->expansion.cfg_cache_line_size, REG_MEM_BASE, pdata->expansion.cfg_mem_base, REG_MEM_BASE_HI, pdata->expansion.cfg_mem_base_hi, REG_IO_BASE, pdata->expansion.cfg_io_base, REG_INT_LINE, pdata->expansion.cfg_int_line, REG_DEVICE_CTRL1, pdata->expansion.cfg_device_ctrl1, REG_PCI_LINK_CTRL, pdata->expansion.cfg_pci_link_ctrl, REG_DEVICE_CTRL2, pdata->expansion.cfg_device_ctrl2, REG_MSIX_CAPABILITY, pdata->expansion.cfg_msix_capability); #endif } static void fxgmac_restore_nonstick_reg(struct fxgmac_pdata* pdata) { u32 i; for (i = REG_PCIE_TRIGGER; i < MSI_PBA_REG; i += 4) { writereg(pdata->pAdapter, pdata->reg_nonstick[(i - REG_PCIE_TRIGGER) >> 2], pdata->base_mem + i); } } #if !defined(UEFI) && !defined(PXE) && !defined(DPDK) static void fxgmac_esd_restore_pcie_cfg(struct fxgmac_pdata* pdata) { cfg_w32(pdata, REG_PCI_COMMAND, pdata->expansion.cfg_pci_cmd); cfg_w32(pdata, REG_CACHE_LINE_SIZE, pdata->expansion.cfg_cache_line_size); cfg_w32(pdata, REG_MEM_BASE, pdata->expansion.cfg_mem_base); cfg_w32(pdata, REG_MEM_BASE_HI, pdata->expansion.cfg_mem_base_hi); cfg_w32(pdata, REG_IO_BASE, pdata->expansion.cfg_io_base); cfg_w32(pdata, REG_INT_LINE, pdata->expansion.cfg_int_line); cfg_w32(pdata, REG_DEVICE_CTRL1, pdata->expansion.cfg_device_ctrl1); cfg_w32(pdata, REG_PCI_LINK_CTRL, pdata->expansion.cfg_pci_link_ctrl); cfg_w32(pdata, REG_DEVICE_CTRL2, pdata->expansion.cfg_device_ctrl2); cfg_w32(pdata, REG_MSIX_CAPABILITY, pdata->expansion.cfg_msix_capability); } #endif static int fxgmac_hw_exit(struct fxgmac_pdata *pdata) { //unsigned int count = 2000; u32 regval; u32 value = 0; #if 1 cfg_r32(pdata, REG_PCI_LINK_CTRL, ®val); pdata->pcie_link_status = FXGMAC_GET_REG_BITS(regval, PCI_LINK_CTRL_ASPM_CONTROL_POS, PCI_LINK_CTRL_ASPM_CONTROL_LEN); if (PCI_LINK_CTRL_L1_STATUS == (pdata->pcie_link_status & 0x02)) { regval = FXGMAC_SET_REG_BITS(regval, PCI_LINK_CTRL_ASPM_CONTROL_POS, PCI_LINK_CTRL_ASPM_CONTROL_LEN, 0); cfg_w32(pdata, REG_PCI_LINK_CTRL, regval); } /* Issue a CHIP reset */ regval = readreg(pdata->pAdapter, pdata->base_mem + SYS_RESET_REG); DPRINTK("CHIP_RESET 0x%x\n", regval); /* reg152c bit31 1->reset, self-clear, if read it again, it still set 1. */ regval = FXGMAC_SET_REG_BITS(regval, SYS_RESET_POS, SYS_RESET_LEN, 1); writereg(pdata->pAdapter, regval, pdata->base_mem + SYS_RESET_REG); usleep_range_ex(pdata->pAdapter, 9000, 10000); //usleep_range_ex(pdata->pAdapter, 10, 15); /* reg152c reset will reset trigger circuit and reload efuse patch 0x1004=0x16,need to release ephy reset again */ value = FXGMAC_SET_REG_BITS(value, MGMT_EPHY_CTRL_RESET_POS, MGMT_EPHY_CTRL_RESET_LEN, MGMT_EPHY_CTRL_STA_EPHY_RELEASE); writereg(pdata->pAdapter, value, pdata->base_mem + MGMT_EPHY_CTRL); usleep_range_ex(pdata->pAdapter, 100, 150); fxgmac_restore_nonstick_reg(pdata); // reset will clear nonstick registers. #else /* Issue a software reset */ regval = readreg(pdata->pAdapter, pdata->mac_regs + DMA_MR); DPRINTK("DMA_MR 0x%x\n", regval); regval = FXGMAC_SET_REG_BITS(regval, DMA_MR_SWR_POS, DMA_MR_SWR_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, DMA_MR_INTM_POS, DMA_MR_INTM_LEN, 0); writereg(pdata->pAdapter, regval, pdata->mac_regs + DMA_MR); usleep_range_ex(pdata->pAdapter, 10, 15); /* Poll Until Poll Condition */ while (--count && FXGMAC_GET_REG_BITS(readreg(pdata->pAdapter, pdata->mac_regs + DMA_MR), DMA_MR_SWR_POS, DMA_MR_SWR_LEN)) { usleep_range_ex(pdata->pAdapter, 500, 600); } DPRINTK("Soft reset count %d\n", count); if (!count) { return -EBUSY; } #endif return 0; } #if defined(UEFI) || defined(PXE) static int fxgmac_set_gmac_register(struct fxgmac_pdata* pdata, u32 address, unsigned int data) #else static int fxgmac_set_gmac_register(struct fxgmac_pdata* pdata, u8* address, unsigned int data) #endif { #if defined(UEFI) || defined(PXE) if (address < (u32)(pdata->base_mem)) #else if (address < (u8*)(pdata->base_mem)) #endif { return -1; } writereg(pdata->pAdapter, data, address); return 0; } #if defined(UEFI) || defined(PXE) static u32 fxgmac_get_gmac_register(struct fxgmac_pdata* pdata, u32 address) #else static u32 fxgmac_get_gmac_register(struct fxgmac_pdata* pdata, u8* address) #endif { u32 regval = 0; #if defined(UEFI) || defined(PXE) if (address > (u32)(pdata->base_mem)) #else if (address > (u8*)(pdata->base_mem)) #endif { regval = readreg(pdata->pAdapter, address); } return regval; } static int fxgmac_pcie_init(struct fxgmac_pdata* pdata, bool ltr_en, bool aspm_l1ss_en, bool aspm_l1_en, bool aspm_l0s_en) { //DbgPrintF(MP_TRACE, "%s ltr_en %d aspm_l1ss_en %d aspm_l1_en %d aspm_l0s_en %d", __FUNCTION__, ltr_en, aspm_l1ss_en, aspm_l1_en, aspm_l0s_en); u32 regval = 0; u32 deviceid = 0; cfg_r32(pdata, REG_PCI_LINK_CTRL, ®val); if (PCI_LINK_CTRL_L1_STATUS == (pdata->pcie_link_status & 0x02) && 0x00 == FXGMAC_GET_REG_BITS(regval, PCI_LINK_CTRL_ASPM_CONTROL_POS, PCI_LINK_CTRL_ASPM_CONTROL_LEN) ) { regval = FXGMAC_SET_REG_BITS(regval, PCI_LINK_CTRL_ASPM_CONTROL_POS, PCI_LINK_CTRL_ASPM_CONTROL_LEN, pdata->pcie_link_status); cfg_w32(pdata, REG_PCI_LINK_CTRL, regval); } regval = FXGMAC_SET_REG_BITS(0, LTR_IDLE_ENTER_REQUIRE_POS, LTR_IDLE_ENTER_REQUIRE_LEN, LTR_IDLE_ENTER_REQUIRE); regval = FXGMAC_SET_REG_BITS(regval, LTR_IDLE_ENTER_SCALE_POS, LTR_IDLE_ENTER_SCALE_LEN, LTR_IDLE_ENTER_SCALE); regval = FXGMAC_SET_REG_BITS(regval, LTR_IDLE_ENTER_POS, LTR_IDLE_ENTER_LEN, LTR_IDLE_ENTER_USVAL); regval = (regval << 16) + regval; /* snoopy + non-snoopy */ writereg(pdata->pAdapter, regval, pdata->base_mem + LTR_IDLE_ENTER); regval = 0; regval = FXGMAC_SET_REG_BITS(0, LTR_IDLE_EXIT_REQUIRE_POS, LTR_IDLE_EXIT_REQUIRE_LEN, LTR_IDLE_EXIT_REQUIRE); regval = FXGMAC_SET_REG_BITS(regval, LTR_IDLE_EXIT_SCALE_POS, LTR_IDLE_EXIT_SCALE_LEN, LTR_IDLE_EXIT_SCALE); regval = FXGMAC_SET_REG_BITS(regval, LTR_IDLE_EXIT_POS, LTR_IDLE_EXIT_LEN, LTR_IDLE_EXIT_USVAL); regval = (regval << 16) + regval; /* snoopy + non-snoopy */ writereg(pdata->pAdapter, regval, pdata->base_mem + LTR_IDLE_EXIT); regval = readreg(pdata->pAdapter, pdata->base_mem + LTR_CTRL); if (ltr_en) { regval = FXGMAC_SET_REG_BITS(regval, LTR_CTRL_EN_POS, LTR_CTRL_EN_LEN, 1); regval = FXGMAC_SET_REG_BITS(regval, LTR_CTRL_IDLE_THRE_TIMER_POS, LTR_CTRL_IDLE_THRE_TIMER_LEN, LTR_CTRL_IDLE_THRE_TIMER_VAL); } else { regval = FXGMAC_SET_REG_BITS(regval, LTR_CTRL_EN_POS, LTR_CTRL_EN_LEN, 0); } writereg(pdata->pAdapter, regval, pdata->base_mem + LTR_CTRL); regval = readreg(pdata->pAdapter, pdata->base_mem + LPW_CTRL); regval = FXGMAC_SET_REG_BITS(regval, LPW_CTRL_ASPM_L0S_EN_POS, LPW_CTRL_ASPM_L0S_EN_LEN, aspm_l0s_en ? 1 : 0); regval = FXGMAC_SET_REG_BITS(regval, LPW_CTRL_ASPM_L1_EN_POS, LPW_CTRL_ASPM_L1_EN_LEN, aspm_l1_en ? 1 : 0); regval = FXGMAC_SET_REG_BITS(regval, LPW_CTRL_L1SS_EN_POS, LPW_CTRL_L1SS_EN_LEN, aspm_l1ss_en ? 1 : 0); writereg(pdata->pAdapter, regval, pdata->base_mem + LPW_CTRL); cfg_r32(pdata, REG_ASPM_CONTROL, ®val); regval = FXGMAC_SET_REG_BITS(regval, ASPM_L1_IDLE_THRESHOLD_POS, ASPM_L1_IDLE_THRESHOLD_LEN, ASPM_L1_IDLE_THRESHOLD_1US); cfg_w32(pdata, REG_ASPM_CONTROL, regval); regval = 0; regval = FXGMAC_SET_REG_BITS(regval, PCIE_SERDES_PLL_AUTOOFF_POS, PCIE_SERDES_PLL_AUTOOFF_LEN, 1); writereg(pdata->pAdapter, regval, pdata->base_mem + REG_PCIE_SERDES_PLL); /*fuxi nto adjust sigdet threshold*/ cfg_r8(pdata, REG_PCI_REVID, ®val); cfg_r16(pdata, REG_PCI_DEVICE_ID, &deviceid); if (FUXI_REV_01 == regval && PCI_DEVICE_ID_FUXI == deviceid) { regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_SIGDET); regval = FXGMAC_SET_REG_BITS(regval, MGMT_SIGDET_POS, MGMT_SIGDET_LEN, MGMT_SIGDET_55MV); writereg(pdata->pAdapter, regval, pdata->base_mem + MGMT_SIGDET); } return 0; } static void fxgmac_trigger_pcie(struct fxgmac_pdata* pdata, u32 code) { writereg(pdata->pAdapter, code, pdata->base_mem + REG_PCIE_TRIGGER); } void fxgmac_init_hw_ops(struct fxgmac_hw_ops *hw_ops) { hw_ops->init = fxgmac_hw_init; hw_ops->exit = fxgmac_hw_exit; hw_ops->save_nonstick_reg = fxgmac_save_nonstick_reg; hw_ops->restore_nonstick_reg = fxgmac_restore_nonstick_reg; #if !defined(UEFI) && !defined(PXE) && !defined(DPDK) hw_ops->esd_restore_pcie_cfg = fxgmac_esd_restore_pcie_cfg; #endif hw_ops->set_gmac_register = fxgmac_set_gmac_register; hw_ops->get_gmac_register = fxgmac_get_gmac_register; hw_ops->tx_complete = fxgmac_tx_complete; hw_ops->enable_tx = fxgmac_enable_tx; hw_ops->disable_tx = fxgmac_disable_tx; hw_ops->enable_rx = fxgmac_enable_rx; hw_ops->disable_rx = fxgmac_disable_rx; hw_ops->enable_channel_rx = fxgmac_enable_channel_rx; #ifdef LINUX hw_ops->dev_xmit = fxgmac_dev_xmit; hw_ops->dev_read = fxgmac_dev_read; hw_ops->config_tso = fxgmac_config_tso_mode; #endif hw_ops->enable_int = fxgmac_enable_int; hw_ops->disable_int = fxgmac_disable_int; hw_ops->set_interrupt_moderation = fxgmac_set_interrupt_moderation; hw_ops->enable_msix_rxtxinterrupt = fxgmac_enable_msix_rxtxinterrupt; hw_ops->disable_msix_interrupt = fxgmac_disable_msix_interrupt; hw_ops->enable_msix_rxtxphyinterrupt = fxgmac_enable_msix_rxtxphyinterrupt; hw_ops->enable_msix_one_interrupt = fxgmac_enable_msix_one_interrupt; hw_ops->disable_msix_one_interrupt = fxgmac_disable_msix_one_interrupt; hw_ops->enable_mgm_interrupt = fxgmac_enable_mgm_interrupt; hw_ops->disable_mgm_interrupt = fxgmac_disable_mgm_interrupt; hw_ops->set_mac_address = fxgmac_set_mac_address; hw_ops->set_mac_hash = fxgmac_add_mac_addresses; hw_ops->config_rx_mode = fxgmac_config_rx_mode; hw_ops->enable_rx_csum = fxgmac_enable_rx_csum; hw_ops->disable_rx_csum = fxgmac_disable_rx_csum; /* For MII speed configuration */ hw_ops->config_mac_speed = fxgmac_config_mac_speed; hw_ops->get_xlgmii_phy_status = fxgmac_check_phy_link; /* For descriptor related operation */ hw_ops->tx_desc_init = fxgmac_tx_desc_init; hw_ops->rx_desc_init = fxgmac_rx_desc_init; hw_ops->tx_desc_reset = fxgmac_tx_desc_reset; hw_ops->rx_desc_reset = fxgmac_rx_desc_reset; hw_ops->is_last_desc = fxgmac_is_last_desc; hw_ops->is_context_desc = fxgmac_is_context_desc; #ifdef LINUX hw_ops->tx_start_xmit = fxgmac_tx_start_xmit; hw_ops->set_pattern_data = fxgmac_set_pattern_data; hw_ops->config_wol = fxgmac_config_wol; hw_ops->get_rss_hash_key = fxgmac_read_rss_hash_key; hw_ops->write_rss_lookup_table = fxgmac_write_rss_lookup_table; #if FXGMAC_SANITY_CHECK_ENABLED hw_ops->diag_sanity_check = fxgmac_diag_sanity_check; #endif #endif /* For Flow Control */ hw_ops->config_tx_flow_control = fxgmac_config_tx_flow_control; hw_ops->config_rx_flow_control = fxgmac_config_rx_flow_control; /*For Jumbo Frames*/ hw_ops->enable_jumbo = fxgmac_config_jumbo; /* For Vlan related config */ hw_ops->enable_tx_vlan = fxgmac_enable_tx_vlan; hw_ops->disable_tx_vlan = fxgmac_disable_tx_vlan; hw_ops->enable_rx_vlan_stripping = fxgmac_enable_rx_vlan_stripping; hw_ops->disable_rx_vlan_stripping = fxgmac_disable_rx_vlan_stripping; hw_ops->enable_rx_vlan_filtering = fxgmac_enable_rx_vlan_filtering; hw_ops->disable_rx_vlan_filtering = fxgmac_disable_rx_vlan_filtering; hw_ops->update_vlan_hash_table = fxgmac_update_vlan_hash_table; /* For RX coalescing */ hw_ops->config_rx_coalesce = fxgmac_config_rx_coalesce; hw_ops->config_tx_coalesce = fxgmac_config_tx_coalesce; hw_ops->usec_to_riwt = fxgmac_usec_to_riwt; hw_ops->riwt_to_usec = fxgmac_riwt_to_usec; /* For RX and TX threshold config */ hw_ops->config_rx_threshold = fxgmac_config_rx_threshold; hw_ops->config_tx_threshold = fxgmac_config_tx_threshold; /* For RX and TX Store and Forward Mode config */ hw_ops->config_rsf_mode = fxgmac_config_rsf_mode; hw_ops->config_tsf_mode = fxgmac_config_tsf_mode; /* For TX DMA Operating on Second Frame config */ hw_ops->config_osp_mode = fxgmac_config_osp_mode; /* For RX and TX PBL config */ hw_ops->config_rx_pbl_val = fxgmac_config_rx_pbl_val; hw_ops->get_rx_pbl_val = fxgmac_get_rx_pbl_val; hw_ops->config_tx_pbl_val = fxgmac_config_tx_pbl_val; hw_ops->get_tx_pbl_val = fxgmac_get_tx_pbl_val; hw_ops->config_pblx8 = fxgmac_config_pblx8; /* For MMC statistics support */ hw_ops->tx_mmc_int = fxgmac_tx_mmc_int; hw_ops->rx_mmc_int = fxgmac_rx_mmc_int; hw_ops->read_mmc_stats = fxgmac_read_mmc_stats; #if defined(UEFI) #elif defined(_WIN32) || defined(_WIN64) hw_ops->update_stats_counters = fxgmac_update_stats_counters; #endif /* For Receive Side Scaling */ hw_ops->enable_rss = fxgmac_enable_rss; hw_ops->disable_rss = fxgmac_disable_rss; hw_ops->get_rss_options = fxgmac_read_rss_options; hw_ops->set_rss_options = fxgmac_write_rss_options; hw_ops->set_rss_hash_key = fxgmac_set_rss_hash_key; hw_ops->set_rss_lookup_table = fxgmac_set_rss_lookup_table; /*For Offload*/ #if defined(LINUX) || defined(_WIN64) || defined(_WIN32) hw_ops->set_arp_offload = fxgmac_update_aoe_ipv4addr; hw_ops->enable_arp_offload = fxgmac_enable_arp_offload; hw_ops->disable_arp_offload = fxgmac_disable_arp_offload; hw_ops->set_ns_offload = fxgmac_set_ns_offload; hw_ops->enable_ns_offload = fxgmac_enable_ns_offload; hw_ops->disable_ns_offload = fxgmac_disable_ns_offload; hw_ops->enable_wake_magic_pattern = fxgmac_enable_wake_magic_pattern; hw_ops->disable_wake_magic_pattern = fxgmac_disable_wake_magic_pattern; hw_ops->enable_wake_link_change = fxgmac_enable_wake_link_change; hw_ops->disable_wake_link_change = fxgmac_disable_wake_link_change; hw_ops->check_wake_pattern_fifo_pointer = fxgmac_check_wake_pattern_fifo_pointer; hw_ops->set_wake_pattern = fxgmac_set_wake_pattern; hw_ops->enable_wake_pattern = fxgmac_enable_wake_pattern; hw_ops->disable_wake_pattern = fxgmac_disable_wake_pattern; hw_ops->set_wake_pattern_mask = fxgmac_set_wake_pattern_mask; #if defined(FUXI_PM_WPI_READ_FEATURE_EN) && FUXI_PM_WPI_READ_FEATURE_EN hw_ops->enable_wake_packet_indication = fxgmac_enable_wake_packet_indication; hw_ops->get_wake_packet_indication = fxgmac_get_wake_packet_indication; #endif #endif /*For phy write /read*/ hw_ops->reset_phy = fxgmac_reset_phy; hw_ops->release_phy = fxgmac_release_phy; hw_ops->get_ephy_state = fxgmac_get_ephy_state; hw_ops->write_ephy_reg = fxgmac_write_ephy_reg; hw_ops->read_ephy_reg = fxgmac_read_ephy_reg; hw_ops->set_ephy_autoneg_advertise = fxgmac_set_ephy_autoneg_advertise; hw_ops->phy_config = fxgmac_phy_config; hw_ops->close_phy_led = fxgmac_close_phy_led; hw_ops->led_under_active = fxmgac_config_led_under_active; hw_ops->led_under_sleep = fxgmac_config_led_under_sleep; hw_ops->led_under_shutdown = fxgmac_config_led_under_shutdown; hw_ops->led_under_disable = fxgmac_config_led_under_disable; #if !defined(UEFI) hw_ops->enable_phy_check = fxgmac_enable_phy_check; hw_ops->disable_phy_check = fxgmac_disable_phy_check; hw_ops->setup_cable_loopback = fxgmac_setup_cable_loopback; hw_ops->clean_cable_loopback = fxgmac_clean_cable_loopback; hw_ops->disable_phy_sleep = fxgmac_disable_phy_sleep; hw_ops->enable_phy_sleep = fxgmac_enable_phy_sleep; hw_ops->phy_green_ethernet = fxgmac_phy_green_ethernet; hw_ops->phy_eee_feature = fxgmac_phy_eee_feature; #endif /* For power management */ hw_ops->pre_power_down = fxgmac_pre_powerdown; hw_ops->config_power_down = fxgmac_config_powerdown; hw_ops->config_power_up = fxgmac_config_powerup; hw_ops->set_suspend_int = fxgmac_suspend_int; hw_ops->set_resume_int = fxgmac_resume_int; hw_ops->set_suspend_txrx = fxgmac_suspend_txrx; hw_ops->set_pwr_clock_gate = fxgmac_pwr_clock_gate; hw_ops->set_pwr_clock_ungate = fxgmac_pwr_clock_ungate; hw_ops->set_all_multicast_mode = fxgmac_set_all_multicast_mode; hw_ops->config_multicast_mac_hash_table = fxgmac_config_multicast_mac_hash_table; hw_ops->set_promiscuous_mode = fxgmac_set_promiscuous_mode; hw_ops->enable_rx_broadcast = fxgmac_enable_rx_broadcast; /* efuse relevant operation. */ hw_ops->read_patch_from_efuse = fxgmac_read_patch_from_efuse; /* read patch per register. */ hw_ops->read_patch_from_efuse_per_index = fxgmac_read_patch_from_efuse_per_index; /* read patch per index. */ hw_ops->write_patch_to_efuse = fxgmac_write_patch_to_efuse; hw_ops->write_patch_to_efuse_per_index = fxgmac_write_patch_to_efuse_per_index; hw_ops->read_mac_subsys_from_efuse = fxgmac_read_mac_subsys_from_efuse; hw_ops->write_mac_subsys_to_efuse = fxgmac_write_mac_subsys_to_efuse; hw_ops->efuse_load = fxgmac_efuse_load; hw_ops->read_efuse_data = fxgmac_efuse_read_data; hw_ops->write_oob = fxgmac_efuse_write_oob; hw_ops->write_led = fxgmac_efuse_write_led; hw_ops->write_led_config = fxgmac_write_led_setting_to_efuse; hw_ops->read_led_config = fxgmac_read_led_setting_from_efuse; /* */ hw_ops->pcie_init = fxgmac_pcie_init; hw_ops->trigger_pcie = fxgmac_trigger_pcie; }